Using CMake Presets to Standardize Cross‑Platform Builds
Learn how CMake Presets let teams share configure and build options across platforms, reducing onboarding friction and improving reproducibility.
01 Oct 2025, 08:34 UTC

The problem: divergent configure steps
When multiple developers work on a C++ project, each may invoke cmake with different flags, toolchain paths or manual dependency steps. This leads to builds that are not reproducible, longer onboarding times and occasional "it works on my machine" issues.
Thesis: CMake Presets give a declarative, version‑controlled way to share configure and build options
By storing preset definitions in a JSON file (CMakePresets.json) next to the source, teams can define named configure and build presets that capture generators, toolchain files, cache variables and even FetchContent declarations. Invoking a preset with cmake --preset <name> applies exactly those settings, eliminating ad‑hoc command‑line variations.
Worked example: two platform‑specific presets with FetchContent
Consider a minimal project:
# CMakeLists.txt
cmake_minimum_required(VERSION 3.20)
project(Demo LANGUAGES CXX)
# Fetch an external library hermetically
include(FetchContent)
FetchContent_Declare(
fmt
GIT_REPOSITORY https://github.com/fmtlib/fmt.git
GIT_TAG 9.1.0
)
FetchContent_MakeAvailable(fmt)
add_executable(app main.cpp)
target_link_libraries(app PRIVATE fmt::fmt)
Now create a presets file that defines two configure presets, one for Linux with Clang and one for Windows with MSVC, and a build preset that reuses the configure step:
{
"version": 3,
"configurePresets": [
{
"name": "linux-clang-debug",
"displayName": "Linux Clang Debug",
"description": "Debug build using Clang on Linux",
"generator": "Ninja",
"toolchainFile": "${CMAKE_SOURCE_DIR}/toolchains/linux-clang.cmake",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "DEBUG",
"CMAKE_CXX_STANDARD": 17
}
},
{
"name": "windows-msvc-release",
"displayName": "Windows MSVC Release",
"description": "Release build using MSVC on Windows",
"generator": "Visual Studio 17 2022",
"toolchainFile": "${CMAKE_SOURCE_DIR}/toolchains/windows-msvc.cmake",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "RELEASE",
"CMAKE_CXX_STANDARD": 17
}
}
],
"buildPresets": [
{
"name": "linux-clang-debug",
"configurePreset": "linux-clang-debug"
},
{
"name": "windows-msvc-release",
"configurePreset": "windows-msvc-release"
}
]
}
To use a preset, run:
cmake --list-presets– you should see the two configure and two build presets listed.cmake --preset linux-clang-debug– this configures the project using the Linux Clang preset.- Inspect
CMakeCache.txtfor entries likeCMAKE_BUILD_TYPE:STRING=DEBUGand the path to the toolchain file. cmake --build --preset linux-clang-debug– builds with Ninja using the configured settings.
The same workflow works on Windows by substituting the preset name windows-msvc-release.
Trade‑offs and limitations
- Version sensitivity – the preset schema evolves; teams should document a minimum CMake version (e.g., 3.20) and test presets when upgrading.
- Discoverability – options live in JSON, which may be less obvious than scanning
CMakeLists.txt. Adding a comment in the top‑level CMake file that points toCMakePresets.jsonhelps. - Configure time – using
FetchContent inside presets means dependencies are downloaded at configure time, which can increase latency and expose network failures. Consider caching or using external package managers for large dependencies.
Actionable closing
Start by adding a CMakePresets.json with a single configure preset that matches your current developer workflow. Commit the file, update the project README to mention cmake --list-presets and cmake --preset <name>, and encourage teammates to adopt it. Over time, add more presets for different build types or platforms, and pair them with FetchContent to keep external dependencies hermetic. This small step yields reproducible builds and smoother onboarding across the team.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.