Professional CMake:

A Practical Guide

Learn to use CMake effectively with practical advice from a CMake co-maintainer. You can also have the author work directly with your team!

Professional CMake: A Practical Guide 13th Edition

Release Date: 29th September 2022

This is part of the change history for the book Professional CMake: A Practical Guide. The 13th Edition has been updated for the CMake 3.24 release. This is by far the largest update yet. A number of new chapters have been added: Advanced Linking, Making Projects Consumable and Dependency Providers. The External Content chapter was also split into two, since the FetchContent material grew significantly and became its own separate chapter. A major new feature covered in this edition is the integration between find_package() and the FetchContent module. The material on Ccache has also been updated for the recently added support for the Visual Studio toolchain. As usual, a variety of smaller updates and clarifications have been made as well. Full details of the changes are given below.


Flow Control chapter:

  • CMake 3.24 added a new PATH_EQUAL operator for the if() command. It is similar to STREQUAL but handles repeated path separators.
  • Added an example for if(IN_LIST) and highlight that policy CMP0057 must be set to NEW in order to use it.

Functions And Macros chapter:

  • Added explanation for how to robustly forward arguments in a macro command where list flattening isn’t a concern. This will be relevant for some dependency provider implementations (a new feature in CMake 3.24).

Generator Expressions chapter:

  • CMake 3.24 added new $<PATH:...> and $<PATH_EQUAL:...> generator expressions. These are essentially the generator expression equivalents of the cmake_path() sub-commands.

Debugging And Diagnostics chapter:

  • CMake 3.24 gained support for enabling color diagnostics in the output of the build tool and compiler. This is controlled by a new CMAKE_COLOR_DIAGNOSTICS CMake variable and a corresponding environment variable of the same name. These replace the old CMAKE_COLOR_MAKEFILE variable which enabled colorised output for just the make build tool.
  • The new cmake --fresh option can be used with CMake 3.24 or later to discard the cache from any previous run in the same build directory.

Compiler And Linker Essentials chapter:

  • A new section on compiler option abstractions was added.
    • One subsection covers turning compiler warnings into errors with the COMPILE_WARNING_AS_ERROR target property and its associated CMAKE_COMPILE_WARNING_AS_ERROR variable. These are new features in CMake 3.24. Later parts of the chapter were also updated to no longer use -Werror in any examples.
    • Another subsection covers how to specify the Visual Studio runtime library with the MSVC_RUNTIME_LIBRARY target property and its associated CMAKE_MSVC_RUNTIME_LIBRARY variable. These have been supported since CMake 3.15.
  • The De-duplicating Options section previously made an incorrect statement that LINKER:... arguments could be de-duplicated. This is not correct, as expansion of LINKER:... items occurs after de-duplication. The text and examples have been updated accordingly.
  • The Advanced Linking Relationships section was moved out to its own separate Advanced Linking chapter.
  • Added advice to the Recommended Practices section to avoid hard-coding turning compiler warnings into errors.

Advanced Linking chapter:

This is a new chapter for the 13th Edition.

  • The Advanced Linking Relationships section of the previous chapter was moved to this chapter as the Require Targets For Linking section.
  • A new section covers the new $<LINK_GROUP:...> and $<LINK_LIBRARY:...> generator expressions added in CMake 3.24. These provide features like grouping libraries on the linker command line for rescanning for unresolved symbols, indicating that all symbols of a static library should be retained (i.e. the behavior of flags like /WHOLEARCHIVE and --whole-archive), robustly identifying an Apple framework and other Apple-specific linker capabilities.
  • Another new section covers the new INTERFACE_LINK_LIBRARIES_DIRECT target property added in CMake 3.24. It includes a detailed discussion of how to use that property to robustly implement the link seaming technique.

Language Requirements chapter:

  • Fixed an example in the Detection And Use Of Optional Language Features section where -D prefixes were incorrectly included in arguments passed to target_compile_definitions(). Such prefixes are not stripped when part of a generator expression.

Custom Tasks chapter:

  • Starting with CMake 3.24, execute_process() no longer sets the CC and CXX environment variables on the first run. That behavior existed with CMake 3.23 and earlier, but was undocumented. It could lead to different behavior between the first and subsequent runs, causing subtle and hard-to-trace issues if you didn’t know about that behavior. Policy CMP0132 provides backward compatibility. The discussion at the end of the Configure Time Tasks section has been updated to highlight these changes, along with a workaround for when using CMake 3.23 or earlier.
  • An example in the Combining The Different Approaches section previously used cmake_minimum_required(VERSION 3.0), but the example actually used features from CMake 3.17. The example has been updated to use cmake_minimum_required(VERSION 3.17) instead.

Working With Files chapter:

  • CMake 3.24 extended file(DOWNLOAD) to support downloading only part of a file.

Libraries chapter:

  • The discussion in Mixing Static And Shared Libraries about using “whole archive” linker flags was updated to mention the $<LINK_LIBRARY:WHOLE_ARCHIVE,...> generator expression, available starting with CMake 3.24.

Apple Features chapter:

  • CMake 3.24 added support for *.xcconfig files with the Xcode generator. A new CMAKE_XCODE_XCCONFIG variable can be used to specify files to apply globally, while a new XCODE_XCCONFIG target property supports files defining target-specific settings. These features may be useful for projects transitioning to CMake from an exclusively Xcode-only arrangement where *.xcconfig files are commonly used.
  • The Linking Frameworks section was updated to mention the new $<LINK_LIBRARY:FRAMEWORK,...> generator expression available starting with CMake 3.24.

Finding Things chapter:

  • Various places have been updated to cross-reference other chapters that discuss new features added in CMake 3.24 which integrate with find_package().
  • All the find_...() commands gained new REGISTRY_VIEW and NO_CMAKE_INSTALL_PREFIX keywords in CMake 3.24, along with an associated CMAKE_FIND_USE_INSTALL_PREFIX variable.
  • CMake 3.24 added a new GLOBAL keyword for find_package(). When the GLOBAL keyword is present, imported targets created as part of that call will have global visibility (they are normally created with visibility in only the current directory scope and below). A CMAKE_FIND_PACKAGE_TARGETS_GLOBAL variable was also added as a way to change the default behavior.
  • A new search location for find_package() was added in CMake 3.24. This location is given by the new read-only CMAKE_FIND_PACKAGE_REDIRECTS_DIR variable and it takes priority over all other search locations. It is used primarily for integration with the FetchContent module (new functionality in CMake 3.24). Some brief notes about this integration were added here in this chapter, with cross-references to the detailed discussions in other chapters.
  • A note was added to highlight that CMAKE_REQUIRE_FIND_PACKAGE_<packageName> can break project logic. An example of a common scenario where this would occur is given.
  • The Recommended Practices section was updated to also mention $<LINK_LIBRARY:FRAMEWORK,...> as another way to link to something by name without breaking a developer’s ability to switch between device and simulator builds when targeting Apple platforms.

Testing chapter:

  • CMake 3.24 added more granular control over the truncation of test output. A new CTEST_CUSTOM_TEST_OUTPUT_TRUNCATION variable controls which part of the output is truncated. A new ctest --test-output-truncation option provides equivalent control for non-dashboard runs using the --output-junit option.
  • Examples using GoogleTest were updated to use the newer GTest::gtest and GTest::gtest_main targets rather than the older GTest::GTest and GTest::Main targets, which have been deprecated since CMake 3.20. A brief explanation of the situation was added to the The GoogleTest section.

Installing chapter:

  • CMake 3.24 added a new feature for verifying that headers are self-contained, meaning they don’t rely on some other header having been included first. It builds on the file sets feature added in CMake 3.23. The new CMAKE_VERIFY_INTERFACE_HEADER_SETS variable can be set to true to enable the creation of targets that carry out these checks for appropriately defined file sets. It is intended to be a developer control, not something the project sets. For projects already using file sets to install their headers, it should be a very simple step for developers to enable these checks. The new capability is covered in the File Sets section of this chapter.
  • The OUTPUT_NAME target property is now discussed in the same place where the EXPORT_NAME target property is introduced in the Installing Exports section. These two properties are related, so they should be discussed together.

Packaging chapter:

  • CMake 3.24 changed the default value of CPACK_DMG_SLA_USE_RESOURCE_FILE_LICENSE, subject to the new policy CMP0133. The behavior corresponding to the old default is no longer supported by recent Xcode releases.
  • The deprecated PackageMaker package generator was completely removed in CMake 3.24.

ExternalProject chapter:

The External Content chapter of the previous edition has been split up. The FetchContent section was moved out to its own dedicated chapter. The ExternalProject sections were revised and extensively restructured to provide a more logical flow, and the chapter has been renamed to ExternalProject in recognition of the narrower focus. The ExternalData section remains as part of the ExternalProject chapter.

  • The ExternalProject_Add() command gained a new DOWNLOAD_EXTRACT_TIMESTAMP option for use with URL archive downloads. It controls whether the timestamp of extracted files is updated to the time of extraction or set to the timestamp as contained in the archive. Policy CMP0135 was also added, since the default behavior was changed in this regard.

FetchContent chapter:

This is a new chapter for the 13th Edition. The FetchContent section of the External Content chapter in the previous edition has been moved here, heavily revised and extended.

  • A major new feature was added in CMake 3.24, providing integration between find_package() and FetchContent. Dependencies requested via one method can now be transparently fulfilled by the other. Controls are provided for both the project and the developer. A substantial new section was added to this chapter covering the new features.
  • Discussion of the constraints around when FetchContent can be used for a particular dependency is now the subject of its own new chapter, Making Projects Consumable. The Restrictions section in the FetchContent chapter is now more brief, providing cross-references to the more comprehensive discussions in the other new chapter instead.
  • The discussion of the manual population pattern has mostly been removed. The chapter now focuses first and foremost on using FetchContent_MakeAvailable(), since it now has a much richer set of features than the manual population pattern can provide.

Making Projects Consumable chapter:

This is a new chapter for the 13th Edition. It provides clear and fairly comprehensive guidelines for what projects can do so that other projects can most easily consume them. The focus is on supporting the common methods consumers may use to bring the project in as a dependency, in particular as pre-built binary installs and building from source. These roughly correspond to the traditional find_package() and FetchContent scenarios. The integration between these two main methods in CMake 3.24 increases the importance of the points highlighted in this chapter. The material is combination of collecting individual points discussed elsewhere in the book, as well as some new recommendations. The guidelines are structured around a few key principles, with specific, actionable points discussed for each one.

Dependency Providers chapter:

This is another new chapter for the 13th Edition. CMake 3.24 added a significant new feature called dependency providers. These allow calls to find_package() and FetchContent_MakeAvailable() to be intercepted by a command the developer defines. That command can choose to fulfil the request in whatever way it prefers and indicate back to CMake whether it was successful, or whether to fall back to the built-in default implementation. The primary use case is for setting up package managers, but the chapter covers other use cases for this feature as well. An example showing how to use the feature to time dependency request calls is provided in an Appendix.

A new CMAKE_PROJECT_TOP_LEVEL_INCLUDES variable is also introduced, which provides a well-defined injection point for one-time setup at the top of the project. This is also the only place a dependency provider can be set.

Project Organization chapter:

  • The advice around how/where to bring dependencies into the build has changed from previous editions. With the new integration features between find_package() and FetchContent, it is now more advantageous to bring dependencies into the build in the project’s top level scope rather than in a dedicated subdirectory. The focus on using FetchContent_MakeAvailable() rather than the manual population pattern removes the main motivation for using a separate directory scope. Examples have been updated accordingly and are now much simpler. Most of the discussions about the old manual population pattern have been removed.
  • A number of examples have been simplified to use the PROJECT_IS_TOP_LEVEL variable instead of comparing CMAKE_SOURCE_DIR with CMAKE_CURRENT_SOURCE_DIR. The minimum CMake version in the examples has been updated accordingly, where needed.
  • Variables used in examples to enable or disable testing have been renamed to be project specific, bringing them into line with recommendations in the new Making Projects Consumable chapter.
  • The discussion of the OUTPUT_NAME target property was removed from the Target Outputs section, since that is now covered in the Installing Exports section of the Installing chapter. Since the material that remains all relates to the location of build outputs, the section has been renamed to Target Output Locations.
  • The Injecting Files Into Projects section was updated to mention to the new CMAKE_PROJECT_TOP_LEVEL_INCLUDES variable introduced in the Dependency Providers chapter. The discussion contrasts the different uses of the various injection variables supported by the project() command. Discussion of examples related to CI setup have been removed from this section, since that is now more appropriately done via presets or a script provided by CMAKE_PROJECT_TOP_LEVEL_INCLUDES.

Build Performance chapter:

  • A substantial new section on Build Parallelism was added. For each of the main CMake generator types, it covers how to enable parallel builds and what generator-specific controls are available. For Ninja, a detailed discussion of job pools is provided. For Visual Studio, the Multi-ToolTask scheduler is discussed, along with its relationship to the well-known /MP compiler option. CMake’s handling of the -parallelizeTargets option for xcodebuild when using the Xcode generator is also discussed. The existing Optimizing Build Dependencies was also moved under this section.
  • Discussion of Ccache was expanded to cover the recently added support for the Visual Studio toolchain on Windows, including with the Visual Studio generators. Discussion about features in much older Ccache versions has been reduced and the material has been updated to focus more on recent Cccache releases. A complete, production-ready implementation supporting all the main CMake generators is provided as an Appendix.