CMake
A cross-platform build system generator that produces native build files for multiple platforms and compilers, created by Kitware for the Insight Toolkit project.
Created by Bill Hoffman (Kitware)
CMake is a cross-platform build system generator created by Kitware. Rather than building software directly, CMake generates native build files for the user’s platform of choice – Makefiles, Ninja files, Visual Studio solutions, Xcode projects, and more. Originally developed to solve the cross-platform build challenges of a government-funded medical imaging project, CMake has grown to become the dominant build system in the C and C++ ecosystem, used by projects ranging from KDE and LLVM to Qt and Blender.
History & Origins
Background and Motivation
In 1999, Kitware was contracted by the U.S. National Library of Medicine to develop the Insight Segmentation and Registration Toolkit (ITK), a large-scale medical image analysis library. The project needed to build reliably across multiple platforms – Linux, Windows, and macOS – using each platform’s native compilers and development environments. The existing build tools were inadequate: Make was Unix-centric, and autotools had poor support for Windows and generated no IDE project files.
Kitware had prior experience with this problem. Their Visualization Toolkit (VTK) used a tool called pcmaker, developed by Ken Martin, which converted Unix Makefiles to Windows NMake files. This approach required developers to check in platform-specific binary executables when adding libraries and offered no IDE support. The TargetJr system they had previously worked with had gone through imake and gmake before reaching similar limitations.
Creation and First Release
Bill Hoffman, a co-founder of Kitware, designed CMake to address all of these shortcomings. The core requirements were clear: depend only on a C++ compiler, support native IDE project file generation (particularly Visual Studio), use a single input format across all platforms, and detect system capabilities at configure time rather than hard-coding platform differences.
Development began in 1999, and on August 31, 2000, Hoffman introduced CMake to the ITK community. CMake was successfully building ITK from its first day. The tool was designed around a two-stage process: first, CMake reads CMakeLists.txt files and generates platform-native build files; then the native build tool (Make, Ninja, Visual Studio, etc.) performs the actual compilation.
Growth Through Scientific Computing
CMake’s early adoption came from the scientific and high-performance computing communities. After proving itself with ITK, CMake was adopted by VTK and ParaView in 2002. Researchers at the Los Alamos, Sandia, and Livermore national laboratories became early contributors, drawn by CMake’s ability to handle large, complex codebases that needed to run on everything from desktop workstations to supercomputers.
In 2003, Ken Martin and Bill Hoffman published “Mastering CMake,” providing the first comprehensive guide to the tool. Articles in Dr. Dobb’s Journal and Linux Journal helped introduce CMake to a broader audience of developers.
Design Philosophy
Build System Generation
CMake’s fundamental design principle is that it does not build software itself – it generates build files for other tools. This separation means CMake does not need to understand every nuance of every compiler and linker. Instead, it leverages the deep platform knowledge already embedded in tools like Make, Ninja, and Visual Studio. This architectural decision allows CMake to support new platforms and toolchains without rebuilding its core logic.
System Introspection
CMake emphasizes detecting system capabilities at configure time rather than requiring developers to maintain platform-specific configuration. Commands like find_package(), check_include_file(), and try_compile() allow CMakeLists.txt files to adapt to what is actually available on the build machine. This introspection model was inspired by the approach used by autoconf, but implemented in a way that works natively on Windows and other non-Unix platforms.
Single Input, Multiple Outputs
A single set of CMakeLists.txt files can generate build files for any supported platform. A developer on macOS can generate an Xcode project while a colleague on Windows generates a Visual Studio solution, both from the same source. This eliminates the need to maintain separate build configurations per platform.
Key Features
Generator System
CMake supports multiple “generators” that produce different types of build files:
- Makefiles: Unix Makefiles, MinGW Makefiles, NMake Makefiles
- Ninja: High-performance build system with minimal overhead
- IDE Projects: Visual Studio (multiple versions), Xcode, CodeBlocks, Eclipse CDT
- Others: Watcom WMake, Borland Makefiles
Target-Based Build Model
Modern CMake (3.0+) centers on targets – logical units like executables and libraries – with associated properties. Dependencies between targets propagate automatically through visibility specifiers:
| |
In this model, myapp automatically inherits mylib’s public include directories and C++17 requirement. The PUBLIC, PRIVATE, and INTERFACE keywords control how properties propagate through the dependency graph.
CTest
CTest is CMake’s integrated testing framework. It discovers and runs tests defined with add_test(), supports parallel execution, timeout enforcement, and regex-based pass/fail detection. CTest can also submit results to CDash, Kitware’s testing dashboard system.
CPack
CPack generates platform-native installers and packages from CMake projects. Supported formats include DEB and RPM packages for Linux, NSIS and WiX installers for Windows, DMG bundles for macOS, and archive formats like ZIP and TGZ.
CMake Presets
Introduced in CMake 3.19, presets allow projects to define standardized configure, build, and test configurations in JSON files (CMakePresets.json). This eliminates the need to communicate long command-line invocations and ensures all developers use consistent settings.
FetchContent
The FetchContent module (CMake 3.11+) downloads and integrates external dependencies at configure time. This allows projects to declare their dependencies directly in CMakeLists.txt and have CMake retrieve and build them automatically, reducing the need for pre-installed system packages.
Generator Expressions
Generator expressions are conditional expressions evaluated at build-system generation time rather than configure time. They enable per-configuration settings and target-dependent logic:
| |
Policy System
CMake maintains backward compatibility through its policy system. Each CMake version can introduce new behaviors without breaking existing projects. The cmake_minimum_required() command sets the expected policy version, and individual policies can be explicitly set to OLD or NEW behavior, allowing gradual migration.
Evolution
CMake’s evolution can be divided into two major eras:
The Classic Era (2000-2013)
Early CMake used an imperative, variable-centric approach. Build configuration involved setting global variables like CMAKE_CXX_FLAGS, INCLUDE_DIRECTORIES, and LINK_LIBRARIES. This approach worked but led to fragile builds where the order of variable settings mattered and dependencies between targets were implicit rather than explicit.
During this period, CMake steadily added platform support and features. The addition of the Ninja generator in 2012 was significant, as Ninja’s speed advantages over Make made CMake-based builds noticeably faster on large projects.
The Modern Era (2014-Present)
CMake 3.0, released in June 2014, introduced the target-based build model that defines “Modern CMake.” Instead of setting global variables, developers define properties on targets and specify how those properties propagate. This approach produces more reliable, composable, and maintainable build configurations.
Subsequent releases continued refining the modern model:
- 3.11 (2018): FetchContent module for dependency management
- 3.19 (2020): CMake Presets for standardized configuration
- 3.28 (2023): C++20 module dependency scanning support
CMake 4.0, released in March 2025, marked a significant milestone by dropping backward compatibility with CMake versions older than 3.5, signaling that the modern target-based approach is now the expected standard.
Current Relevance
CMake is the dominant build system generator for C and C++ projects. Its adoption extends across virtually every segment of the C/C++ ecosystem:
- IDEs: Visual Studio, CLion, Qt Creator, and VS Code all provide native or first-party CMake support
- Package managers: vcpkg and Conan both integrate tightly with CMake
- CI/CD: Major CI platforms provide CMake pre-installed in their build environments
- Standards: CMake is the de facto standard for building C++ open-source libraries, with most expecting consumers to use
find_package()for integration
The CMake community is active, with regular releases maintaining compatibility with new compilers, platforms, and language standards. The project is developed on gitlab.kitware.com and mirrored to GitHub, with contributions from both Kitware employees and the broader community.
Why It Matters
CMake’s impact on the C and C++ ecosystem has been transformative:
Cross-platform C++ development: Before CMake, building a C++ project across Linux, Windows, and macOS often required maintaining separate build systems. CMake made true cross-platform development practical for projects of any size.
IDE integration without lock-in: By generating native IDE project files, CMake allowed developers to use their preferred development environment without committing the project to any single IDE’s proprietary format.
Ecosystem unification: CMake provided a common build interface that enabled the growth of C++ package managers and dependency management tools. The
find_package()mechanism became the standard way for C++ libraries to advertise their location and usage requirements.Modern build practices: The target-based model introduced in CMake 3.0 brought software engineering principles like encapsulation and explicit dependency management to the build system layer, improving the maintainability of large C++ codebases.
Scientific and industrial adoption: CMake’s origins in scientific computing and its support for complex, multi-platform builds made it the natural choice for industries where software must run reliably across diverse environments – from national laboratories to game studios to embedded systems manufacturers.
Timeline
Notable Uses & Legacy
KDE
One of the largest open-source C++ projects switched its entire build system from autotools to CMake in 2006, serving as CMake's breakthrough adoption moment
LLVM/Clang
The LLVM compiler infrastructure project adopted CMake as its sole build system in 2016, replacing autoconf
Qt
The Qt cross-platform application framework adopted CMake as the build system for Qt 6, shipping in December 2020
Blender
The open-source 3D creation suite uses CMake for cross-platform builds across Linux, macOS, and Windows
MySQL
Oracle's MySQL database uses CMake as its build system for compiling across multiple platforms