# Appendix D: CMake This appendix teaches CMake using the build setup of this book as the running example. CMake is a build‑system generator. It reads a description of the project and produces files for a native build tool. The book uses the Ninja generator. Ninja is a fast, low‑level build tool that CMake drives. ## Configure, generate, build, test CMake separates configuration from building. The configure step reads `CMakeLists.txt` files and records the choices you make. The generate step writes the Ninja files. The build step compiles the targets. The test step runs the registered tests. The book drives all four steps with one command sequence: ``` cmake --preset dev cmake --build build -j ctest --test-dir build --output-on-failure ``` The first command configures and generates. The preset `dev` supplies the generator and the build directory. The second command builds every target with `-j` for parallel jobs. The third command runs every test and prints the output of failing tests. This sequence is the acceptance gate for the book. The script `scripts/verify.sh` runs it inside the Nix development shell. ## The project file The root `CMakeLists.txt` opens with a minimum version and a project name: ```cmake cmake_minimum_required(VERSION 3.30) project(tour_cpp26 LANGUAGES CXX) ``` The version 3.30 guarantees that the features the book uses exist. The project declares that it uses only the C++ language. Three lines fix the language standard: ```cmake set(CMAKE_CXX_STANDARD 26) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_EXTENSIONS OFF) ``` The standard is C++26, strictly. `CMAKE_CXX_STANDARD_REQUIRED ON` refuses a compiler that cannot reach C++26. `CMAKE_CXX_EXTENSIONS OFF` forbids GNU extensions. The line `set(CMAKE_EXPORT_COMPILE_COMMANDS ON)` writes a `compile_commands.json` file that clangd and other tools consume. ## Cache variables and options CMake stores configuration values in a cache. The `option` command declares a boolean cache variable with a default: ```cmake option(BOOK_SANITIZE "Run example tests under AddressSanitizer and UndefinedBehaviorSanitizer" ON) option(BOOK_ENABLE_GAPS "Build examples for C++26 features without shipping Clang support" OFF) option(BOOK_WERROR "Turn compiler warnings into errors for book_example targets" ON) ``` `BOOK_SANITIZE` turns the sanitizers on for example tests. It defaults to ON. `BOOK_ENABLE_GAPS` builds examples for C++26 features that lack shipping Clang support. It defaults to OFF. `BOOK_WERROR` turns warnings into errors for `book_example` targets. It defaults to ON. You override a default on the command line with `-D`: ``` cmake --preset dev -DBOOK_ENABLE_GAPS=ON ``` ## The CMakePresets dev preset A preset bundles configuration options under a name. The file `CMakePresets.json` defines the `dev` preset: ```json { "name": "dev", "generator": "Ninja", "binaryDir": "${sourceDir}/build", "cacheVariables": { "CMAKE_BUILD_TYPE": "RelWithDebInfo" } } ``` The preset selects the Ninja generator. It places the build tree in the `build` directory beside the source. It sets the build type to `RelWithDebInfo`, which optimizes the code and keeps debug information. The preset also defines matching build and test presets, so `cmake --build build -j` and `ctest --test-dir build` work without extra flags. ## Targets and subdirectories A target is a named unit of work. The command `add_executable` creates an executable target from a source file. The command `add_subdirectory` descends into a child directory and reads its `CMakeLists.txt`. The file `examples/CMakeLists.txt` calls `add_subdirectory` for each chapter directory: ```cmake add_subdirectory(ch01) add_subdirectory(ch02) ``` Each chapter directory holds one `CMakeLists.txt` that registers its examples. For example, `examples/ch01/CMakeLists.txt` contains: ```cmake book_example(ch01_hello.cpp EXPECT "hello, world") book_demo(ch01_dangling.cpp) book_demo(ch01_overflow.cpp) ``` The names `book_example` and `book_demo` are functions that the book defines. They are not CMake built‑ins. ## The book_example function The functions live in `cmake/BookExample.cmake`. The root `CMakeLists.txt` adds that directory to the module path and includes the file: ```cmake list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake") include(BookExample) ``` The `book_example` function registers a real, fully‑checked example. Its body is: ```cmake function(book_example file) cmake_parse_arguments(arg "" "EXPECT" "" ${ARGN}) _book_add_target(t "${file}") target_compile_options(${t} PRIVATE ${BOOK_WARNING_FLAGS}) if(BOOK_WERROR) target_compile_options(${t} PRIVATE -Werror) endif() if(BOOK_SANITIZE) target_compile_options(${t} PRIVATE -fsanitize=address -fsanitize=undefined) target_link_options(${t} PRIVATE -fsanitize=address -fsanitize=undefined) endif() add_test(NAME ${t}_run COMMAND ${t}) if(arg_EXPECT) set_tests_properties(${t}_run PROPERTIES PASS_REGULAR_EXPRESSION "${arg_EXPECT}") endif() endfunction() ``` The helper `_book_add_target` derives the target name from the file name and calls `add_executable`. The function attaches the warning flags, the `-Werror` flag, and the sanitizer flags. It registers a CTest test named `_run`. When `EXPECT` is present, the test must match the given regular expression. The `book_demo` function registers a deliberately wrong example that compiles with warnings visible and no test. The `book_gap` function registers a C++26 feature target that builds only with `BOOK_ENABLE_GAPS=ON`. The warning flags come from a list that includes the lifetime‑safety flag. The file probes the compiler with `check_cxx_compiler_flag` and `check_cxx_source_compiles` to discover which spelling of the lifetime‑safety analysis it accepts. It prefers `-Wlifetime-safety` and falls back to the experimental cc1 form. ## Try this Open `cmake/BookExample.cmake`, compare `book_demo` to `book_example`, then run `cmake --preset dev -DBOOK_SANITIZE=OFF` to verify the build succeeds without sanitizer flags.