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" 把多个条件组合起来。

我的经验: 我曾经在团队里见过有人把 Windows 和 Linux 的 Preset 写在一起,结果 Windows 上加载了 Linux 的配置,导致生成器不匹配。后来我强制要求每个 Preset 都加上 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 架构 | 编译器 | 自定义变量 Windows Visual Studio / Ninja Linux Ninja / Makefile macOS Xcode / Ninja x86 / x86_64 x86_64 / ARM64 x86_64 / ARM64 通过 condition 精确匹配 → 自动选择正确的 Preset

这张图展示了整个流程:从 CMakePresets.json 出发,经过 condition 判断,自动匹配到对应的操作系统,再进一步匹配 CPU 架构。最终每个开发者只需要运行 cmake --preset <name>,就能得到完全正确的构建配置。

避坑指南: 我曾经在配置 ARM64 交叉编译时,忘记在 condition 里同时判断架构和操作系统。结果在 x86_64 的 Linux 上也能加载 ARM64 的 Preset,导致编译失败。后来我养成了习惯:每个 Preset 的 condition 一定要同时包含操作系统和架构,除非你明确知道自己在做什么。

好了,关于架构与平台配置,我就讲这么多。记住核心原则:用 condition 做精确匹配,用 vendor 做平台扩展,用 inherits 避免重复。这样你的 Presets 就能在团队里稳定运行,不管大家用什么机器。


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