CMake execution flow chart#
graph TD A[Start] --> B["Write CMakeLists.txt Files"] B --> C["Run CMake Command (e.g., cmake .)"] C --> D{"CMakeLists.txt Valid?"} D -- No --> E["Error Message
Fix Configuration"] D -- Yes --> F["Parse CMakeLists.txt"] F --> G["Check System Dependencies
(Compiler, Libraries)"] G --> H{"All Dependencies Found?"} H -- No --> I["Error Message
Missing Tools/Libraries"] H -- Yes --> J["Generate Build System Files
(Makefiles, .sln, Xcode Projects)"] J --> K["Build System Ready"] K --> L["Run Build Tool
(make, ninja, MSBuild)"] L --> M{"Compilation
Successful?"} M -- No --> N["Fix Code/Configuration"] M -- Yes --> O["Generate Executables/Libraries"] O --> P[End]
Three Main Stages#
Configurations#
- Parsing CMakeLists.txt: CMake reads your build description files and executes the commands sequentially
- System inspection: Checks for available compilers, tools, and libraries on the system
- Dependency resolution: Identifies and locates required external packages
- Variable evaluation: Sets up build variables and processes conditionals
Generations#
- Build system selection: CMake determines which generator to use (Make, Ninja, Visual Studio, etc.)
- File generation: Creates all necessary files for the selected build system
- Dependency graph construction: Maps out how targets depend on each other.
Build#
- Compilation: Source files are compiled into object files
- Linking: Object files are linked together to form executables or libraries
- Post-build steps: Any custom commands or installation rules are executed
Core CMake Concepts#
Targets and Properties#
In modern CMake, everything revolves around targets (executables, libraries, custom outputs) and properties associated with those targets:
|
Properties can have different visibility levels:
- PRIVATE: Used only by the target itself
- PUBLIC: Used by both the target and any target that links to it
- INTERFACE: Used only by targets that link to this one8
Find Packages and Dependencies#
CMake provides a powerful mechanism for finding and using external libraries:
|
This approach works with CMake’s built-in find modules and package config files provided by libraries8.
Advanced CMake Topics#
Generator Expressions#
Generator expressions provide powerful capabilities for conditional property setting:
|
This adds a different version string definition depending on the build configuration8.
Custom Commands and Build Events#
For special build steps:
|
Configuring Files#
CMake can generate files with variable substitutions:
|
In config.h.in
:
|
This will substitute the @PROJECT_VERSION@
token with the actual project version17.
Modern CMake Best Practices#
The field of CMake best practices has evolved over time. Here are the most important guidelines:
- Use at least CMake 3.0: Modern CMake features are only available in newer versions8.
- Treat CMake code as production code: Keep it clean, organized, and follow consistent patterns8.
- Define project properties at target level: Avoid global settings that affect all targets8.
- Forget directory-level commands: Avoid
add_compile_options
,include_directories
,link_directories
, andlink_libraries
8. - Keep your hands off CMAKE_CXX_FLAGS: Use target properties instead8.
- Always specify visibility with target commands: Use
PRIVATE
,PUBLIC
, orINTERFACE
appropriately8. - Don’t use
file(GLOB)
for source files: List source files explicitly so CMake can detect when they change8. - Create proper installation rules: Define what gets installed and where8.
Multi-Project Organization#
For larger projects with multiple components:
|
In app/CMakeLists.txt
:
|
This approach enables proper dependency tracking between subprojects3.
Package Installation and Export#
To make your library usable by other CMake projects:
|
This creates a complete package that other projects can use with find_package(MyLib)
8.
Debugging CMake#
For troubleshooting CMake issues:
|