15、预设的可见性与作用域:hidden 预设与公开预设的设计模式

聊到 CMake Presets 的可见性,说白了就是「谁能看到谁」。你想想看,一个项目里,有些预设是给所有人用的,比如 debugrelease 这种通用配置。但有些预设,可能只是你本地调试用的,或者某个 CI 流水线的专属配置,你并不想让团队里每个人都看到。

CMake 提供了 hidden 这个布尔字段,专门解决这个问题。我个人习惯是:默认公开,按需隐藏。别一上来就把所有预设都藏起来,那样反而会增加团队协作的沟通成本。

15.1 hidden 预设:藏起来的「私房配置」

先看一个最简单的例子。假设你有一个 configurePresets,里面有个 my-local-debug,只在你自己的开发机上用:

{
  "version": 6,
  "configurePresets": [
    {
      "name": "my-local-debug",
      "hidden": true,
      "displayName": "我的本地调试配置",
      "description": "仅供个人使用,包含本地路径硬编码",
      "generator": "Ninja",
      "binaryDir": "${sourceDir}/build/debug-local",
      "cacheVariables": {
        "CMAKE_BUILD_TYPE": "Debug",
        "MY_LOCAL_PATH": "/home/me/special-libs"
      }
    }
  ]
}

嗯,这里要注意:hidden 设为 true 后,这个预设不会出现在 cmake --list-presets 的输出里。但如果你知道它的名字,仍然可以显式使用:

cmake --preset my-local-debug

我在项目中遇到过这样的情况:有个同事把本地路径硬编码写进了公开预设,结果 CI 机器上编译直接报错。后来我们规定:所有包含绝对路径、本地环境变量、或者临时测试开关的预设,一律设为 hidden。这个规则帮我们省了不少排查时间。

15.2 公开预设:团队共享的「标准配置」

公开预设就是 hidden 字段不写,或者显式设为 false。这类预设是团队协作的基础,通常放在项目根目录的 CMakePresets.json 里。

举个例子,一个典型的公开预设设计:

{
  "version": 6,
  "configurePresets": [
    {
      "name": "default",
      "hidden": false,
      "displayName": "默认 Debug 构建",
      "description": "团队标准调试配置,所有开发者通用",
      "generator": "Ninja",
      "binaryDir": "${sourceDir}/build/default",
      "cacheVariables": {
        "CMAKE_BUILD_TYPE": "Debug",
        "CMAKE_CXX_STANDARD": "17"
      }
    },
    {
      "name": "release",
      "hidden": false,
      "displayName": "Release 构建",
      "description": "优化版本,用于性能测试和发布",
      "generator": "Ninja",
      "binaryDir": "${sourceDir}/build/release",
      "cacheVariables": {
        "CMAKE_BUILD_TYPE": "Release",
        "CMAKE_INTERPROCEDURAL_OPTIMIZATION": "ON"
      }
    }
  ]
}

公开预设的设计原则,我个人总结了三句话:

  • 可移植:不要依赖任何本地路径或环境变量
  • 可复现:同一份代码、同一个预设,在任何机器上行为一致
  • 可理解displayNamedescription 写清楚,别让队友猜

15.3 设计模式:分层可见性

在实际项目中,我通常把预设分成三层。这张图可以帮你快速理解:

预设可见性分层设计模式 公开预设(hidden: false) 团队标准配置:debug、release、asan、coverage 半公开预设(hidden: true + 文档说明) CI 专用配置、特定平台调优、临时测试分支 私有预设(hidden: true + 本地 CMakeUserPresets.json) 个人调试配置、本地路径硬编码、实验性开关 可见性递减 隐私性递增

这张图展示了我最常用的分层策略。从上到下,可见性递减,隐私性递增。每一层都有明确的用途和边界。

15.4 实战:用 hidden 预设做「预设继承」

你想想看,hidden 预设还有一个很妙的用法——作为「基类」预设。我在项目中经常这样用:

{
  "version": 6,
  "configurePresets": [
    {
      "name": "base",
      "hidden": true,
      "description": "基础配置,所有预设继承自此",
      "generator": "Ninja",
      "cacheVariables": {
        "CMAKE_CXX_STANDARD": "17",
        "CMAKE_CXX_EXTENSIONS": "OFF"
      }
    },
    {
      "name": "debug",
      "hidden": false,
      "inherits": "base",
      "cacheVariables": {
        "CMAKE_BUILD_TYPE": "Debug",
        "CMAKE_CXX_FLAGS": "-g -O0"
      }
    },
    {
      "name": "release",
      "hidden": false,
      "inherits": "base",
      "cacheVariables": {
        "CMAKE_BUILD_TYPE": "Release",
        "CMAKE_CXX_FLAGS": "-O3 -DNDEBUG"
      }
    }
  ]
}

这里 base 预设是 hidden 的,它只作为模板存在。团队里没人会直接使用 base,但 debugrelease 都从它继承公共配置。这样做的好处是:公共配置只写一次,后续维护只需要改 base 一处

我的小技巧:base 预设的 displayName 写成「基础模板(请勿直接使用)」,这样即使有人误操作,也能从名字上得到提示。

15.5 避坑指南:hidden 预设的常见误区

我曾经踩过一个坑:把 hidden 预设当作「安全机制」,以为别人看不到就用不了。其实不是的——hidden 只是不在列表里显示,但只要你知道了名字,照样可以 cmake --preset xxx 调用。

所以,不要把敏感信息(比如密码、Token)放在任何预设里,哪怕是 hidden 的。敏感信息应该通过环境变量或外部文件注入。

另外还有一个常见的误解:hidden 预设不能作为 inherits 的目标。其实完全没问题,CMake 允许从 hidden 预设继承,这也是我上面那个「基类模式」能跑通的原因。

注意: hidden 预设仍然会被 cmake --preset 执行,只是不会出现在 --list-presets 的输出中。如果你希望某个预设完全不可用,应该从配置文件中删除它,而不是仅仅设为 hidden

15.6 团队协作中的可见性约定

最后,分享一个我们团队的实际约定。我们用一张表格来规范预设的可见性:

预设类型 hidden 值 存放位置 示例
团队标准配置 false CMakePresets.json debug, release, asan
CI 专用配置 true CMakePresets.json ci-linux, ci-macos
平台调优配置 true CMakePresets.json opt-avx2, opt-neon
个人调试配置 true CMakeUserPresets.json my-local, test-experiment

这个表格贴在项目的 CONTRIBUTING.md 里,新成员一看就明白。我个人觉得,好的约定比好的工具更重要。CMake Presets 给了你 hidden 这个开关,但怎么用、用在哪,还是得靠团队自己定规矩。

核心总结:

  • hidden: true 让预设不出现在列表里,但名字已知仍可使用
  • 公开预设用于团队共享,必须可移植、可复现、可理解
  • 利用 hidden 预设做「基类模板」,减少重复配置
  • 敏感信息永远不要放进预设文件,无论是否 hidden
  • 团队层面建立可见性约定,比单纯依赖技术手段更可靠

嗯,关于预设的可见性与作用域,就聊这么多。说白了,hidden 是个很轻量的设计,但用好了能让你的预设体系既灵活又整洁。下次你在项目里看到一堆乱七八糟的预设时,不妨试试这个分层思路。


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