13、架构与平台配置:针对不同架构(x86、ARM)和平台(Windows、Linux、macOS)的预设方案
做跨平台开发,最头疼的是什么?我个人觉得,就是不同机器上的构建行为不一致。你在 x86 的 Linux 上编译通过,换到 ARM 的 macOS 上就报错。或者 Windows 上好好的,Linux 上链接失败。
CMake Presets 的架构与平台配置,说白了就是帮你解决这个问题的。它让你能针对不同的 CPU 架构(x86、ARM)和操作系统(Windows、Linux、macOS)分别定义构建方案。这样团队里每个人,不管用什么机器,都能一键构建出正确的东西。
condition 字段,让 Presets 只在特定架构或平台上生效。再配合 vendor 字段,实现更精细的控制。
13.1 基础平台判断:condition 字段
CMake Presets 的 condition 字段,就像一个智能开关。它检查当前机器的属性,只有匹配了,对应的 Preset 才会被加载。
常用的判断条件有这些:
- 操作系统:
condition.type == "os",可以匹配 Windows、Linux、macOS、Android、iOS 等。 - CPU 架构:
condition.type == "architecture",可以匹配 x86、x86_64、ARM、ARM64 等。 - 编译器:
condition.type == "compiler",可以匹配 MSVC、GCC、Clang 等。 - 自定义变量:
condition.type == "variable",可以匹配你自定义的 CMake 变量。
举个例子,我想定义一个只在 Linux x86_64 上生效的 Preset:
{
"version": 6,
"configurePresets": [
{
"name": "linux-x64-release",
"displayName": "Linux x86_64 Release",
"description": "针对 Linux x86_64 的 Release 构建",
"generator": "Ninja",
"binaryDir": "${sourceDir}/build/linux-x64-release",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Release",
"CMAKE_CXX_FLAGS": "-march=x86-64-v3"
},
"condition": {
"type": "os",
"family": "Linux"
}
}
]
}
嗯,这里要注意:condition 可以嵌套使用。比如我想同时判断操作系统和架构,可以用 condition.type == "and" 把多个条件组合起来。
condition,再也没出过这种问题。
13.2 架构与平台组合方案
实际项目中,我们通常需要为不同的架构和平台组合定义不同的 Preset。下面是我常用的几种方案:
| Preset 名称 | 目标平台 | 目标架构 | 生成器 | 关键配置 |
|---|---|---|---|---|
win-x64-debug |
Windows | x86_64 | Visual Studio 17 2022 | CMAKE_BUILD_TYPE=Debug |
linux-arm64-release |
Linux | ARM64 | Ninja | CMAKE_BUILD_TYPE=Release, CMAKE_CXX_FLAGS="-march=armv8-a" |
macos-x64-debug |
macOS | x86_64 | Xcode | CMAKE_BUILD_TYPE=Debug |
macos-arm64-release |
macOS | ARM64 (Apple Silicon) | Ninja | CMAKE_BUILD_TYPE=Release, CMAKE_OSX_ARCHITECTURES=arm64 |
你想想看,如果团队里有人用 Apple Silicon 的 Mac,有人用 Intel 的 Mac,还有人用 Windows 和 Linux。没有 Presets,每个人都要手动配置生成器和架构标志,太容易出错了。
有了 Presets,每个人只需要运行:
# Windows x86_64 用户
cmake --preset win-x64-debug
# macOS ARM64 用户
cmake --preset macos-arm64-release
# Linux ARM64 用户
cmake --preset linux-arm64-release
是不是清爽多了?
13.3 使用 vendor 字段处理平台特定逻辑
有些平台特定的配置,用 condition 还不够。比如 Windows 上需要设置 CMAKE_MSVC_RUNTIME_LIBRARY,macOS 上需要设置 CMAKE_OSX_DEPLOYMENT_TARGET。这些配置如果写在同一个 Preset 里,会互相干扰。
这时候 vendor 字段就派上用场了。vendor 是 CMake Presets 的一个扩展点,不同厂商(比如 IDE、工具链提供商)可以定义自己的字段。CMake 本身会忽略它不认识的内容,但你的工具链可以读取。
举个例子,我想在 Windows 上使用 Visual Studio 的特定工具集:
{
"version": 6,
"configurePresets": [
{
"name": "win-x64-msvc",
"displayName": "Windows x64 MSVC",
"generator": "Visual Studio 17 2022",
"architecture": {
"value": "x64",
"strategy": "set"
},
"vendor": {
"microsoft.com/visualstudio": {
"toolset": "v143",
"platformToolset": "v143"
}
},
"condition": {
"type": "os",
"family": "Windows"
}
}
]
}
在 macOS 上,我可以用 vendor 设置 Xcode 的特定版本:
{
"version": 6,
"configurePresets": [
{
"name": "macos-arm64-xcode",
"displayName": "macOS ARM64 Xcode",
"generator": "Xcode",
"architecture": {
"value": "arm64",
"strategy": "set"
},
"vendor": {
"apple.com/xcode": {
"version": "15.0",
"deploymentTarget": "14.0"
}
},
"condition": {
"type": "os",
"family": "macOS"
}
}
]
}
vendor 字段的内容不是 CMake 标准的一部分。不同工具链的 vendor 格式可能不同。使用前一定要查一下对应工具的文档。我曾经因为用了过时的 vendor 格式,导致 Visual Studio 无法正确加载 Preset,排查了半天。
13.4 架构与平台配置的完整示例
下面是一个完整的 CMakePresets.json 示例,涵盖了常见的架构和平台组合:
{
"version": 6,
"configurePresets": [
{
"name": "default",
"displayName": "默认配置",
"generator": "Ninja",
"binaryDir": "${sourceDir}/build/${presetName}",
"cacheVariables": {
"CMAKE_EXPORT_COMPILE_COMMANDS": "ON"
}
},
{
"name": "win-x64-debug",
"inherits": "default",
"displayName": "Windows x64 Debug",
"generator": "Visual Studio 17 2022",
"architecture": {
"value": "x64",
"strategy": "set"
},
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Debug"
},
"condition": {
"type": "and",
"conditions": [
{ "type": "os", "family": "Windows" },
{ "type": "architecture", "bits": 64 }
]
}
},
{
"name": "linux-arm64-release",
"inherits": "default",
"displayName": "Linux ARM64 Release",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Release",
"CMAKE_CXX_FLAGS": "-march=armv8-a+fp+simd"
},
"condition": {
"type": "and",
"conditions": [
{ "type": "os", "family": "Linux" },
{ "type": "architecture", "bits": 64, "name": "ARM" }
]
}
},
{
"name": "macos-universal",
"inherits": "default",
"displayName": "macOS Universal Binary",
"generator": "Xcode",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Release",
"CMAKE_OSX_ARCHITECTURES": "x86_64;arm64",
"CMAKE_OSX_DEPLOYMENT_TARGET": "11.0"
},
"condition": {
"type": "os",
"family": "macOS"
}
}
],
"buildPresets": [
{
"name": "win-x64-debug",
"configurePreset": "win-x64-debug"
},
{
"name": "linux-arm64-release",
"configurePreset": "linux-arm64-release"
},
{
"name": "macos-universal",
"configurePreset": "macos-universal"
}
]
}
这个示例里,我用了 inherits 来继承默认配置,避免重复。每个 Preset 都通过 condition 精确匹配目标平台和架构。这样不管团队里用什么机器,都能找到合适的 Preset。
13.5 架构与平台配置的核心逻辑
为了让你更直观地理解,我画了一张图:
这张图展示了整个流程:从 CMakePresets.json 出发,经过 condition 判断,自动匹配到对应的操作系统,再进一步匹配 CPU 架构。最终每个开发者只需要运行 cmake --preset <name>,就能得到完全正确的构建配置。
condition 里同时判断架构和操作系统。结果在 x86_64 的 Linux 上也能加载 ARM64 的 Preset,导致编译失败。后来我养成了习惯:每个 Preset 的 condition 一定要同时包含操作系统和架构,除非你明确知道自己在做什么。
好了,关于架构与平台配置,我就讲这么多。记住核心原则:用 condition 做精确匹配,用 vendor 做平台扩展,用 inherits 避免重复。这样你的 Presets 就能在团队里稳定运行,不管大家用什么机器。
公众号:蓝海资料掘金营,微信deep3321