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 字段指定生成器,通过 architecturetoolset 字段控制平台和工具集。但多配置生成器有个特殊之处——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-debugcmake --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 的架构名是 x64Win32ARM64,不是 x86_64amd64。写错了 CMake 不会报错,但生成出来的工程可能无法编译。

特别注意:Ninja Multi-Config 生成器虽然也是多配置,但它不像 Visual Studio 那样有 IDE 界面。你仍然需要在命令行里通过 --config 参数指定配置。别以为用了 Ninja Multi-Config 就能在 Visual Studio 里切换配置——它们不是一回事。

多配置生成器的知识体系

下面这张图梳理了多配置生成器的核心逻辑,我建议你保存下来,以后配置 Presets 时对照着看:

多配置生成器 Presets 配置流程 配置阶段 cmake --preset <name> 选择多配置生成器 Visual Studio / Xcode / Ninja Multi 生成工程文件 .sln / .xcodeproj 构建阶段 cmake --build --preset <name> 选择构建配置 configuration: "Debug" / "Release" 编译输出 .exe / .dylib / .app 关键配置项 • generator: 指定多配置生成器名称 • CMAKE_CONFIGURATION_TYPES: 声明支持的配置列表 • architecture: 目标平台架构 • configuration: 构建时选择的配置

跨平台团队的最佳实践

如果你的团队同时使用 Windows、macOS 和 Linux,我建议这样组织 Presets:

  1. 按平台分 preset:每个平台一个 configurePreset,比如 vs2022-x64xcode-macosninja-linux
  2. 按配置分 buildPreset:每个平台下再细分 Debug 和 Release 的 buildPreset。
  3. 统一命名规范:比如 <平台>-<架构>-<配置>,这样一看名字就知道是干什么的。
  4. 共享 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 是怎么帮你省掉那一次重新配置的时间的。


公众号:蓝海资料掘金营,微信deep3321