Skip to main content

CMake Modules

Ideal CMake Modules is the shared build infrastructure for all components of the Ideal project. It provides a consistent, opinionated set of CMake modules that handle compilation, testing, documentation, installation, and packaging — so that every component follows the same conventions and quality standards without duplicating build logic.

The design of this infrastructure is guided by several architectural decisions. ADR-0005 establishes CMake 3.21+ with Ninja as the standard build toolchain. ADR-0002 mandates C23 with strict compiler settings. ADR-0004 defines the standard interface that every component exposes through a Makefile wrapper that delegates to CMake.

Module overview

Every module targets a specific concern of the build lifecycle. When loaded, each module defines variables, provides functions, or registers build targets — or a combination of the three.

ModulePurpose
compilerConfigures strict C23 compilation with comprehensive warnings and link-time optimization
coverageInstruments code for coverage measurement and generates HTML reports
docsGenerates documentation from Doxygen XML and Markdown content files
i18nExtracts translatable strings and compiles message catalogs with gettext
installInstalls libraries with CMake package config, pkg-config, and source distribution
packagingGenerates Alpine Linux APK packages for CI pipelines
sanitizersIntegrates AddressSanitizer, MemorySanitizer, ThreadSanitizer, and UBSan
summaryPrints a configuration summary at the end of the configure step
toolsProvides clang-tidy static analysis and clang-format integration
versionDerives the project version from Git tags following semantic versioning

Loading the modules

Add IdealCmakeModules as a dependency in your CMakeLists.txt:

find_package(IdealCmakeModules REQUIRED)

This loads every module listed above. If you only need a subset, list them explicitly with COMPONENTS:

find_package(IdealCmakeModules REQUIRED COMPONENTS compiler install)

Typical CMakeLists.txt

A minimal component that uses the full build infrastructure looks like this:

cmake_minimum_required(VERSION 3.21...4.2)

project(
mylib
LANGUAGES C
DESCRIPTION "A sample library"
HOMEPAGE_URL "https://git.sr.ht/~cpradog/ideal-mylib/"
)

set(APK_MAINTAINER "Your Name <you@example.com>")
find_package(IdealCmakeModules REQUIRED)

add_library(mylib src/mylib.c)

target_include_directories(mylib PUBLIC
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include>
)

target_enable_strict_c23(mylib)
target_enable_sanitizers(mylib)
target_enable_coverage(mylib)

install_library(mylib)

The functions called on the target come from different modules — target_enable_strict_c23 from compiler, target_enable_sanitizers from sanitizers, target_enable_coverage from coverage, and install_library from install. Each is designed to be called unconditionally: when the corresponding feature is disabled (for example, ENABLE_COVERAGE=OFF), the function is a no-op.