Recent from talks
Contribute something
Nothing was collected or created yet.
CMake
View on Wikipedia
| CMake | |
|---|---|
| Developers | Andy Cedilnik, Bill Hoffman, Brad King, Ken Martin, Alexander Neundorf |
| Initial release | 2000 |
| Stable release | 4.1.2[1] |
| Repository | |
| Written in | C, C++[2] |
| Operating system | Cross-platform |
| Type | Software development tools |
| License | BSD-3-Clause |
| Website | cmake |
CMake is a free, cross-platform, software development tool for building applications via compiler-independent instructions. It also can automate testing, packaging and installation. It runs on a variety of platforms and supports many programming languages.[3]
As a meta-build tool, CMake configures native build tools which in turn build the codebase. CMake generates configuration files for other build tools based on CMake-specific configuration files. The other tools are responsible for more directly building; using the generated files. A single set of CMake-specific configuration files can be used to build a codebase using the native build tools of multiple platforms.[4]
Notable native build tools supported by CMake include: Make, Qt Creator, Ninja, Android Studio, Xcode, and Visual Studio.[4]
CMake is distributed as free and open-source software under a permissive BSD-3-Clause license.[5]
History
[edit]Initial development began in 1999 at Kitware with funding from the United States National Library of Medicine as part of the Visible Human Project.[4] CMake was first released in 2000.
CMake was developed to support building the Insight Segmentation and Registration Toolkit (ITK) for multiple platforms. Stated goals included addressing weaknesses while maintaining strengths of contemporary tools such as autoconf and libtool, and to align with state of the art build technology of the time: configure scripts and Make files for Unix platforms, and Visual Studio project files for Windows.[6][4]
CMake was inspired by multiple contemporary tools. pcmaker – developed by Ken Martin and others to support building the Visualization Toolkit (VTK) – converted Unix Make files into NMake files for building on Windows.[4] gmake supported Unix and Windows compilers, but its design led to issues that were hard to resolve. Both tools were working examples of a build tool that supported both Unix and Windows, but they suffered from a serious flaw: they required Windows developers to use the command line even though many prefer to use an integrated development environment (IDE) such as Visual Studio.
CMake was to provide similar cross-platform support but to better satisfy the preferences of the developers on each platform.
The design goals of the first version included:[4]
- Depend only on host C++ compiler; no other third-party tools or libraries required
- Generate Visual Studio project files (as well as Unix files)
- Support building targets: program, static library, shared library
- Run build-time code generators
- Support separate directory trees for source vs. build files
- Support host computer capability introspection
- Support automatic dependency scanning of C/C++ header files
- All features must work consistently and equally well on all supported platforms
For various reasons, CMake developers chose to develop a scripting language for CMake instead of using Tcl – a popular language for building at the time. Use of Tcl would have then added a dependency to the host machine which is counter to the goal of no dependencies other than a compiler. Also, Tcl was not well supported on Windows and some Unix systems at the time of initial development.[4]
Subsequent development and improvements were fueled by the incorporation of CMake into developers’ own systems, including the VXL Project,[clarification needed] the CABLE[7] features added by Brad King,[clarification needed] and GE Corporate R&D for support of DART.[clarification needed] Additional features were created when VTK transitioned to CMake for its build environment and for supporting ParaView.
Version 3.0 was released in June 2014.[8] It has been described as the beginning of "Modern CMake".[9] Experts now advise to avoid variables in favor of targets and properties.[10] The commands add_compile_options, include_directories, link_directories, link_libraries that were at the core of CMake 2 should now be replaced by target-specific commands.
Name
[edit]CMake developer Brad King stated that "the 'C' in CMake stands for 'cross-platform'".
Features
[edit]Generators and IDE support
[edit]CMake can generate project files for IDEs like Microsoft Visual Studio, Xcode, Eclipse CDT and build scripts for MSBuild or NMake on Windows; Unix Make on Unix-like platforms such as Linux, macOS, and Cygwin; and Ninja on both Windows and Unix-like platforms by specifying generator for a platform-specific build tool. By default, CMake automatically determines default generator for the host environment it runs on. Command line option -G can be used to specify alternative generator. E.g. -G Unix Makefiles forces CMake to create build scripts for make.[4]
CMake does not support custom generators without modifying the CMake implementation. None-the-less, the CMake source code could be modified to include a custom generator.
Build targets
[edit]CMake supports building executables, libraries (e.g. libxyz, xyz.dll etc.), object file libraries and pseudo-targets (including aliases). CMake can produce object files that can be linked against by executable binaries/libraries, avoiding dynamic (run-time) linking and using static (compile-time) linking instead. This enables flexibility in configuration of various optimizations.[11]
Target generation can be configured via target properties. With older versions, this was done via CMAKE_-prefixed global variables, but this approach is deprecated.[10][12]
Hierarchical configuration
[edit]CMake configuration files can be structured according the hierarchical structure of the source code; the source tree. A CMakeLists.txt in a root source directory serves as the root of the configuration. It may include sub-directories which each contain a CMakeLists.txt. Repeating this, results in a hierarchical structure of configuration that follows the structure of the source code.[10][12]
Separate build tree
[edit]CMake can store generated files (both by CMake and the native build tools) in a directory tree that is separate from the source tree.[4]
This enables multiple builds from the same source tree since each has non-overlapping file system space. This may be leveraged to build different or even incompatible configurations such as for different platforms.
This also simplifies file management by allowing removing generated files by deleting a single directory tree instead of removing multiple files and directories throughout the source tree. This tends to prevent accidentally deleting source files or accidentally adding generated files to source control.
Dependency management
[edit]CMake ensures that downstream components are re-built when its sources are changed or built.[4]
Flexible project structure
[edit]CMake can locate system-wide and user-specified executables, files, and libraries. These locations are stored in a cache, which can then be tailored before generating the target build files. The cache can be edited with a graphical editor, which is shipped with CMake.
Complicated directory hierarchies and applications that rely on several libraries are well supported by CMake. For instance, CMake is able to accommodate a project that has multiple toolkits, or libraries that each have multiple directories. In addition, CMake can work with projects that require executables to be created before generating code to be compiled for the final application. Its open-source, extensible design allows CMake to be adapted as necessary for specific projects.[13]
Compiler feature detection
[edit]CMake allows specification of features that the compiler is required to support in order to get the target program or library compiled.[14]
Compiler support
[edit]CMake supports many compilers, including: Apple Clang, Clang, GNU GCC, MSVC, Oracle Developer Studio, and Intel C++ Compiler.[15]
Packaging
[edit]CMake can produce packages that can be consumed both by end-user and third-party cmake-based project. Via CPack, built files may be packed into an archive file for a target system's package manager (e.g. dpkg) or installer supported by the target platform.[16]: 132, 142 [17][18] CMake provides functions for pulling packages from a remote server that can be used as part of the build process or link previously installed cmake packages.[18]
GUI
[edit]Cmake may be run by using a ncurses program like ccmake that can be used to configure projects via command-line interface.
Precompiled headers and modules
[edit]It is possible to generate precompiled headers via CMake since version 3.6.[19] As of version 3.28, CMake can also compile modules. Experimental support for header units also exists.[20]
JSON strings
[edit]CMake supports extracting values into variables from JSON-data strings (since version 3.19).[21]
Language
[edit]
CMake includes an interpreter for a relatively simple, custom, imperative scripting language that supports variables, string manipulation, arrays, function and macro declaration, and module inclusion (importing).
The interpreter reads CMake language commands from files named CMakeLists.txt which specify source files and build preferences. CMake uses this information to generate native tool configuration files. Additionally, files with suffix .cmake can be used for storing additional script.[22]
Command syntax
[edit]CMake language commands are formatted as:
name(argument ...)
Arguments are whitespace-separated and can include keywords to separate groups of arguments. For instance, in the following command, the keyword COMPILE_FLAGS delimits a list of source files from compiler flags.[23]
set_source_file_properties(filename ... COMPILE_FLAGS compile_flag ...)
Implementation
[edit]The CMake scripting language is implemented via Yacc and Lex generators.
The executable programs CMake, CPack, and CTest are written in C++.
Much of CMake's functionality is implemented in modules written in the CMake language.[24]
CMake documentation (since release 3.0) uses reStructuredText markup. HTML pages and man pages are generated by the Sphinx documentation generator.
Additional tools
[edit]CMake ships with numerous .cmake script files and development tools that facilitate tasks such as finding dependencies (both built-in and external, e.g. FindXYZ modules), testing the toolchain environment and executables, packaging releases (CPack), and managing dependencies on external projects (ExternalProject module). Additional development tools include:[25][26]
Adoption
[edit]CMake has been very widely adopted among commercial, open source, and academic software projects. A few notable users include Android NDK, Netflix, Inria, MySQL, Boost (C++ libraries), KeePassXC, KDE, KiCAD, FreeCAD, Webkit, Blender,[29] Biicode, ReactOS, Apache Qpid, the ATLAS experiment,[30] and Second Life.[31]
Build process
[edit]Building via CMake has a two major stages.[4] First, native build tool configuration files are generated from CMake configuration files – written in the CMake scripting language. The command line syntax is cmake <dir> where <dir> is a directory that contains a CMakeLists.txt file. Then, the native build tools are invoked either via CMake (cmake --build <dir>) or directly via the native tool's interface. The native build tools use the generated files.[13][32]
Examples
[edit]Hello world
[edit]The following demonstrates configuring CMake to build a hello world program written in C++, and using CMake to build the program.
Hello.cpp:
#include <print>
int main() {
std::println("Hello, world!");
return 0;
}
CMakeLists.txt:
cmake_minimum_required(VERSION 3.22)
project(HelloWorld CXX)
add_executable(hello hello.cpp)
To build via CMake, first cd to the directory containing the two files above. Then, generate the native build config files via the cross-platform CMake command:
cmake -B out .
All generated files will be under the directory out as specified via -B out.
Then, build via the native build tool as supported thru CMake:
cmake --build out
The program is then available for running. Via Bash, the command is like ./out/hello. On Windows, the output file ends with .exe.
Include
[edit]This example demonstrates configuring the preprocessor include path.
Hello.cpp:
#include <print>
#include "Hello.h"
int main() {
for (int i = 0; i < TIMES; ++i) {
std::println("Hello, world!");
}
return 0;
}
Hello.h:
#pragma once
constexpr int TIMES = 10;
CMakeLists.txt:
cmake_minimum_required(VERSION 3.22)
project(HelloWorld CXX)
include_directories(${PROJECT_SOURCE_DIR})
add_executable(hello hello.cpp)
See also
[edit]References
[edit]- ^ "CMake 4.1.2 available for download". 1 October 2025. Retrieved 20 October 2025.
- ^ "The CMake Open Source Project on OpenHub". OpenHub. Retrieved 9 April 2016.
- ^ "CMake".
- ^ a b c d e f g h i j k "The Architecture of Open Source Applications (Volume 1)CMake". aosabook.org. Retrieved 11 June 2023.
- ^ "Licenses · master · CMake / CMake". GitLab. Retrieved 13 November 2020.
- ^ "FLOSS Weekly 111: CMake". podcast. TWiT Network. Retrieved 27 February 2011.
- ^ "The CABLE". Archived from the original on 19 June 2013. Retrieved 10 November 2010.
- ^ Maynard, Robert (10 June 2014). "[CMake] [ANNOUNCE] CMake 3.0.0 Released".
- ^ "Effective Modern CMake". Gist.
- ^ a b c Binna, Manuel (22 July 2018). "Effective Modern CMake".
- ^ "cmake-buildsystem(7) — CMake 3.19.0-rc3 Documentation". cmake.org. Retrieved 14 November 2020.
- ^ a b Pfeifer, Daniel (19 May 2017). Effective Cmake (PDF). CPPNow.
- ^ a b Neundorf, Alexander (21 June 2006). "Why the KDE project switched to CMake—and how". LWN.net.
- ^ "CMake compiler feature detect". www.scivision.dev. 15 November 2020. Retrieved 22 January 2022.
- ^ "Supported Compilers". CMake Documentation. Retrieved 22 January 2022.
- ^ Berner, Dominik (2022). CMake Best Practices : Discover Proven Techniques for Creating and Maintaining Programming Projects with CMake. Mustafa Kemal Gilor. Birmingham: Packt Publishing, Limited. ISBN 978-1-80324-424-2. OCLC 1319218167.
- ^ "cmake-packages(7) — CMake 3.24.1 Documentation". cmake.org. Retrieved 11 September 2022.
- ^ a b "Exposing a module's configuration (advanced) — CMake build procedure 1.0 documentation". docs.salome-platform.org. Retrieved 11 September 2022.
- ^ "target_precompile_headers — CMake 3.21.20210925-gb818e3c Documentation". cmake.org. Retrieved 25 September 2021.
- ^ "CXX_MODULE_HEADER_UNIT_SETS". cmake.org. Kitware. Retrieved 31 October 2025.
- ^ "CMake 3.19 Release Notes — CMake 3.19.7 Documentation". cmake.org. Retrieved 15 March 2021.
- ^ "cmake-language(7) — CMake 3.19.0-rc2 Documentation". cmake.org. Retrieved 29 October 2020.
- ^ Cedilnik, Andrej (30 October 2003). "Cross-Platform Software Development Using CMake Software". Linux Journal. Retrieved 29 January 2021.
- ^ "cmake-language(7) — CMake 3.19.0-rc1 Documentation". cmake.org. Retrieved 25 October 2020.
- ^ "cmake-modules(7) — CMake 3.14.7 Documentation". cmake.org. Retrieved 24 October 2020.
- ^ "ExternalProject — CMake 3.14.7 Documentation". cmake.org. Retrieved 24 October 2020.
- ^ "Packaging With CPack". CMake Community Wiki.
- ^ – Linux General Commands Manual from ManKier.com.
- ^ "Building Blender - Blender Developer Wiki". wiki.blender.org. Retrieved 1 July 2021.
- ^ Elmsheuser, J; Krasznahorkay, A; Obreshkov, E; Undrus, A (2017). "Large Scale Software Building with CMake in ATLAS" (PDF). CERN. Archived (PDF) from the original on 28 July 2018.
- ^ "CMake Success". cmake.org. Kitware. 2011. Retrieved 12 March 2022.
- ^ "cmake-toolchains(7) — CMake 3.19.0-rc2 Documentation". cmake.org. Retrieved 29 October 2020.
External links
[edit]CMake
View on GrokipediaOrigins
History
CMake was initially developed in 2000 by Kitware Inc. for the Insight Software Consortium, sponsored by the U.S. National Library of Medicine, to address the challenges of building complex Makefiles for the Insight Toolkit (ITK), a medical imaging software project requiring cross-platform portability.[2] The tool emerged from the success of the Visualization Toolkit (VTK), aiming to simplify the build process for C++ applications across multiple operating systems and compilers.[5] Development began on August 31, 2000, with Kitware creating a prototype in a few weeks to meet the consortium's needs.[5] The first stable release, CMake 1.0, arrived in November 2001, marking the tool's public availability under the permissive BSD-3-Clause license, which has remained its licensing model since inception to encourage widespread adoption.[6] Early adoption followed quickly, with integration into VTK and ParaView by 2002, supported by funding from national laboratories such as Los Alamos, Sandia, and Lawrence Livermore, which expanded its use in scientific computing projects.[2] In 2004, CMake received funding from the National Alliance for Medical Image Computing (NA-MIC), increasing its use in open-source projects.[2] CMake 2.0, released on June 11, 2004, introduced significant enhancements in cross-platform support, including better handling of Windows and macOS builds, solidifying its role as a versatile alternative to platform-specific tools.[7] A pivotal milestone occurred in 2006 when the KDE project transitioned from autotools to CMake, championed by developer Alexander Neundorf, enabling faster porting of KDE applications to Windows and macOS while adding features like shared library versioning.[2] This integration boosted CMake's visibility in the open-source community and influenced subsequent adoptions, such as LLVM's initial use in 2008 and full switch in 2016.[2] The 3.x series began with CMake 3.0 on June 10, 2014, shifting to a modern target-based API that emphasized declarative build descriptions through commands likeadd_library with INTERFACE types, improving modularity and dependency handling.[8]
The evolution continued into the 4.x series, launched with CMake 4.0 on March 29, 2025, which deprecated policies from versions prior to 3.5 to streamline compatibility.[3] Subsequent releases built on this foundation; CMake 4.1.0 arrived in August 2025, followed by 4.1.2 as the latest stable version on September 30, 2025.[9] As of November 2025, the 4.2.0 release candidate series, including 4.2.0-rc2 on October 31, 2025, added new generators such as Visual Studio 18 2026 and FASTBuild for distributed caching.[9] These updates reflect CMake's ongoing commitment to modern language features and performance optimizations, maintaining its status as a cornerstone for cross-platform software development.[10]
Name
The name "CMake" is a portmanteau of "C"—referring to its initial focus on building C and C++ software—and "make", selected to convey a simple, effective build tool in contrast to more complex systems like Imake used in X11 development.[2] It stands for "Cross-platform Make". This naming choice deliberately avoids direct use of "Make" to differentiate from the Unix Make utility, underscoring CMake's function as a meta-build system generator that produces native build files for various platforms and tools rather than executing builds itself.[11] Branding for CMake began with simple text-based representations in its early releases around 2000, evolving to integrate Kitware's corporate visual identity, including a stylized logo featuring the tool's name in a modern sans-serif font aligned with the company's blue and white color scheme.Features
Generators and IDE support
CMake generators are responsible for producing native build system files from CMake configurations, enabling the creation of Makefiles, Ninja build files, IDE project files, and other formats tailored to specific platforms and tools.[12] This abstraction allows developers to write portable build scripts while leveraging optimized native tools for compilation and linking.[12] Major generators include Unix Makefiles for traditional Unix-like systems, which generate standard Makefile syntax for command-line builds; Ninja, a high-performance small build system that produces faster incremental builds; Visual Studio generators supporting versions from 9 2008 up to 17 2022, creating solution (.sln) and project files for Microsoft's IDE; Xcode for Apple ecosystems, outputting project files (.xcodeproj) compatible with Xcode; and CodeLite, which generates project files (.cbp) for the CodeLite IDE.[12] These generators are selected based on the target environment, with platform-specific defaults such as Unix Makefiles on Linux and macOS, or Visual Studio on Windows.[12] CMake provides native integration with several IDEs through its generators and auxiliary mechanisms. Visual Studio offers direct support via its generators, allowing users to open and build .sln files seamlessly within the IDE.[13] CLion and Qt Creator leverage CMakePresets.json for configuration and the CMake File API to access build artifacts and project details, enabling full editing, building, and debugging workflows.[13] For lighter editors, VS Code integrates via the CMake Tools extension, which handles generation and build processes using Ninja or other backends, while Vim relies on community plugins like cmake-tools.vim for similar functionality.[14] Introduced in the CMake 4.2 release candidates (as of November 2025), new generators enhance support for advanced and emerging workflows: the FASTBuild generator enables distributed compilation across machines for faster builds in large projects, and the Visual Studio 18 2026 generator provides experimental compatibility with the unreleased Visual Studio 2026, based on Insider previews.[15] Generators are selected during configuration using thecmake -G command-line option, such as cmake -G [Ninja](/page/Ninja) .. to specify Ninja files, or interactively via cmake-gui; the full list of available generators is shown with cmake --help.[11] This selection influences the entire build tree and can be overridden for cross-compilation scenarios.[11]
Build targets
In CMake, build targets form the core organizational units of a build system, representing the logical components such as executables, libraries, or custom tasks that the build process generates or executes.[16] Each target encapsulates the necessary rules for compilation, linking, and other actions, allowing developers to define project outputs declaratively in CMakeLists.txt files. Targets are created using dedicated commands and can have properties configured to specify sources, dependencies, and build behaviors, promoting modularity and reusability across projects.[16] CMake supports several primary target types. Executable targets are defined with theadd_executable() command, which specifies a target name and one or more source files to compile and link into a runnable binary; for example, add_executable(hello hello.cpp) creates an executable named "hello" from the given C++ source.[17] Library targets are created via add_library(), supporting variants such as static libraries (default or specified with STATIC), shared libraries (SHARED), loadable modules (MODULE), object libraries (OBJECT) for intermediate compilation without archiving, and framework bundles on Apple platforms (FRAMEWORK). For instance, add_library(mylib STATIC source1.cpp source2.cpp) produces a static archive.[18] Custom targets, added with add_custom_target(), represent non-binary outputs or tasks like generating documentation or running scripts, without producing compilable artifacts; an example is add_custom_target(gen_docs COMMAND doxygen) to invoke an external tool.
Target properties control various aspects of a target's build and usage, set using commands like set_target_properties() since CMake 2.8, which allows assigning values to properties such as SOURCES for listing input files, INCLUDE_DIRECTORIES for header paths, and COMPILE_DEFINITIONS for preprocessor macros. Starting with CMake 2.8.12, finer-grained control became available through dedicated target_* commands, such as target_sources(target PRIVATE file.cpp) to add sources scoped to the target. These properties enable customization of build artifacts, like setting OUTPUT_NAME to rename the generated file or POSITION_INDEPENDENT_CODE for PIC compilation in libraries.[19]
The modern target-based API, emphasized since CMake 3.0, shifts away from global variables toward target-centric commands for better encapsulation and portability.[20] Key introductions include target_include_directories() and target_compile_definitions() in CMake 3.0, allowing per-target configuration of includes and defines without affecting the entire project. Linking is handled via target_link_libraries(), which connects targets and propagates properties; for example, target_link_libraries(myexe mylib) links the executable to the library.[21] This command supports scoping keywords—PRIVATE for internal use only, [PUBLIC](/page/Public) for both the target and its consumers, and INTERFACE for consumers alone—introduced in CMake 2.8.12 and refined in 3.0 to enable transitive usage requirements, such as automatically passing include directories to dependent targets. This approach fosters hierarchical project designs where targets expose interfaces without exposing implementation details.[16]
Hierarchical configuration
CMake's hierarchical configuration enables the organization of large projects into modular components by processing multipleCMakeLists.txt files across directories. The add_subdirectory() command is central to this mechanism, as it instructs CMake to load and execute the CMakeLists.txt file from a specified subdirectory, thereby incorporating its contents into the overall build process. This allows developers to structure projects as trees of subprojects, where each subdirectory can define its own targets, dependencies, and settings while maintaining a unified build. For instance, in a project with a root directory containing the main CMakeLists.txt and subfolders for libraries or executables, invoking add_subdirectory(src/lib) from the root would process the corresponding file in the src/lib directory, enabling a scalable and maintainable project layout.[22]
In a typical hierarchical setup, the root CMakeLists.txt file establishes global project policies, such as the minimum required CMake version via cmake_minimum_required(), the project name with project(), and top-level options like enabling languages or setting build types. These settings propagate to subdirectories unless overridden. In contrast, leaf-level CMakeLists.txt files—those in the deepest subdirectories—focus on defining local targets, such as libraries or executables using add_library() or add_executable(), and specifying their immediate dependencies without altering broader project configurations. This division promotes separation of concerns, where the root handles overarching setup and leaves manage specific build artifacts, facilitating collaboration in multi-developer environments.[23]
Variable scoping in CMake hierarchies is managed through directory and function scopes, ensuring isolation while allowing controlled propagation. Each invocation of add_subdirectory() or the function() command creates a new scope, where variables set with set(VAR VALUE) remain local by default and do not affect parent scopes. To propagate values upward, the PARENT_SCOPE option can be used, as in set(MY_VAR value PARENT_SCOPE), which sets the variable in the immediately enclosing scope, such as the parent directory. The function() command, in particular, enforces strict scoping to prevent unintended side effects, differing from macros which share the caller's scope. This design supports clean hierarchies by minimizing global pollution.[24][25]
Best practices for hierarchical CMake projects emphasize avoiding global variables in favor of target-based approaches to enhance modularity and reduce coupling. Instead of relying on directory-wide variables like INCLUDE_DIRECTORIES(), developers should use target-specific commands such as target_include_directories(target PRIVATE path) to attach properties directly to targets, with visibility keywords (PRIVATE, PUBLIC, INTERFACE) controlling propagation to dependents. This target-centric method ensures that subdirectory changes do not inadvertently affect unrelated parts of the project, improving scalability and debuggability in complex builds. For propagation needs, explicit use of PARENT_SCOPE or target properties is recommended over cache variables, aligning with modern CMake principles.[26][27]
Separate build tree
CMake supports out-of-source builds, which involve running the CMake configuration process from a directory separate from the source code tree, thereby generating all build artifacts in the designated build directory while leaving the source directory pristine.[11] This approach has been a core capability since CMake's early versions and is strongly recommended to avoid mixing generated files with source code. Traditionally, users create a new build directory adjacent to the source directory, navigate into it, and invoke CMake with a path to the source directory, such asmkdir build && cd build && cmake ...[11]
Since CMake 3.13, explicit specification of source and build directories has been facilitated by the -S and -B command-line options, allowing invocation from any location without changing directories, for example: cmake -S <path-to-source> -B <path-to-build>.[11] The CMAKE_BINARY_DIR variable is automatically set to the full path of the top-level build tree during configuration, providing a reliable reference for build system scripts and CMakeLists.txt files to locate generated files relative to the build directory rather than the source.[28] This variable remains distinct from CMAKE_SOURCE_DIR, which points to the source tree, enabling clear separation in out-of-source setups.[28]
Out-of-source builds enable the creation of multiple parallel build trees from the same source, such as separate directories for Debug and Release configurations, without duplicating the source code or risking conflicts.[29] This supports efficient management of variant builds, as each tree can be configured independently with different options while sharing the underlying source.[11] Key advantages include preventing source pollution by build outputs like object files and executables, simplifying cleanup through deletion of the entire build directory, and improving integration with version control systems by excluding generated files from the repository.[11] These benefits promote cleaner workflows, especially in large or multi-platform projects.[29]
Dependency management
CMake manages dependencies between build targets through a combination of explicit commands and automated mechanisms, ensuring correct build order, linking, and propagation of compile-time requirements. Internal dependencies within a project are primarily handled via thetarget_link_libraries() command, which establishes both link-time and compile-time relationships between targets. For external dependencies, CMake provides tools like find_package() to locate pre-installed libraries and FetchContent to fetch and integrate source-based dependencies. Transitive dependencies are propagated using INTERFACE libraries and usage requirements, allowing header-only libraries and other non-compiled components to influence downstream targets seamlessly. Recent enhancements, such as broader integration with pkg-config files, further streamline dependency discovery.
Internal Dependencies
Thetarget_link_libraries() command is central to defining internal dependencies in CMake projects. It specifies libraries or targets that a given executable or library depends on, creating link-time edges by adding the necessary linker flags and object files during the build process. For compile-time edges, it propagates usage requirements such as include directories, compile definitions, and compiler flags to dependent targets, ensuring that compilation occurs with the correct settings. The command supports visibility scopes—PRIVATE for internal use only, PUBLIC for both the target and its dependents, and INTERFACE for dependents only—which control how dependencies are inherited. For example, to link an executable myexe to a library target mylib while propagating its include paths:
add_executable(myexe main.cpp)
target_link_libraries(myexe PUBLIC mylib)
add_executable(myexe main.cpp)
target_link_libraries(myexe PUBLIC mylib)
myexe links against mylib and any targets linking to myexe also inherit mylib's public usage requirements.[21]
CMake also automates header dependency scanning for incremental builds, leveraging compiler-specific tools to detect include relationships without manual specification. Introduced in CMake 3.10 for supported generators like Ninja and Makefiles, this feature uses compiler flags (e.g., -MD for GCC/Clang) to generate dependency information at compile time, rebuilding affected sources only when headers change. This reduces build times and errors from missed dependencies, particularly in large projects with complex include graphs.
External Dependencies
For system-installed or third-party libraries,find_package() searches for and configures external dependencies, supporting two modes: Module mode, which uses heuristic Find<PackageName>.cmake scripts provided by CMake, and Config mode, which relies on package-provided <PackageName>Config.cmake files for precise location and version handling. Config mode is preferred for modern packages as it allows exact version matching and component selection, such as requiring specific sub-libraries. An example invocation for the Google Test framework:
find_package(GTest REQUIRED)
target_link_libraries(my_test_exe GTest::gtest_main)
find_package(GTest REQUIRED)
target_link_libraries(my_test_exe GTest::gtest_main)
REQUIRED or provide fallbacks. Module mode, while legacy, remains useful for older or non-CMake packages via paths in CMAKE_MODULE_PATH.[30]
Introduced in CMake 3.11, the FetchContent module addresses cases where dependencies are not pre-installed by downloading and building them from source during the configure step. It declares content via Git, SVN, or file URLs and integrates the resulting targets seamlessly. For instance:
include(FetchContent)
FetchContent_Declare(
googletest
GIT_REPOSITORY https://github.com/google/googletest.git
GIT_TAG 703bd9caab50b139428cea1aaff9974ebee5742e
)
FetchContent_MakeAvailable(googletest)
add_executable(my_test test.cpp)
target_link_libraries(my_test gtest)
include(FetchContent)
FetchContent_Declare(
googletest
GIT_REPOSITORY https://github.com/google/googletest.git
GIT_TAG 703bd9caab50b139428cea1aaff9974ebee5742e
)
FetchContent_MakeAvailable(googletest)
add_executable(my_test test.cpp)
target_link_libraries(my_test gtest)
find_package() to redirect to FetchContent for unified handling.[31]
Transitive Propagation
Transitive dependencies in CMake are managed through usage requirements and INTERFACE libraries, ensuring that dependencies of dependencies are correctly resolved without explicit repetition. When a target links to another viatarget_link_libraries(), PUBLIC and INTERFACE items propagate their properties—such as include directories (target_include_directories()) or compile options—to all consuming targets, forming a dependency graph that the build system traverses for ordering and configuration. PRIVATE items remain isolated to the direct target. This mechanism prevents over-linking and supports modular designs.
For header-only libraries, which lack compiled sources, INTERFACE libraries provide a lightweight way to encapsulate and propagate requirements. Created with add_library(name INTERFACE), they define properties like includes and definitions that are inherited by linking targets. An example for a header-only utility library:
add_library(myutils INTERFACE)
target_include_directories(myutils INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/include)
target_link_libraries(myutils INTERFACE some_external_lib) # If it depends on others
target_link_libraries(myexe [PUBLIC](/page/Public) myutils)
add_library(myutils INTERFACE)
target_include_directories(myutils INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/include)
target_link_libraries(myutils INTERFACE some_external_lib) # If it depends on others
target_link_libraries(myexe [PUBLIC](/page/Public) myutils)
myexe and its dependents automatically receive the include paths and any transitive links from myutils, enabling clean separation of interface concerns. This is particularly valuable for template-heavy or inline code, where no linking artifacts are produced but compile-time visibility is essential.
New Features in CMake 4.0
CMake 4.0 introduces broader pkg-config integration through thecmake_pkg_config() command, allowing native processing of .pc files to generate CMake variables and imported targets without requiring the pkg-config executable. This enhances dependency discovery for Unix-like systems, where many libraries provide pkg-config metadata for flags and paths. The command extracts details like CFLAGS and LIBS, supporting version constraints and strict parsing. For example:
cmake_pkg_config(EXTRACT mypackage 1.0 REQUIRED)
target_link_libraries(my_target mypackage)
cmake_pkg_config(EXTRACT mypackage 1.0 REQUIRED)
target_link_libraries(my_target mypackage)
mypackage::mypackage with propagated properties, bridging traditional pkg-config workflows into CMake's target-based system and improving portability across environments.[32]
Flexible project structure
CMake supports both in-source builds, where the build artifacts are generated within the source directory, and out-of-source builds, where a separate build tree is used to keep the source tree pristine and enable multiple configurations without interference.[11] Out-of-source builds are the recommended approach for larger projects, as they facilitate cleaner management of generated files and easier switching between build types like Debug and Release.[11] For complex dependencies, CMake enables superbuilds through the ExternalProject module, which uses the ExternalProject_Add() command to orchestrate the download, configuration, building, and installation of external projects as part of the main build process.[33] This approach allows a top-level CMake project to manage and integrate third-party libraries or components in external trees, ensuring they are built and linked appropriately without embedding their sources directly.[33] CMake's language-agnostic design permits handling multiple programming languages within the same project via the enable_language() command, which activates support for languages such as C, C++ (CXX), Fortran, Java, CUDA, and others depending on the platform and compiler availability.[34] This flexibility allows developers to mix languages seamlessly, for instance, compiling Fortran routines alongside C++ code in a single build configuration.[34] To accommodate custom workflows, CMake integrates with other build systems like Meson or Bazel using custom commands and targets, such as add_custom_command() or add_custom_target(), which execute external scripts or tools during the build phase. For example, a CMake project can invoke Meson's build process for specific subcomponents via these mechanisms, enabling hybrid setups where CMake oversees the overall structure while delegating parts to alternative tools.[35] Best practices for scalable projects emphasize a minimal root-level CMakeLists.txt file that sets essential options like cmake_minimum_required() and project(), then delegates implementation details to subdirectory CMakeLists.txt files using add_subdirectory().[23] This structure promotes modularity, where the root handles global settings and subdirectories manage local targets, reducing complexity in large codebases and improving maintainability.[36]Compiler feature detection
CMake provides several mechanisms to detect and require specific compiler features, ensuring that build configurations align with the capabilities of the selected compiler. This is particularly important for C++ projects where language standards and extensions vary across compilers like GCC, Clang, and MSVC. The primary tools include functions for testing compiler flags and properties for specifying required features, which automatically adjust compile options such as-std=[c++20](/page/C++20) when support is confirmed.[37]
One fundamental way to test compiler support is through the check_cxx_compiler_flag function, which verifies if a given flag is accepted by the C++ compiler without producing diagnostics. This function, part of the CheckCXXCompilerFlag module, uses an internal try_compile test to attempt compilation with the specified flag and caches the result in a variable for reuse. For instance, to check for C++20 support, the following can be used:
include(CheckCXXCompilerFlag)
check_cxx_compiler_flag(-std=c++20 HAVE_STD_CXX20)
if(HAVE_STD_CXX20)
target_compile_options(my_target PRIVATE -std=c++20)
endif()
include(CheckCXXCompilerFlag)
check_cxx_compiler_flag(-std=c++20 HAVE_STD_CXX20)
if(HAVE_STD_CXX20)
target_compile_options(my_target PRIVATE -std=c++20)
endif()
CMAKE_REQUIRED_QUIET (added in 3.1) to suppress output during testing.[38]
For more structured feature requirements, the target_compile_features command specifies expected compiler features for a target, such as cxx_std_20 for C++20 compliance. Introduced in CMake 3.1, this command checks the feature against the compiler's known capabilities stored in variables like CMAKE_CXX_COMPILE_FEATURES and raises a fatal error if unsupported. If the feature is available, it automatically infers and adds necessary flags, such as -std=gnu++20 for GNU compilers. An example is:
add_library(my_library source.cpp)
target_compile_features(my_library PUBLIC cxx_std_20)
add_library(my_library source.cpp)
target_compile_features(my_library PUBLIC cxx_std_20)
PRIVATE, PUBLIC, or INTERFACE to control propagation to dependent targets. This mechanism supports both required and optional features, with conditional compilation handled via generator expressions.[39][37]
CMake maintains a list of all known C++ features in the global property CMAKE_CXX_KNOWN_FEATURES, which includes meta-features like cxx_std_20 (added in 3.12) representing full standard support. This property, introduced in 3.1, catalogs over 100 features ranging from basic types (cxx_auto_type) to advanced constructs, independent of the current compiler. In contrast, CMAKE_CXX_COMPILE_FEATURES lists only those supported by the detected compiler, enabling precise requirements. For example, cxx_std_20 ensures the compiler handles C++20 elements like concepts and coroutines, with support tracked for compilers such as GCC 10+ and Clang 10+.[40][41]
Automatic detection of language standards is facilitated by the CMAKE_CXX_STANDARD variable, which sets a default C++ standard level (e.g., 20) for all targets in the project unless overridden by target properties. Added in 3.1, this variable influences compile flags globally; for example, setting set(CMAKE_CXX_STANDARD 20) prompts CMake to append -std=[c++20](/page/C++20) (or equivalent) during configuration if the compiler supports it. If the specified standard is unavailable, CMake issues a warning unless CMAKE_CXX_STANDARD_REQUIRED is set to ON, in which case it errors out. This provides a straightforward way to enforce modern standards without manual flag testing in simple cases.[42]
In CMake 4.0, enhancements to C++20 module feature checks were introduced, building on prior module support from 3.28 to include better integration for standard library modules like std with GCC compilers (version 15+). These improvements allow more reliable detection of module-related flags and dependencies, such as those needed for import std;, expanding usability for modular C++ builds across generators like Ninja.[43][44]
Compiler support
CMake supports a range of programming languages as primary targets for building projects, including C, C++, and Fortran, which form the core of its usage in software development.[34] Secondary languages such as CUDA (introduced in version 3.8), HIP (version 3.21), Objective-C (version 3.16), and Swift (version 3.15) are also supported, enabling CMake to handle specialized workloads like GPU programming and Apple ecosystem development.[34] The tool supports various compilers across these languages, with minimum version requirements varying by compiler and feature set. For C and C++, key supported compilers include GCC starting from version 3.4 for C and 4.4 for C++, Clang from 2.9, Microsoft Visual C++ (MSVC) from 2010 (Visual Studio 2010), Intel C++ Compiler from version 12.1, and NVIDIA's NVCC for CUDA from version 7.5.[37] As of 2025, support extends to the MSVC 2026 preview toolset within Visual Studio previews, ensuring compatibility with emerging Microsoft compiler updates. Additional compilers like Cray (8.1+), Fujitsu HPC (4.0+), and PGI/NVHPC (11.0+) are supported for high-performance computing environments.[37]| Compiler | Minimum Version | Languages Supported | Source |
|---|---|---|---|
| GCC | C: 3.4+; C++/Fortran: 4.4+ | C, C++, Fortran | [37] |
| Clang | 2.9+ | C, C++, Objective-C, Swift, CUDA | [37] |
| MSVC | 2010+ (VS 2010) | C, C++, Fortran | [37] |
| Intel | 12.1+ | C, C++, Fortran | [37] |
| NVCC | 7.5+ | CUDA | [37] |
Packaging
CMake provides packaging capabilities through CPack, an integrated tool that generates binary installers and source packages from CMake projects. By including theCPack module in a project's CMakeLists.txt file via include(CPack), developers can configure and create packages using the cpack executable, which supports a variety of formats suitable for different platforms and distribution methods.[48]
CPack supports multiple generators to produce packages such as DEB for Debian-based Linux distributions, RPM for Red Hat-based systems, NSIS for Windows installers, and archive formats like ZIP and TGZ for cross-platform bundles. These generators leverage the installation rules defined in the project's CMake configuration to assemble the final package, allowing for platform-specific customization without altering the core build logic.[49][50]
The install() command is central to specifying files and targets for packaging, directing executables, libraries, headers, and other artifacts to installation directories relative to CMAKE_INSTALL_PREFIX. For modular installations, the COMPONENT option groups items into logical sets, such as "runtime" or "development," enabling selective packaging and user choices during installation. CPack integrates these components via the CPackComponent module, which allows defining dependencies between components and generating installers that prompt users for selections.[51][52]
Configuration occurs through CPACK_* variables, such as CPACK_PACKAGE_NAME for the package identifier, CPACK_GENERATOR to select output formats, and CPACK_PACKAGE_VERSION for versioning. These variables can be set in CMakeLists.txt or overridden at runtime, providing flexibility for tailored packages. The packaging workflow supports a streamlined one-step process: after building the project, running cpack (or cmake --build . --target package) installs files to a staging directory and bundles them into the final package.[48][50]
Introduced in CMake 4.0, native support for the cmake_pkg_config command enables processing of pkg-config files directly within CMake, generating imported targets and variables without requiring an external pkg-config tool, which enhances packaging of dependencies across ecosystems. Additionally, experimental support for the Common Package Specification (CPS) improves dependency packaging by allowing export and import of transitive dependencies in a standardized format, facilitating better resolution in multi-package scenarios when enabled via CMAKE_EXPERIMENTAL_FIND_CPS_PACKAGES.[53][54]
GUI
CMake provides two primary graphical user interfaces for interactive configuration of projects: ccmake, a terminal-based curses interface, and cmake-gui, a cross-platform Qt-based application. These tools allow users to edit CMake cache variables, select build generators, and generate build systems without relying on command-line invocation, facilitating easier setup for complex projects.[11] ccmake serves as a lightweight, text-based GUI utilizing the ncurses library to enable interactive editing of CMake variables and management of the CMake cache file (CMakeCache.txt). Users navigate the interface using keyboard controls, such as arrow keys to select variables, Enter to edit values, and 'c' to configure the project or 'g' to generate build files. It displays variable descriptions and supports toggling the view of advanced cache entries by pressing 't', hiding less commonly used options by default to streamline the configuration process. This tool is particularly suited for environments without graphical desktops, such as remote servers or embedded systems, and integrates seamlessly with terminal workflows for iterative cache adjustments.[55][56] In contrast, cmake-gui offers a full graphical interface built with Qt, providing a more visual and user-friendly experience across Windows, macOS, and Linux platforms. It features fields for specifying source and build directories, a dropdown for selecting build generators (e.g., Ninja, Visual Studio), and a table for editing cache variables with inline help text. Users can enable a "Search" box to filter variables by name, toggle "Advanced" view via a checkbox to reveal hidden options, and group variables by prefix for better organization. The interface updates in real-time during configuration, warning of errors, and supports presets from CMakePresets.json files for reproducible setups.[57][56] Both tools can be launched directly from integrated development environments (IDEs) that support CMake, such as by invoking them via build menus or scripts to handle initial project configuration before IDE-specific project generation. This integration allows developers to leverage the GUIs for fine-tuning options like compiler flags or dependency paths without leaving their primary workflow.[11] Despite their utility, these GUIs have limitations, including a lack of support for scripting or automation, making them unsuitable for continuous integration pipelines or batch processing; they are designed primarily for one-time or occasional interactive setup rather than repeated executions. Additionally, changing the build generator after initial configuration requires clearing the build directory, as the cache becomes tied to the selected generator.[56]Precompiled headers and modules
CMake provides support for precompiled headers (PCH) through thetarget_precompile_headers() command, introduced in version 3.16, which allows specifying a list of header files to precompile for a target to accelerate subsequent compilations by reusing partially processed versions of those headers.[58] This command supports visibility options such as INTERFACE, PUBLIC, and PRIVATE to control how the precompiled headers are propagated to dependent targets, and it generates a PCH file (e.g., cmake_pch.h or cmake_pch.hxx) that is automatically force-included in source files via compiler flags like -include for GCC or /FI for MSVC.[58] Automatic PCH generation is handled by populating target properties like PRECOMPILE_HEADERS, enabling reuse across sources without manual intervention, though care must be taken to ensure consistent compiler settings to avoid mismatches.[59]
Unity builds, also known as jumbo builds, are supported via the UNITY_BUILD target property, added in CMake 3.16, which combines multiple source files into fewer "unity" source files to reduce compilation overhead and speed up the build process by minimizing repeated header processing.[60] Developers enable this by setting set_target_properties(target PROPERTIES UNITY_BUILD ON), with the global CMAKE_UNITY_BUILD variable providing default control; the property uses algorithms like BATCH (default, grouping files automatically) or GROUP (explicit via source properties) to form unity files, limited by UNITY_BUILD_BATCH_SIZE to prevent excessively large files.[60] This feature is available for C, C++, CUDA (since 3.31), and Objective-C languages, but requires compatible compilers and may introduce one-definition-rule issues if not managed carefully.[60]
CMake introduced experimental support for C++20 header units in version 3.28 (released in 2023), allowing basic integration of modular headers, though full header unit support remains limited as of the latest releases.[61] Full C++20 modules, including named modules, are officially supported starting in 3.28 with the Ninja and Visual Studio generators (VS 2022+), using file sets of type CXX_MODULES in target_sources() to specify module interface files like .ixx for MSVC or .cppm for others, with automatic scanning for import dependencies to enforce compilation ordering.[61] In CMake 4.0 (released in 2025), enhanced integration for the GCC standard library module (import std;) was added for GCC 15 and later, enabling seamless use of compiler-provided modules alongside custom ones via properties like CXX_MODULE_STD.[62]
For Fortran, CMake natively handles module dependencies through automatic scanning of source files for MODULE and USE statements, generating and tracking .mod files since version 3.10, with the Fortran_MODULE_DIRECTORY target property allowing specification of a dedicated output directory for these files to organize builds involving mixed-language projects.[63] This ensures proper dependency resolution without manual intervention, supporting compilers like gfortran and supporting propagation of module interfaces across targets.[63]
Language
Command syntax
CMake commands are invoked in CMakeLists.txt files using a simple, parenthesized syntax that specifies the command name followed by its arguments. The general form iscommand(arg1 arg2 ... ), where the command name is case-insensitive and the arguments are enclosed in parentheses, separated by whitespace or newlines.[64] Arguments are treated as strings or lists; unquoted arguments are automatically split into lists using semicolon (;) as the delimiter, unless the semicolon is escaped with a backslash (\;).[64] To preserve semicolons in paths or multi-word arguments (e.g., those containing spaces), arguments can be quoted with double quotes ("...") or enclosed in bracket argument syntax ([=[...]=]), which supports nested content without escaping.[64]
Comments in CMake scripts begin with a hash symbol (#) and extend to the end of the line, allowing inline documentation without affecting execution.[64] For multi-line or bracketed comments that might include special characters, the bracket argument syntax can be used, such as #[=[This is a multi-line comment]=]#.[64] When dealing with file paths that include spaces, proper quotation is essential to prevent unintended list splitting; for instance, set(PATH_TO_SOURCE "/path with spaces/main.cpp") ensures the entire path is treated as a single argument.[64]
Control flow structures in CMake enable conditional execution and iteration, forming the basis for dynamic script behavior. Conditional blocks use if(condition) paired with endif(), optionally including elseif() or else() for branching; the condition is evaluated as a boolean expression.[65] Loops are supported via foreach(item IN LISTS listname ITEMS item1 item2 ...) or while(condition), each terminated by endforeach() or endwhile(), respectively, allowing repetition over lists or until a condition fails.[66] These constructs process commands line-by-line within their blocks, with variables (detailed in the Variables and expressions section) often used to store and manipulate loop variables or conditions.[64]
CMake provides mechanisms for defining reusable code through functions and macros, which differ in scope and argument evaluation. A function is declared with function(name arg1 arg2 ... ) and ended by endfunction(), creating a new variable scope where arguments are evaluated lazily upon invocation, similar to procedural calls in other languages.[25] In contrast, a macro uses macro(name arg1 arg2 ... ) and endmacro(), operating in the caller's scope and substituting arguments textually before evaluation, which can lead to unintended variable capture but allows more direct text replacement. For example, a simple function might be defined as:
function(add_numbers a b result)
math(EXPR ${result} "${a} + ${b}")
endfunction(add_numbers)
function(add_numbers a b result)
math(EXPR ${result} "${a} + ${b}")
endfunction(add_numbers)
${result} in the function's local scope, invoked as add_numbers(1 2 output).[25] Macros, however, expand arguments immediately, making them suitable for simple substitutions but riskier for complex logic due to scope sharing.
Variables and expressions
In CMake, variables are fundamental data structures used to store and manipulate values during the configuration and build process. Normal variables are defined using theset() command with the syntax set(<variable> <value>... [PARENT_SCOPE]), which assigns one or more values to the variable in the current scope; multiple values automatically form a semicolon-separated list.[24] For example, set(MY_LIST item1 item2 item3) creates a list variable that can be iterated or joined later in the CMakeLists.txt file.[24] These variables are scope-specific and do not persist beyond the current directory or function unless the PARENT_SCOPE option is used to propagate them upward.[24]
Cache variables provide persistence across CMake runs and allow user interaction via the CMake GUI or command line, making them ideal for configurable options like build paths or feature flags. They are set with set(<variable> <value>... CACHE <type> <docstring> [FORCE]), where <type> specifies the data type (e.g., BOOL, [STRING](/page/String), PATH), and the optional FORCE overwrites existing cache entries.[24] For instance, set(BUILD_TESTS ON CACHE BOOL "Enable unit tests") stores a boolean value that users can toggle, ensuring reproducibility in multi-run builds.[24] Unlike normal variables, cache entries are written to the CMakeCache.txt file and can be queried or modified externally.[24]
Properties in CMake extend variables by associating metadata with specific entities like targets, directories, or the global scope, enabling fine-grained control over build behaviors. They are accessed and manipulated using commands such as get_target_property(<variable> <target> <property>) for target-specific properties or get_directory_property(<variable> [<directory>] <property>) for directory-wide ones.[19] A common example is the INCLUDE_DIRECTORIES property, which can be retrieved with get_target_property(INCLUDES my_target INTERFACE_INCLUDE_DIRECTORIES) to obtain a list of header search paths for a given target, allowing dynamic adjustments based on project needs.[19] Properties support various categories, including those for sources, tests, and cache entries, and their values can be used interchangeably with regular variables in expressions.[19]
Generator expressions, introduced in CMake 3.0, provide a powerful mechanism for conditional logic evaluated at build time rather than configuration time, using the syntax $<expression> within commands like target_include_directories() or properties.[67] The $<CONFIG> expression returns the active build configuration (e.g., "Debug" or "Release"), enabling config-specific settings, as in target_compile_definitions(my_target PRIVATE $<$<CONFIG:Debug>:DEBUG_BUILD>), which defines DEBUG_BUILD only for Debug builds.[67] Similarly, $<TARGET_PROPERTY:tgt,prop> retrieves a property value from a target, such as $<TARGET_PROPERTY:my_target,INCLUDE_DIRECTORIES>, allowing runtime queries that adapt to the build environment without re-running CMake.[67] These expressions support nesting and logical operators for complex conditions, like version checks on compilers.[67]
Since CMake 3.19, the string() command includes support for JSON string manipulation, facilitating the extraction and processing of structured data like package metadata into variables.[68] Using subcommands like JSON GET, values can be queried from a JSON string, as in:
set(package_json "{\"name\": \"example\", \"version\": \"2.1.0\"}")
string(JSON version GET "${package_json}" version)
set(package_json "{\"name\": \"example\", \"version\": \"2.1.0\"}")
string(JSON version GET "${package_json}" version)
version variable, converting JSON elements to CMake-compatible types (e.g., strings, booleans as ON/OFF, or numbers).[68] Other subcommands, such as JSON LENGTH for array/object sizes or JSON SET for modifications, integrate seamlessly with variables, enabling dynamic handling of external data sources like manifest files in modern package ecosystems.[68]
Internals
Implementation
CMake's core engine is implemented in C++ using an object-oriented design that emphasizes inheritance and encapsulation to manage the build configuration process.[69] This modular architecture divides responsibilities into distinct components, including reader modules for input processing, evaluator modules for script execution, and writer modules for output generation, enabling extensible handling of commands and configurations.[69] The engine operates in a two-phase manner: first, the configure phase reads and evaluates input files to build an in-memory representation of the project; second, the generate phase produces the necessary build files or IDE projects based on that representation.[69] The parser interprets CMakeLists.txt files as a scripting language, employing a lex/yacc-based lexical analyzer and parser to tokenize and syntactically analyze the input.[69] During this process, it generates dependency graphs by automatically scanning source files for inclusions and other relationships, particularly for languages like C, C++, and Fortran, to determine build order and incremental compilation needs.[69] These graphs are represented internally through objects such ascmMakefile for directory-level targets and cmTarget for individual build artifacts, ensuring efficient traversal and resolution of interdependencies.[69]
The cache system maintains project configuration in a file named CMakeCache.txt, which stores persistent variables and settings generated during the initial configure run.[11] This file allows CMake to avoid re-evaluating unchanged aspects across invocations, but it is regenerated or updated if source changes or explicit reconfiguration occurs, preserving user-specified options while adapting to modifications.[11] By design, the cache decouples configuration from environment variables, promoting reproducibility in cross-platform builds.[69]
For enhanced IDE integration, CMake introduced a file-based API in version 3.14, documented as cmake-file-api(7), which exposes semantic details of the generated buildsystem through JSON-formatted query and reply files in the .cmake/api directory.[70] Clients, such as IDEs, initiate queries for objects like codemodel versions to retrieve information on targets, directories, and configurations without needing a persistent server connection.[70] The codemodel uses major version 2 since the API's introduction in 3.14, with minor version updates over time (e.g., to 2.8 in CMake 4.0) providing more detailed structural insights into the buildsystem for improved project navigation and editing support.[70]
Build process
The CMake build process involves a multi-stage workflow that separates configuration, generation of build files, and actual compilation, enabling cross-platform consistency and efficient incremental builds. This out-of-source approach recommends creating a separate build directory to keep source files clean and allow multiple build configurations without duplication.[11] The first stage is configuration, where CMake reads theCMakeLists.txt files in the source tree, detects the compiler and system features, and populates a cache of variables for reuse. This step uses the command cmake [<options>] -B <build-dir> [-S <source-dir>], with options like -G <generator> to select the build system (e.g., Unix Makefiles or Ninja) and -D <var>=<value> to set cache entries such as build type or paths. During configuration, CMake performs platform detection, resolves dependencies, and stores results in CMakeCache.txt to avoid redundant work on subsequent runs; changes to source files or CMakeLists.txt trigger partial reconfiguration to update only affected parts.[11][11]
Following configuration, the generation stage produces native build files tailored to the chosen generator, such as Makefiles or Visual Studio project files, based on the processed CMake instructions. This is invoked implicitly during the initial cmake run or explicitly with cmake --build <dir> --preset=<name> for preset-based workflows. The resulting files enable the build tool to handle compilation, linking, and dependency resolution.[11]
The final building stage compiles and links the project using the generated files, typically via cmake --build <dir> [--target <tgt>] [-- <build-tool-args>], which unifies invocation across generators without needing the native tool directly (e.g., make or ninja). Options include --parallel or -j <jobs> for concurrent builds to speed up large projects, --target <tgt> to build specific targets like executables or libraries, and --clean-first for cleaning outputs before rebuilding to ensure a fresh state. Reconfiguration integrates seamlessly if source changes are detected, minimizing full rebuilds through dependency tracking.[11][11]
In CMake 4.1, enhancements to the Makefile and Ninja generators introduced support for linker launchers in Fortran, CUDA, and HIP languages via the CMAKE_<LANG>_LINKER_LAUNCHER variable, allowing custom tools to wrap linking steps for better integration with specialized environments.[71]
Ecosystem
Additional tools
CMake provides several companion tools that extend its functionality for testing, packaging, and diagnostic reporting. Among these, CTest serves as the primary test driver, enabling automated unit testing and integration within CMake projects. By invoking theenable_testing() and add_test() commands in a CMakeLists.txt file, developers can define tests that CTest executes and reports on, supporting parallel runs with the -j option and verbose output via -V. A key feature for selective test execution is the -R <regex> command-line option, which runs only tests whose names match the specified regular expression, available since CMake 2.4.[72][73]
CTest also facilitates continuous integration by integrating with CDash, an open-source dashboard application for aggregating and visualizing build and test results across distributed systems. Projects can submit results to a CDash server using CTest's dashboard modes—such as Experimental, Nightly, or Continuous—through a sequence of steps including Start, Update, Configure, Build, Test, and Submit, executed via the ctest -S script mode or directly from the command line. This setup allows teams to monitor build health, track regressions, and generate reports without manual intervention.[74][75]
CPack complements CMake by generating installers and packages from the project's installation rules, invoked separately after the CMake configuration and build phases. The cpack command reads a generated CPackConfig.cmake file—produced when the CPack module is included in the CMakeLists.txt—and creates output in formats specified by the -G option, such as ZIP, DEB, or NSIS installers (e.g., cpack -G ZIP). This tool supports a wide range of generators for different platforms, ensuring portable distribution of built artifacts.[50][48]
For handling runtime libraries, particularly on Windows with MSVC, CMake includes the rare but useful InstallRequiredSystemLibraries module, which detects and installs necessary compiler-provided runtime libraries (such as MSVCRT.dll) to avoid dependency issues in distributed binaries. In recent developments, CMake 4.0 introduced support for the SARIF (Static Analysis Results Interchange Format) standard, enabling export of build diagnostics—including static analysis warnings—in a standardized JSON format via the CMAKE_EXPORT_SARIF variable, improving integration with analysis tools and IDEs as of October 2025.[76][77][78]
Adoption
CMake has seen widespread adoption across major open-source projects, particularly in C++ ecosystems. The KDE project, one of the earliest large-scale adopters, transitioned to CMake around 2006 to manage its complex, cross-platform framework development.[79] LLVM and Clang, core components of modern compiler infrastructure, have relied on CMake as their primary build system since version 3.8 (2016), enabling reliable target exports for downstream projects.[80] MySQL uses CMake for source configuration and building across platforms, providing extensive options for customization.[81] Boost, a foundational C++ library collection, integrates with CMake through dedicated support modules, facilitating its use in countless CMake-based builds despite its primary b2 tool.[82] Unreal Engine supports CMake natively for Linux builds and external library integration, streamlining cross-platform game development workflows.[83] In a 2024 survey of modern C++ developers, 83% reported using CMake, reflecting its dominance in top GitHub repositories for the language.[84] In industry applications, CMake powers diverse sectors beyond general software development. In game development, it enables plugin and external C++ library integration for engines like Unreal, supporting rapid iteration in high-performance environments. For scientific computing, the Insight Toolkit (ITK) and Visualization Toolkit (VTK) are built exclusively with CMake, ensuring reproducible builds for medical imaging and data visualization pipelines.[85][86] In embedded systems, CMake's toolchain files facilitate cross-compilation to various architectures, making it a staple for resource-constrained device firmware. CMake's growth trajectory traces from a niche tool in the early 2000s, initially developed for ITK and VTK, to the de facto standard for C++ builds by the 2010s, driven by its cross-platform reliability and extensibility.[2] By 2025, it achieves over 2 million downloads per month, underscoring its entrenched role in professional and open-source workflows.[46] Despite its prevalence, adoption faces hurdles, including a learning curve for developers accustomed to simpler scripting, which can complicate initial setup for complex configurations.[87] Migrating from legacy systems like Autotools requires manual reconfiguration without automated tools, often demanding significant effort to replicate conditional logic and platform checks.[88]Examples
Hello world
To create a basic "Hello, World!" program using CMake, begin with a minimal project structure consisting of a single source file and aCMakeLists.txt configuration file.[36]
The CMakeLists.txt file specifies the project's requirements and targets. A minimal version includes the following commands:
cmake_minimum_required(VERSION 3.10)
project(Hello)
add_executable(hello main.cpp)
cmake_minimum_required(VERSION 3.10)
project(Hello)
add_executable(hello main.cpp)
cmake_minimum_required command enforces a minimum CMake version to ensure compatibility with required features.[47] The project command declares the project name, which influences variable scoping and default build settings. The add_executable command defines an executable target named hello built from main.cpp.[17]
The source file main.cpp contains a standard C++ "Hello, World!" implementation:
#include <iostream>
int main() {
std::cout << "Hello, World!" << std::endl;
return 0;
}
#include <iostream>
int main() {
std::cout << "Hello, World!" << std::endl;
return 0;
}
- Create a build directory:
mkdir build - Enter the build directory:
[cd](/page/.cd) build - Configure the build:
cmake .. - Compile the project:
cmake --build .
build directory using an out-of-source build approach, which keeps source files clean. The cmake .. command reads CMakeLists.txt from the parent directory and configures the project based on the detected compiler and platform. The cmake --build . command invokes the native build tool (e.g., Make on Linux or MSBuild on Windows) to produce the executable.
Upon successful compilation, an executable named hello (or hello.exe on Windows) is created in the build directory. Running it with ./hello (or hello.exe on Windows) outputs:
Hello, World!
Hello, World!
Multi-file project
In CMake, multi-file projects are organized using a hierarchical directory structure, where the rootCMakeLists.txt file invokes subdirectories containing their own build configurations via the add_subdirectory() command. This approach enables modular development, allowing separate CMakeLists.txt files to define libraries, executables, and dependencies within subfolders, while the top-level file orchestrates the overall build.[36]
Consider a project with source code divided into a library and an application. The directory structure might include a src/lib subdirectory for the library sources and a src/app subdirectory for the executable. In the root CMakeLists.txt, the following commands integrate these components:
cmake_minimum_required(VERSION 3.10)
project(MyProject)
add_subdirectory(src/lib)
add_subdirectory(src/app)
cmake_minimum_required(VERSION 3.10)
project(MyProject)
add_subdirectory(src/lib)
add_subdirectory(src/app)
src/lib/CMakeLists.txt file defines a static library target, such as a simple math utility:
add_library(math math.cpp)
add_library(math math.cpp)
math.cpp contains the library's implementation, and add_library() creates a target named math, typically producing a static archive like libmath.a during the build.
In the src/app/CMakeLists.txt file, an executable target is created that depends on the library:
add_executable(calc calc.cpp)
target_link_libraries(calc math)
add_executable(calc calc.cpp)
target_link_libraries(calc math)
add_executable() command builds the calc executable from calc.cpp, while target_link_libraries() specifies that calc links against the math library, ensuring the executable can access the library's functions at runtime. To handle header includes, modern CMake recommends using target_include_directories() on the library target for public interfaces:
target_include_directories(math PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
target_include_directories(math PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
calc automatically.
For integrating external libraries, such as the Eigen linear algebra library, the find_package() command locates and configures the dependency. In the root or relevant CMakeLists.txt, add:
find_package(Eigen3 REQUIRED NO_MODULE)
target_link_libraries(calc Eigen3::Eigen)
find_package(Eigen3 REQUIRED NO_MODULE)
target_link_libraries(calc Eigen3::Eigen)
cmake . (or cmake -S . -B build for out-of-source builds) in the project root to generate build files, followed by make (or the appropriate generator command) to compile. This produces the libmath.a static library in the build directory and the calc executable, which can then be run directly. Target linking ensures dependencies are resolved correctly, with the library archived before the executable is linked.[36]