CMake 预设配置
CMake 预设(CMake Presets)是 CMake 3.19 引入的特性,允许你通过 JSON 文件定义项目的配置、构建和测试选项。这使得开发者可以轻松共享构建配置,而无需记忆复杂的命令行参数。
为什么需要预设配置?
传统方式的问题
在没有预设配置之前,开发者需要记忆或记录各种构建命令:
# 配置项目
cmake -B build -G Ninja -DCMAKE_BUILD_TYPE=Debug -DCMAKE_CXX_COMPILER=clang++
# 构建项目
cmake --build build -j4
# 运行测试
cd build && ctest --output-on-failure
这些命令不仅难以记忆,而且在团队协作中难以保持一致性。
预设配置的优势
使用预设配置后,构建变得简单:
# 配置
cmake --preset debug
# 构建
cmake --build --preset debug
# 测试
ctest --preset debug
预设配置的好处:
- 一致性:团队所有成员使用相同的配置
- 可维护性:配置集中管理,易于修改
- IDE 支持:VS Code、Visual Studio、CLion 等都支持读取预设
- 版本控制:
CMakePresets.json可以提交到 Git
CMakePresets.json 结构
基本结构
{
"version": 6,
"cmakeMinimumRequired": {
"major": 3,
"minor": 25,
"patch": 0
},
"configurePresets": [],
"buildPresets": [],
"testPresets": []
}
版本说明
| 版本 | CMake 最低版本 | 新增特性 |
|---|---|---|
| 1 | 3.19 | 基础配置预设 |
| 2 | 3.20 | 构建/测试预设 |
| 3 | 3.21 | 条件预设、工具链文件 |
| 4 | 3.23 | include 引用、包预设 |
| 5 | 3.24 | 流程预设 |
| 6 | 3.25 | 包预设、输出覆盖 |
配置预设(Configure Presets)
基础示例
{
"version": 6,
"cmakeMinimumRequired": {
"major": 3,
"minor": 25
},
"configurePresets": [
{
"name": "default",
"displayName": "Default Config",
"description": "默认配置,使用 Ninja 生成器",
"generator": "Ninja",
"binaryDir": "${sourceDir}/build/${presetName}",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Release"
}
}
]
}
关键字段说明
name(必需)
预设的唯一标识符,用于命令行引用:
cmake --preset default
displayName 和 description
用于在 IDE 和命令行中显示友好信息:
{
"name": "debug",
"displayName": "Debug 配置",
"description": "用于开发调试的配置,包含调试符号"
}
generator
指定构建系统生成器:
{
"generator": "Ninja"
}
常用生成器:
Ninja- 快速的单配置生成器Ninja Multi-Config- 多配置生成器Unix Makefiles- 传统 MakefileVisual Studio 17 2022- VS 2022 项目Xcode- Xcode 项目
binaryDir
指定构建目录:
{
"binaryDir": "${sourceDir}/build/${presetName}"
}
可用变量:
${sourceDir}- 项目根目录${presetName}- 当前预设名称${generator}- 生成器名称
cacheVariables
设置 CMake 缓存变量:
{
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Debug",
"BUILD_TESTS": {
"type": "BOOL",
"value": "ON"
}
}
}
预设继承
使用 inherits 字段复用配置:
{
"configurePresets": [
{
"name": "base",
"hidden": true,
"generator": "Ninja",
"binaryDir": "${sourceDir}/build/${presetName}"
},
{
"name": "debug",
"displayName": "Debug",
"inherits": "base",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Debug"
}
},
{
"name": "release",
"displayName": "Release",
"inherits": "base",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Release"
}
}
]
}
说明:
hidden: true表示该预设不会显示在 IDE 中,仅用于继承- 子预设会继承父预设的所有配置
- 子预设可以覆盖继承的配置
条件预设
根据平台或环境条件性地启用预设:
{
"configurePresets": [
{
"name": "windows-only",
"displayName": "Windows 专用",
"condition": {
"type": "equals",
"lhs": "${hostSystemName}",
"rhs": "Windows"
}
},
{
"name": "linux-debug",
"displayName": "Linux Debug",
"condition": {
"type": "equals",
"lhs": "${hostSystemName}",
"rhs": "Linux"
}
}
]
}
条件类型:
| 类型 | 说明 |
|---|---|
equals | 相等比较 |
notEquals | 不等比较 |
inList | 值在列表中 |
notInList | 值不在列表中 |
matches | 正则匹配 |
notMatches | 正则不匹配 |
anyOf | 任一条件为真 |
allOf | 所有条件为真 |
not | 条件取反 |
环境变量
{
"configurePresets": [
{
"name": "with-env",
"environment": {
"MY_VAR": "custom_value",
"PATH": "$env{HOME}/bin:$penv{PATH}"
}
}
]
}
环境变量语法:
$env{VAR}- 引用预设中定义的环境变量$penv{VAR}- 引用父进程的环境变量${sourceDir}- 项目目录
工具链文件
指定交叉编译工具链:
{
"configurePresets": [
{
"name": "arm-cross",
"displayName": "ARM 交叉编译",
"toolchainFile": "${sourceDir}/toolchains/arm-linux.cmake"
}
]
}
构建预设(Build Presets)
基本结构
{
"buildPresets": [
{
"name": "debug",
"displayName": "Debug 构建",
"configurePreset": "debug",
"configuration": "Debug"
}
]
}
常用字段
{
"buildPresets": [
{
"name": "debug-verbose",
"configurePreset": "debug",
"jobs": 4,
"verbose": true,
"targets": ["myapp", "tests"],
"nativeToolOptions": ["--", "VERBOSE=1"]
}
]
}
字段说明:
configurePreset- 关联的配置预设jobs- 并行任务数(对应-j)verbose- 详细输出targets- 指定构建目标cleanFirst- 构建前清理configuration- 多配置生成器的构建类型
测试预设(Test Presets)
基本结构
{
"testPresets": [
{
"name": "debug",
"displayName": "Debug 测试",
"configurePreset": "debug",
"output": {
"outputOnFailure": true,
"verbosity": "default"
},
"execution": {
"noTestsAction": "error",
"stopOnFailure": false
}
}
]
}
输出配置
{
"output": {
"shortProgress": false,
"verbosity": "default",
"debug": false,
"outputOnFailure": true,
"quiet": false,
"outputLogFile": "test.log",
"outputJUnitFile": "junit.xml"
}
}
执行配置
{
"execution": {
"noTestsAction": "error",
"stopOnFailure": true,
"parallelJobs": 4,
"repeat": {
"mode": "until-pass",
"count": 3
},
"timeout": 300
}
}
筛选配置
{
"testPresets": [
{
"name": "unit-tests",
"configurePreset": "debug",
"filter": {
"include": {
"name": "Unit.*"
},
"exclude": {
"label": "slow"
}
}
}
]
}
完整示例
多配置项目示例
{
"version": 6,
"cmakeMinimumRequired": {
"major": 3,
"minor": 25
},
"configurePresets": [
{
"name": "base",
"hidden": true,
"generator": "Ninja Multi-Config",
"binaryDir": "${sourceDir}/build",
"cacheVariables": {
"CMAKE_CXX_STANDARD": "17",
"BUILD_TESTING": "ON"
}
},
{
"name": "debug",
"displayName": "Debug",
"inherits": "base",
"cacheVariables": {
"ENABLE_DEBUG_SYMBOLS": "ON"
}
},
{
"name": "release",
"displayName": "Release",
"inherits": "base",
"cacheVariables": {
"ENABLE_LTO": "ON"
}
},
{
"name": "release-with-debug",
"displayName": "RelWithDebInfo",
"inherits": "release"
}
],
"buildPresets": [
{
"name": "debug",
"configurePreset": "debug",
"configuration": "Debug"
},
{
"name": "release",
"configurePreset": "release",
"configuration": "Release"
},
{
"name": "release-with-debug",
"configurePreset": "release-with-debug",
"configuration": "RelWithDebInfo"
}
],
"testPresets": [
{
"name": "debug",
"configurePreset": "debug",
"configuration": "Debug",
"output": {
"outputOnFailure": true
}
},
{
"name": "release",
"configurePreset": "release",
"configuration": "Release"
}
]
}
跨平台配置示例
{
"version": 6,
"cmakeMinimumRequired": {
"major": 3,
"minor": 25
},
"configurePresets": [
{
"name": "common",
"hidden": true,
"binaryDir": "${sourceDir}/build/${presetName}",
"cacheVariables": {
"CMAKE_CXX_STANDARD": "17",
"BUILD_TESTING": "ON"
}
},
{
"name": "windows-base",
"hidden": true,
"inherits": "common",
"condition": {
"type": "equals",
"lhs": "${hostSystemName}",
"rhs": "Windows"
},
"generator": "Visual Studio 17 2022"
},
{
"name": "unix-base",
"hidden": true,
"inherits": "common",
"condition": {
"type": "notEquals",
"lhs": "${hostSystemName}",
"rhs": "Windows"
},
"generator": "Ninja"
},
{
"name": "debug",
"displayName": "Debug",
"inherits": ["windows-base", "unix-base"],
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Debug"
}
},
{
"name": "release",
"displayName": "Release",
"inherits": ["windows-base", "unix-base"],
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Release"
}
}
]
}
带依赖下载的配置
{
"version": 6,
"configurePresets": [
{
"name": "with-deps",
"displayName": "With Dependencies",
"generator": "Ninja",
"binaryDir": "${sourceDir}/build",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Release",
"FETCHCONTENT_FULLY_DISCONNECTED": "OFF"
}
}
]
}
CMakeUserPresets.json
CMakeUserPresets.json 用于本地开发者的个人配置,不应提交到版本控制:
{
"version": 6,
"configurePresets": [
{
"name": "local-dev",
"inherits": "debug",
"cacheVariables": {
"MY_LOCAL_PATH": "/home/user/local"
}
}
]
}
使用规则:
CMakeUserPresets.json自动继承CMakePresets.json- 不要将
CMakeUserPresets.json提交到 Git - 在
.gitignore中添加CMakeUserPresets.json
命令行使用
列出预设
# 列出所有配置预设
cmake --list-presets
# 列出构建预设
cmake build --list-presets
# 列出测试预设
ctest --list-presets
使用预设
# 配置
cmake --preset debug
# 构建
cmake --build --preset debug
# 测试
ctest --preset debug
# 清理构建
cmake --build --preset debug --target clean
覆盖选项
# 覆盖缓存变量
cmake --preset debug -DMY_VAR=custom
# 指定其他源目录
cmake --preset debug -S /path/to/source
IDE 集成
VS Code
安装 CMake Tools 扩展后,VS Code 会自动读取预设:
- 打开命令面板(
Ctrl+Shift+P) - 输入 "CMake: Select Configure Preset"
- 从列表中选择预设
Visual Studio
Visual Studio 2019 及以上版本支持预设:
- 打开
文件 > 打开 > CMake - 选择
CMakeLists.txt - IDE 自动读取
CMakePresets.json
CLion
CLion 2021.3 及以上版本支持:
- 打开
Settings > Build > CMake - 启用 "Use CMake Presets"
- 预设会自动显示在配置列表中
最佳实践
1. 使用隐藏基础预设
{
"configurePresets": [
{
"name": "base",
"hidden": true,
"generator": "Ninja",
"binaryDir": "${sourceDir}/build/${presetName}"
},
{
"name": "debug",
"inherits": "base",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Debug"
}
}
]
}
2. 按功能分组命名
{
"configurePresets": [
{ "name": "linux-debug" },
{ "name": "linux-release" },
{ "name": "windows-debug" },
{ "name": "windows-release" },
{ "name": "arm-cross-debug" }
]
}
3. 添加清晰的描述
{
"name": "asan",
"displayName": "Address Sanitizer",
"description": "用于检测内存错误的配置,启用 AddressSanitizer",
"cacheVariables": {
"CMAKE_CXX_FLAGS": "-fsanitize=address -fno-omit-frame-pointer"
}
}
4. 使用 include 分离配置
对于大型项目,可以将配置拆分到多个文件:
CMakePresets.json:
{
"version": 6,
"include": [
"presets/common.json",
"presets/linux.json",
"presets/windows.json"
]
}
常见问题
问题 1:预设不被识别
检查:
- JSON 语法是否正确
version字段是否符合 CMake 版本- 文件是否在项目根目录
问题 2:IDE 不显示预设
确保:
- IDE 版本支持预设功能
hidden字段不是truecondition条件满足
问题 3:缓存变量不生效
缓存变量在首次配置后会被缓存,需要清理构建目录或强制更新:
rm -rf build
cmake --preset debug
小结
本章我们学习了:
- 预设配置的优势:一致性、可维护性、IDE 支持
- 配置预设:generator、binaryDir、cacheVariables、inherits
- 构建预设:关联配置预设、并行构建、目标指定
- 测试预设:输出配置、执行配置、测试筛选
- 跨平台配置:条件预设、多继承
- IDE 集成:VS Code、Visual Studio、CLion
预设配置是现代 CMake 项目的推荐配置方式,它简化了构建流程并提高了团队协作效率。
练习
- 创建一个包含 Debug、Release、RelWithDebInfo 三种配置的预设文件
- 配置跨平台的预设,Windows 使用 Visual Studio,Linux/macOS 使用 Ninja
- 为项目添加测试预设,配置失败时输出详细信息