Presets Overview
CMake Presets (introduced in CMake 3.19, extended through 3.25+) provide a JSON-based way to specify common configure, build, and test options. Instead of remembering long command lines, you define named presets that anyone on your team can use identically.
JSON Format
The presets file uses a versioned JSON schema:
# CMakePresets.json — committed to version control
{
"version": 6,
"cmakeMinimumRequired": {
"major": 3,
"minor": 25,
"patch": 0
},
"configurePresets": [...],
"buildPresets": [...],
"testPresets": [...],
"workflowPresets": [...]
}
File Structure
| File | Purpose | Version Control |
|---|---|---|
CMakePresets.json | Project-wide presets (shared by team) | Yes — commit |
CMakeUserPresets.json | Personal developer overrides | No — .gitignore |
flowchart TD
A[CMakePresets.json] --> B[base-config]
B --> C[debug-config]
B --> D[release-config]
B --> E[ci-config]
C --> F[debug-build]
D --> G[release-build]
E --> H[ci-build]
F --> I[debug-test]
G --> J[release-test]
H --> K[ci-test]
L[CMakeUserPresets.json] --> M[my-local-config]
M -->|inherits| B
Configure Presets
Configure presets define how cmake -S . -B build runs — the generator, cache variables, environment, and toolchain:
Generators and Cache Variables
{
"version": 6,
"configurePresets": [
{
"name": "base",
"hidden": true,
"binaryDir": "${sourceDir}/build/${presetName}",
"cacheVariables": {
"CMAKE_EXPORT_COMPILE_COMMANDS": "ON",
"BUILD_TESTING": "ON"
}
},
{
"name": "linux-debug",
"inherits": "base",
"displayName": "Linux Debug",
"description": "Debug build with GCC on Linux",
"generator": "Ninja",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Debug",
"CMAKE_C_COMPILER": "gcc",
"CMAKE_CXX_COMPILER": "g++",
"ENABLE_SANITIZERS": "ON"
},
"environment": {
"CXXFLAGS": "-fdiagnostics-color=always"
}
},
{
"name": "linux-release",
"inherits": "base",
"displayName": "Linux Release",
"generator": "Ninja",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Release",
"CMAKE_C_COMPILER": "gcc",
"CMAKE_CXX_COMPILER": "g++",
"CMAKE_INTERPROCEDURAL_OPTIMIZATION": "ON"
}
},
{
"name": "windows-msvc",
"inherits": "base",
"displayName": "Windows MSVC",
"generator": "Visual Studio 17 2022",
"architecture": {
"value": "x64",
"strategy": "set"
},
"cacheVariables": {
"CMAKE_INSTALL_PREFIX": "${sourceDir}/install"
}
}
]
}
# List available presets
cmake --list-presets
# Configure using a preset
cmake --preset linux-debug
# Equivalent to:
# cmake -S . -B build/linux-debug -G Ninja \
# -DCMAKE_BUILD_TYPE=Debug -DCMAKE_C_COMPILER=gcc ...
Toolchain File Integration
{
"name": "arm-cross",
"inherits": "base",
"displayName": "ARM Cross-Compilation",
"toolchainFile": "${sourceDir}/cmake/toolchains/arm-none-eabi.cmake",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "MinSizeRel"
}
}
Inheritance
Presets support single and multiple inheritance to avoid duplication:
{
"name": "ci-linux-release",
"inherits": ["linux-release", "ci-base"],
"displayName": "CI Linux Release",
"cacheVariables": {
"BUILD_DOCS": "ON",
"ENABLE_COVERAGE": "OFF"
}
}
Multi-Platform Presets
Create a CMakePresets.json that supports both Debug and Release on Linux with Ninja:
# Create the presets file at project root
cat > CMakePresets.json << 'EOF'
{
"version": 6,
"configurePresets": [
{
"name": "dev",
"displayName": "Development",
"generator": "Ninja",
"binaryDir": "${sourceDir}/build/dev",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Debug",
"CMAKE_EXPORT_COMPILE_COMMANDS": "ON"
}
},
{
"name": "release",
"displayName": "Release",
"generator": "Ninja",
"binaryDir": "${sourceDir}/build/release",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Release"
}
}
],
"buildPresets": [
{"name": "dev", "configurePreset": "dev"},
{"name": "release", "configurePreset": "release"}
]
}
EOF
# Use it
cmake --preset dev
cmake --build --preset dev
Build Presets
Build presets define how cmake --build executes — targets, parallelism, and configuration:
"buildPresets": [
{
"name": "linux-debug-build",
"configurePreset": "linux-debug",
"jobs": 8,
"targets": ["all"],
"verbose": false
},
{
"name": "linux-release-build",
"configurePreset": "linux-release",
"jobs": 0,
"configuration": "Release",
"cleanFirst": false
},
{
"name": "docs-only",
"configurePreset": "linux-debug",
"targets": ["docs"],
"inherits": "linux-debug-build"
}
]
# Build using preset
cmake --build --preset linux-debug-build
# List build presets
cmake --build --list-presets
Test Presets
Test presets configure ctest execution:
"testPresets": [
{
"name": "linux-debug-test",
"configurePreset": "linux-debug",
"output": {
"outputOnFailure": true,
"verbosity": "default"
},
"execution": {
"jobs": 8,
"timeout": 300,
"stopOnFailure": false
}
},
{
"name": "unit-tests-only",
"configurePreset": "linux-debug",
"filter": {
"include": {
"label": "unit"
},
"exclude": {
"label": "integration|slow"
}
}
},
{
"name": "ci-test",
"configurePreset": "ci-linux-release",
"output": {
"outputOnFailure": true,
"outputJUnitFile": "test-results.xml"
},
"execution": {
"jobs": 4,
"repeatMode": "until-pass",
"repeatCount": 3
}
}
]
# Run tests using preset
ctest --preset linux-debug-test
# Run only unit tests
ctest --preset unit-tests-only
Workflow Presets
Workflow presets (CMake 3.25+) chain configure → build → test into a single command:
"workflowPresets": [
{
"name": "full-ci",
"displayName": "Full CI Pipeline",
"steps": [
{"type": "configure", "name": "ci-linux-release"},
{"type": "build", "name": "linux-release-build"},
{"type": "test", "name": "ci-test"}
]
},
{
"name": "dev-cycle",
"displayName": "Developer Build + Test",
"steps": [
{"type": "configure", "name": "linux-debug"},
{"type": "build", "name": "linux-debug-build"},
{"type": "test", "name": "unit-tests-only"}
]
}
]
# Execute entire workflow
cmake --workflow --preset full-ci
# Developer quick cycle
cmake --workflow --preset dev-cycle
cmake --version and update if needed.
CMakeUserPresets.json
Personal presets that shouldn't be committed (add to .gitignore):
# CMakeUserPresets.json — NOT committed to git
{
"version": 6,
"configurePresets": [
{
"name": "my-debug",
"inherits": "linux-debug",
"displayName": "My Local Debug",
"cacheVariables": {
"CMAKE_C_COMPILER": "/opt/gcc-14/bin/gcc",
"CMAKE_CXX_COMPILER": "/opt/gcc-14/bin/g++",
"VCPKG_ROOT": "/home/dev/vcpkg"
},
"environment": {
"CC": "/opt/gcc-14/bin/gcc",
"CXX": "/opt/gcc-14/bin/g++"
}
}
]
}
# .gitignore entry
CMakeUserPresets.json
Complete CI Workflow Preset
Set up a workflow that mirrors your CI pipeline locally:
# Run the full CI pipeline locally
cmake --workflow --preset full-ci
# Output:
# -- Configuring preset 'ci-linux-release'...
# -- Building preset 'linux-release-build'...
# -- Testing preset 'ci-test'...
# 100% tests passed, 0 tests failed out of 47
This eliminates "works on my machine" problems — the same presets run in CI and locally.
Macros & Conditions
Presets support macro expansion and conditional expressions for dynamic configuration:
{
"name": "platform-aware",
"binaryDir": "${sourceDir}/build/${presetName}",
"cacheVariables": {
"CMAKE_INSTALL_PREFIX": "$env{HOME}/opt/myapp",
"PROJECT_DATA_DIR": "${sourceDir}/data"
},
"environment": {
"PATH": "$penv{PATH}:${sourceDir}/tools"
},
"condition": {
"type": "equals",
"lhs": "${hostSystemName}",
"rhs": "Linux"
}
}
Available macros:
| Macro | Expands To |
|---|---|
${sourceDir} | Path to source directory |
${sourceParentDir} | Parent of source directory |
${presetName} | Name of the current preset |
${generator} | Generator name |
${hostSystemName} | Host OS (Linux, Windows, Darwin) |
$env{VAR} | Environment variable value |
$penv{VAR} | Parent environment (for prepending) |
$vendor{key} | Vendor-specific macro |
flowchart LR
A[CMakePresets.json] --> B[VS Code CMake Tools]
A --> C[CLion]
A --> D[Visual Studio 2022]
A --> E[Qt Creator]
B --> F[Kit Selection = Preset]
C --> G[Profiles from Presets]
D --> H[CMake Settings]
E --> I[Build Configuration]
F --> J[cmake --preset dev]
G --> J
H --> J
I --> J
Platform-Specific Preset with Conditions
{
"name": "macos-arm",
"inherits": "base",
"displayName": "macOS ARM64",
"generator": "Ninja",
"condition": {
"type": "allOf",
"conditions": [
{"type": "equals", "lhs": "${hostSystemName}", "rhs": "Darwin"},
{"type": "matches", "string": "$env{PROCESSOR_ARCHITECTURE}", "regex": "arm64|aarch64"}
]
},
"cacheVariables": {
"CMAKE_OSX_ARCHITECTURES": "arm64",
"CMAKE_BUILD_TYPE": "Release"
}
}
This preset only appears in cmake --list-presets when running on macOS ARM64 hardware.
Conclusion & Next Steps
CMake Presets eliminate configuration drift and make builds reproducible across machines and CI systems. Key takeaways:
CMakePresets.jsongoes in version control;CMakeUserPresets.jsonstays local- Use
inheritsto compose presets and avoid duplication - Workflow presets chain configure → build → test into one command
- All major IDEs natively read CMakePresets.json for kit/profile selection
- Conditions gate presets to specific platforms or environments