15、预设的可见性与作用域:hidden 预设与公开预设的设计模式
聊到 CMake Presets 的可见性,说白了就是「谁能看到谁」。你想想看,一个项目里,有些预设是给所有人用的,比如 debug、release 这种通用配置。但有些预设,可能只是你本地调试用的,或者某个 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"
}
}
]
}
公开预设的设计原则,我个人总结了三句话:
- 可移植:不要依赖任何本地路径或环境变量
- 可复现:同一份代码、同一个预设,在任何机器上行为一致
- 可理解:
displayName和description写清楚,别让队友猜
15.3 设计模式:分层可见性
在实际项目中,我通常把预设分成三层。这张图可以帮你快速理解:
这张图展示了我最常用的分层策略。从上到下,可见性递减,隐私性递增。每一层都有明确的用途和边界。
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,但 debug 和 release 都从它继承公共配置。这样做的好处是:公共配置只写一次,后续维护只需要改 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