14、多配置生成器:处理 Visual Studio、Xcode 等多配置生成器的 Presets 配置
说实话,我第一次接触多配置生成器时,也被绕晕过。
那时候我刚从 Linux 转到 Windows 上做开发,习惯性地写了套 CMakeLists.txt,然后敲了个 cmake -B build。结果生成出来的 Visual Studio 解决方案里,Debug 和 Release 配置混在一起,我愣是没找到怎么单独编译某个版本。后来才明白——嗯,这就是单配置生成器和多配置生成器的区别。
今天我们就来聊聊,在 CMake Presets 里怎么优雅地处理 Visual Studio、Xcode 这类多配置生成器。
什么是多配置生成器?
说白了,多配置生成器就是一次生成,多个配置都能用。你跑一遍 CMake,生成出来的工程文件里同时包含了 Debug、Release、RelWithDebInfo、MinSizeRel 等配置。你可以在 IDE 里随时切换,不用重新运行 CMake。
常见的多配置生成器有:
- Visual Studio(所有版本)
- Xcode
- Ninja Multi-Config(CMake 3.17+ 引入)
与之相对的,是 Unix Makefiles、Ninja 这类单配置生成器。它们一次只生成一个配置,想换配置就得重新跑一遍 CMake。
核心区别一句话:多配置生成器把「配置选择」推迟到了构建阶段,而单配置生成器在配置阶段就定死了。
Presets 中如何指定多配置?
在 CMakePresets.json 里,我们通过 generator 字段指定生成器,通过 architecture 和 toolset 字段控制平台和工具集。但多配置生成器有个特殊之处——CMAKE_BUILD_TYPE 这个变量在配置阶段是不生效的。
我个人的习惯是,在 configurePresets 里只定义生成器和架构,把构建类型留给 buildPresets 去处理。这样逻辑更清晰。
来看一个实际例子:
{
"version": 6,
"configurePresets": [
{
"name": "vs2022-x64",
"displayName": "Visual Studio 2022 (x64)",
"generator": "Visual Studio 17 2022",
"architecture": "x64",
"toolset": "v143",
"binaryDir": "${sourceDir}/build/${presetName}",
"cacheVariables": {
"CMAKE_CONFIGURATION_TYPES": "Debug;Release;RelWithDebInfo"
}
},
{
"name": "xcode-macos",
"displayName": "Xcode (macOS)",
"generator": "Xcode",
"binaryDir": "${sourceDir}/build/${presetName}",
"cacheVariables": {
"CMAKE_CONFIGURATION_TYPES": "Debug;Release"
}
},
{
"name": "ninja-multi",
"displayName": "Ninja Multi-Config",
"generator": "Ninja Multi-Config",
"binaryDir": "${sourceDir}/build/${presetName}",
"cacheVariables": {
"CMAKE_CONFIGURATION_TYPES": "Debug;Release;RelWithDebInfo;MinSizeRel"
}
}
]
}
注意看,这里我显式设置了 CMAKE_CONFIGURATION_TYPES。如果不设,CMake 会使用默认值(Debug;Release;RelWithDebInfo;MinSizeRel)。我个人建议还是显式写出来,团队协作时一目了然。
buildPresets 中的配置选择
配置阶段搞定了,构建阶段怎么选配置呢?在 buildPresets 里用 configuration 字段:
{
"buildPresets": [
{
"name": "vs2022-debug",
"displayName": "VS 2022 Debug",
"configurePreset": "vs2022-x64",
"configuration": "Debug"
},
{
"name": "vs2022-release",
"displayName": "VS 2022 Release",
"configurePreset": "vs2022-x64",
"configuration": "Release"
},
{
"name": "xcode-debug",
"displayName": "Xcode Debug",
"configurePreset": "xcode-macos",
"configuration": "Debug"
},
{
"name": "ninja-release",
"displayName": "Ninja Multi Release",
"configurePreset": "ninja-multi",
"configuration": "Release"
}
]
}
这样,你只需要跑一次 cmake --preset vs2022-x64,然后就可以用 cmake --build --preset vs2022-debug 和 cmake --build --preset vs2022-release 分别构建不同版本,不用重新配置。
小技巧:如果你用 Visual Studio 打开生成的 .sln 文件,可以在解决方案配置下拉框里直接切换。Xcode 也一样,在 scheme 里选。这就是多配置生成器的便利之处。
我曾经踩过的坑
讲几个我实际遇到过的问题,希望能帮你避开:
- 坑一:在 configurePresets 里设置了
CMAKE_BUILD_TYPE。对于多配置生成器,这个变量会被忽略,但不会报错。我花了半天排查为什么 Debug 和 Release 的编译选项都一样——原来CMAKE_BUILD_TYPE根本没起作用。 - 坑二:忘记设置
CMAKE_CONFIGURATION_TYPES。默认值虽然够用,但如果你项目里自定义了配置(比如 Profile、Sanitize),不显式声明的话,CMake 不会帮你生成这些配置的工程文件。 - 坑三:architecture 和 toolset 写错。Visual Studio 的架构名是
x64、Win32、ARM64,不是x86_64或amd64。写错了 CMake 不会报错,但生成出来的工程可能无法编译。
特别注意:Ninja Multi-Config 生成器虽然也是多配置,但它不像 Visual Studio 那样有 IDE 界面。你仍然需要在命令行里通过 --config 参数指定配置。别以为用了 Ninja Multi-Config 就能在 Visual Studio 里切换配置——它们不是一回事。
多配置生成器的知识体系
下面这张图梳理了多配置生成器的核心逻辑,我建议你保存下来,以后配置 Presets 时对照着看:
跨平台团队的最佳实践
如果你的团队同时使用 Windows、macOS 和 Linux,我建议这样组织 Presets:
- 按平台分 preset:每个平台一个 configurePreset,比如
vs2022-x64、xcode-macos、ninja-linux。 - 按配置分 buildPreset:每个平台下再细分 Debug 和 Release 的 buildPreset。
- 统一命名规范:比如
<平台>-<架构>-<配置>,这样一看名字就知道是干什么的。 - 共享 common 配置:用
inherits字段提取公共部分,减少重复。
举个例子,Windows 和 macOS 共享同一个编译选项:
{
"configurePresets": [
{
"name": "common-multi",
"hidden": true,
"cacheVariables": {
"CMAKE_CONFIGURATION_TYPES": "Debug;Release",
"CMAKE_CXX_STANDARD": "17"
}
},
{
"name": "vs2022-x64",
"inherits": "common-multi",
"generator": "Visual Studio 17 2022",
"architecture": "x64"
},
{
"name": "xcode-macos",
"inherits": "common-multi",
"generator": "Xcode"
}
]
}
这样改一处 common-multi,所有平台都同步更新。我在团队里推行这个模式后,再也没人抱怨「为什么 Windows 能编译 macOS 不行」了——因为配置本来就是统一的。
总结一下:多配置生成器的 Presets 配置,核心就三点——配置阶段选对生成器,构建阶段选对配置,别忘了显式声明 CMAKE_CONFIGURATION_TYPES。把这三点记住,你就能在 Visual Studio、Xcode 和 Ninja Multi-Config 之间游刃有余。
好了,这一章的内容就到这里。多配置生成器其实没那么复杂,关键是要理解它和单配置生成器的本质区别。下次你在 IDE 里切换 Debug/Release 时,可以想想背后 CMake Presets 是怎么帮你省掉那一次重新配置的时间的。