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 14th Edition

Release Date: 4th January 2023

This is part of the change history for the book Professional CMake: A Practical Guide. The 14th Edition has been updated for the CMake 3.25 release. Main highlights for this edition include:

  • A new compiler abstraction for MSVC debug information formats.
  • Expanded support for system header search paths.
  • Expanded scope control with a new block() command and new return() capabilities.
  • Support for validators in most of the find_...() commands.
  • New package and workflow preset types.

Full details of the changes are given below.


Variables chapter:

  • CMake 3.25 added a new block() command, which can be used to define a new scope for variables (and policies). A new Scope Blocks section was added to cover the new functionality.

Flow Control chapter:

  • The Interrupting Loops subsection was extended to cover the behavior of break() and continue() when called inside a local scope defined by block() commands.

Using Subdirectories chapter:

  • The add_subdirectory() command gained a new SYSTEM keyword in CMake 3.25.
  • In the Scope subsection, the explanation of the scope-related effects when adding a subdirectory has been tweaked. It is now more technically accurate and a bit simpler.
  • The return() command gained support for a PROPAGATE keyword in CMake 3.25. The Ending Processing Early section has been extended to cover this new keyword, including its interaction with the block() command also added in CMake 3.25.

Functions And Macros chapter:

  • The Scope section was renamed to Returning Values, and separate subsections were added for Returning Values From Functions and Returning Values From Macros. These extend the previous content by covering the new PROPAGATE keyword for the return() command and interaction with the block() command.

Policies chapter:

  • The Policy Scope section was updated to cover the new block() command added in CMake 3.25. This command can define a new policy scope more robustly than using the manual cmake_policy(PUSH) / cmake_policy(POP) pattern. A new example also compares the two methods and highlights why the old method is more fragile.
  • The Recommended Practices section was updated to prefer using the block() command instead of the old manual push/pop pattern.

Debugging And Diagnostics chapter:

  • CMake 3.25 gained support for obtaining the current active message logging level using a new cmake_language(GET_MESSAGE_LOG_LEVEL) subcommand. The Log Levels subsection was extended to cover this, including an example for a common usage scenario.

Build Type chapter:

  • Updated the text and examples to only modify CMAKE_CONFIGURATION_TYPES or CMAKE_BUILD_TYPE in the top level CMakeLists.txt file. It is not safe to modify these in any other directory scope for some CMake generators.

Compiler And Linker Essentials chapter:

  • A new compiler abstraction was added in CMake 3.25 for selecting the debug information format with the MSVC toolchain. A new MSVC_DEBUG_INFORMATION_FORMAT target property and associated CMAKE_MSVC_DEBUG_INFORMATION_FORMAT variable can be used to select the format instead of having to work directly with the corresponding flags (/Z7, /Zi and /ZI). Policy CMP0141 was added to provide backward compatibility for code not aware of the new abstraction.
  • CMake 3.25 added a number of new properties related to how header search paths may be treated as “system”. A new System Header Search Paths subsection was added to the Compiler Option Abstractions section, which was in turn moved to later in the chapter. The new subsection covers the new SYSTEM target and directory properties, the new EXPORT_NO_SYSTEM target property, and the deprecation of the IMPORTED_NO_SYSTEM target property. Key CMake and toolchain versions where system-related support was extended is now also explicitly stated.
  • Added advice to the Recommended Practices section to avoid using the SYSTEM keyword with target_include_directories() or include_directories() for paths that are not outside the project.

Language Requirements chapter:

  • Updated the details for CXX_STANDARD to mention that 26 is now a supported value as of CMake 3.25, even though CMake does not yet support C++26 for any of the toolchains it currently knows about.

Toolchains And Cross Compiling chapter:

  • The Tool Selection section now uses -T ClangCL rather than -T llvm in its examples. The llvm toolset is from the no longer maintained LLVM Visual Studio extension. The ClangCL toolset is part of Visual Studio built-in LLVM distribution and is the recommended toolset for using clang-based compilers on Windows with VS2019 or later.

Apple Features chapter:

  • The XCODE_SCHEME_... properties and CMAKE_XCODE_SCHEME_... variables are now mentioned (very briefly).

Finding Things chapter:

  • CMake 3.25 added support for a new VALIDATOR keyword in the find_file(), find_path(), find_program() and find_library() commands. The new keyword provides more precise and customizable control over whether these commands accept a particular candidate during their search. More extended validator examples are provided for find_file() and find_library(), including a way to potentially distinguish between a static library and an import library for a DLL on Windows (not previously possible with CMake 3.24 or earlier).
  • CMake 3.25 added <prefix>/<packageName>*/(cmake|CMake)/<packageName>*/ as a new search path for find_package().

Testing chapter:

  • The gtest_discover_tests() command has supported a XML_OUTPUT_DIR keyword since CMake 3.18, but earlier editions did not mention it. This omission has been addressed and the keyword is now discussed.

Packaging chapter:

  • CMake 3.25 added support for a new CPACK_ARCHIVE_FILE_EXTENSION variable. It can be used to customize the extension of generated package archives produced by CPack.
  • A note was added for the productbuild generator to highlight a long-standing bug which can result in empty packages being produced. A simple workaround is given for avoiding that bug.

FetchContent chapter:

  • FetchContent_Declare() gained support for a new SYSTEM keyword in CMake 3.25. This is part of the expanded support for “system” header search paths and will apply to subdirectories added by FetchContent_MakeAvailable().
  • In the Other Uses For FetchContent section, the JoeSmithUtilsSetup example contained an error. It used a macro with ${CMAKE_CURRENT_LIST_DIR} instead of a function with ${CMAKE_CURRENT_FUNCTION_LIST_DIR} when extending CMAKE_MODULE_PATH. The example has now been fixed and extended further to explicitly show how to use the function.

Presets chapter:

  • CMake 3.25 added two new preset types: package and workflow. New sections have been added to cover both.

Project Organization chapter:

  • The discussion of the superbuild structure has been extended slightly, providing an additional example showing how to use CMAKE_PREFIX_PATH to share a common base install location between dependencies.
  • The 13th Edition updated the advice around how/where to bring dependencies into a non-superbuild arrangement, but some conflicting wording remained. The text has been updated again to remove the inconsistencies and ensure the new advice is clearer.

Build Performance chapter:

  • include_file_ctime is now also mentioned in the discussion of the CCACHE_SLOPPINESS environment variable.
  • Following recently added content in the Ccache documentation, the -fno-pch-timestamp flag is now recommended when using clang with Ccache 4.0 or later.
  • The MSVC-specific code example was updated to handle the CMAKE_MSVC_DEBUG_INFORMATION_FORMAT variable, if it is defined.

Appendix B: Full Compiler Cache Example:

  • The example code now adds the -fno-pch-timestamp flag if using clang.
  • Both the /Zx and -Zx forms of the debug information format flags are now handled, not just the former.
  • The CMAKE_MSVC_DEBUG_INFORMATION_FORMAT variable is handled appropriately, if defined.
  • If using a Visual Studio generator, the example no longer assumes the C language is enabled. It now only requires that at least one of C or C++ is enabled.