CMake Complete Guide (2025 Edition)

1 · Introduction & Core Concepts

What is CMake?

CMake is a cross‑platform, open‑source build‑system generator. It produces native build files (Ninja, Makefiles, Visual Studio solutions, etc.), letting you describe your project once in portable CMakeLists.txt files. As of April 10 2025 the latest stable version is CMake 4.0.1.

Two‑Phase Workflow

Key Terms

2 · Installing CMake

Package Managers

Official Binaries

Download self‑extracting installers or .zip/.tar.gz archives from cmake.org — always grab the latest 4.0.1 release.

From Source

git clone https://github.com/kitware/cmake.git
cd cmake && ./bootstrap && make -j$(nproc) && sudo make install

3 · Configure‑Build‑Install Workflow

Out‑of‑Source Build

# 1 · Configure
cmake -S . -B build -G Ninja -D CMAKE_BUILD_TYPE=Release

# 2 · Build
cmake --build build

# 3 · Install (optional)
cmake --install build --prefix /usr/local

Re‑Configuring

Edit CMakeLists.txt → run cmake -S . -B build again. CMake re‑evaluates only changed files.

Build Presets (CMakePresets.json)

{
  "version": 4,
  "configurePresets": [
    {
      "name": "ninja-release",
      "generator": "Ninja",
      "binaryDir": "${sourceDir}/build",
      "cacheVariables": {
        "CMAKE_BUILD_TYPE": "Release"
      }
    }
  ]
}

Run cmake --preset ninja-release to configure; cmake --build --preset ninja-release to build.

4 · Anatomy of CMakeLists.txt

Minimal Example

cmake_minimum_required(VERSION 3.20)
project(hello LANGUAGES CXX)

add_executable(hello src/main.cpp)

target_compile_features(hello PRIVATE cxx_std_20)

Variables & Lists

Conditional Logic

if (CMAKE_SYSTEM_NAME STREQUAL "Windows")
  set(PLATFORM_DEFINES WIN32_LEAN_AND_MEAN)
endif()

Generator Expressions

Evaluate during generation: $<CONFIG:Debug>, $<TARGET_FILE:foo>.

5 · Targets & Modern CMake Patterns

Adding Targets

Usage Requirements

Prefer target_*() commands:

target_include_directories(hello
  PUBLIC ${PROJECT_SOURCE_DIR}/include)     # Propagates to dependents
target_link_libraries(hello
  PRIVATE fmt::fmt)                          # Link only for this target

Interface & ALIAS Libraries

Provide header‑only packages or rename targets:

add_library(spdlog::spdlog ALIAS spdlog)

Compile Features, Options & Definitions

target_compile_features(hello PUBLIC cxx_std_23)
target_compile_options(hello PRIVATE -Wall -Wextra)
target_compile_definitions(hello PUBLIC VERSION_MAJOR=${VERSION_MAJOR})

6 · Dependencies & Package Management

find_package()

Searches for package config files (FooConfig.cmake) or FindFoo.cmake modules.

FetchContent (>= 3.11)

include(FetchContent)
FetchContent_Declare(
  json
  GIT_REPOSITORY https://github.com/nlohmann/json.git
  GIT_TAG        v3.11.3
)
FetchContent_MakeAvailable(json)

ExternalProject, CPM.cmake, vcpkg

For large downloads or pre‑built binaries use ExternalProject_Add(). Modern alternative: CPM.cmake. vcpkg integrates via -DCMAKE_TOOLCHAIN_FILE=[vcpkg]/scripts/buildsystems/vcpkg.cmake.

7 · Toolchains, Cross‑Compiling & Presets

Toolchain Files

# toolchain-arm64-linux.cmake
set(CMAKE_SYSTEM_NAME Linux)
set(CMAKE_SYSTEM_PROCESSOR aarch64)
set(CMAKE_C_COMPILER aarch64-linux-gnu-gcc)
set(CMAKE_CXX_COMPILER aarch64-linux-gnu-g++)

Invoke: cmake -S . -B build -DCMAKE_TOOLCHAIN_FILE=toolchain-arm64-linux.cmake

Presets for Cross Builds

{
  "configurePresets": [
    {
      "name": "rpi-release",
      "generator": "Ninja",
      "binaryDir": "${sourceDir}/build/rpi",
      "toolchainFile": "toolchain-arm64-linux.cmake",
      "cacheVariables": { "CMAKE_BUILD_TYPE": "Release" }
    }
  ]
}

8 · Testing with CTest

Enable Tests

enable_testing()
add_test(NAME unit
              COMMAND hello --self-test)

Run ctest -V. Combine with --output-on-failure for detailed logs.

Dashboards & CDash

Submit results: ctest -S dashboard.cmake.

9 · Packaging with CPack

Quick Start

include(CPack)  # after install() commands

set(CPACK_GENERATOR "TGZ;DEB")   # rpm, nsis, dmg, etc.
set(CPACK_PACKAGE_CONTACT "you@example.com")

Generate packages: cpack -G DEB --config ./build/CPackConfig.cmake

10 · Advanced Topics

Custom Commands & Targets

add_custom_command(
  OUTPUT generated.cpp
  COMMAND python codegen.py -o generated.cpp
  DEPENDS codegen.py
)

add_custom_target(generate_sources DEPENDS generated.cpp)

File API & CMake Query

IDE tooling (e.g., VS Code CMake Tools) reads .cmake/api/v1 replies for semantic project data.

Profiling Builds

Enable the new --profile flag (≥ 4.0) to emit JSON timing data.

11 · Migrating to CMake 4.x

Removed OLD Policy Behaviors

CMake 4.0 permanently deletes OLD modes for policies CMP0000–CMP0065. Use cmake_policy(SET CMP0000 NEW) where necessary .

Recommended Steps

  1. Upgrade incrementally: 3.25 → 3.29 → 3.31.7 → 4.0.1.
  2. Run cmake -P cmake_upgrade_test.cmake to scan for deprecated commands.
  3. Remove legacy include_directories()/link_libraries() in favor of target‑scoped variants.

12 · IDE Integration & Tooling

Supported IDEs

Language Servers

cmake‑language‑server provides completion & linting for .cmake files.

13 · Further Reading & Community