11、缓存变量(cacheVariables):定义 CMake 缓存变量,如 CMAKE_BUILD_TYPE
缓存变量,说白了就是 CMake 里那些「记住一次,下次不用再问」的变量。你想想看,每次运行 cmake 都要重新指定构建类型、安装路径,是不是很烦?缓存变量就是来解决这个问题的。
我个人习惯把缓存变量理解成「CMake 的配置文件」。第一次配置时设好值,它们会被写入 CMakeCache.txt。下次再跑 cmake,这些值自动生效,不用重复输入。嗯,这里要注意:缓存变量和普通变量不一样,普通变量只在当前 CMakeLists.txt 作用域有效,缓存变量是全局的、持久的。
11.1 缓存变量的本质
在 CMake Presets 里,cacheVariables 字段就是用来预设这些缓存变量的。它的语法很简单:
{
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Release",
"CMAKE_INSTALL_PREFIX": "${sourceDir}/install",
"MY_PROJECT_ENABLE_TEST": "ON"
}
}
每个键值对对应一个缓存变量。值可以是字符串、布尔值、路径等。CMake 会自动识别类型。
核心要点:缓存变量一旦设置,除非手动清除或强制覆盖,否则一直保留。这既是优点也是坑点。
11.2 常见的缓存变量
我在项目中遇到过不少团队,对缓存变量的理解停留在「不就是 CMAKE_BUILD_TYPE 嘛」。其实远不止这些。下面这张图帮你理清常见的缓存变量分类:
从图中可以看到,缓存变量覆盖了构建的方方面面。我个人最常用的是前三类:构建类型、安装路径和编译工具链。
11.3 CMAKE_BUILD_TYPE 的细节
这个变量可能是大家最熟悉的。但有个坑:它只对单配置生成器有效,比如 Makefile 和 Ninja。对于 Visual Studio 和 Xcode 这种多配置生成器,CMAKE_BUILD_TYPE 会被忽略。
我曾经踩过的坑:有一次团队里有人用 Ninja 生成器,但 Presets 里没设 CMAKE_BUILD_TYPE。结果默认是空字符串,编译出来的东西既不是 Debug 也不是 Release,优化级别乱七八糟。排查了半天才发现是缓存变量没设对。
正确的做法是:
{
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Release"
}
}
如果你用的是多配置生成器,就别设这个变量了。改用 configuration 字段来指定。
11.4 布尔值缓存变量
很多项目会用缓存变量来控制功能开关。比如:
{
"cacheVariables": {
"BUILD_SHARED_LIBS": "ON",
"ENABLE_UNIT_TESTS": "OFF",
"USE_OPENMP": "ON"
}
}
这里有个小技巧:CMake 里布尔值用 ON/OFF,而不是 true/false。虽然 CMake 也认 TRUE/FALSE,但行业惯例是 ON/OFF。我建议统一用这个风格,团队协作时少一些歧义。
11.5 路径类缓存变量
路径变量要注意绝对路径和相对路径的区别。在 Presets 里,我推荐用 ${sourceDir} 和 ${sourceParentDir} 这类宏来构建路径:
{
"cacheVariables": {
"CMAKE_INSTALL_PREFIX": "${sourceDir}/output",
"THIRD_PARTY_DIR": "${sourceParentDir}/third_party"
}
}
这样做的好处是:项目换个目录,路径自动跟着变。不用手动改。
个人经验:我见过有人把绝对路径写死在 Presets 里,比如 /home/zhangsan/project/install。结果别人拉下来根本跑不了。用 ${sourceDir} 这种宏,才是团队协作的正确姿势。
11.6 缓存变量的覆盖规则
缓存变量有优先级。理解这个优先级,能帮你避免很多莫名其妙的 bug:
| 优先级 | 来源 | 说明 |
|---|---|---|
| 最高 | 命令行 -D 参数 |
cmake -DCMAKE_BUILD_TYPE=Debug ... |
| 中 | Presets 中的 cacheVariables | 当前 Preset 配置 |
| 低 | CMakeLists.txt 中的 set(... CACHE ...) | 项目源码中的默认值 |
| 最低 | CMake 内置默认值 | 比如 CMAKE_BUILD_TYPE 默认为空 |
为什么会这样?因为命令行 -D 是用户主动指定的,理应优先级最高。Presets 是团队约定,次之。源码里的默认值,只是兜底方案。
11.7 实战:一个完整的例子
来看一个我实际项目中用过的 Preset 配置:
{
"configurePresets": [
{
"name": "release",
"displayName": "Release 构建",
"description": "生产环境发布版本",
"generator": "Ninja",
"binaryDir": "${sourceDir}/build/release",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Release",
"CMAKE_CXX_STANDARD": "17",
"CMAKE_INSTALL_PREFIX": "${sourceDir}/install/release",
"BUILD_SHARED_LIBS": "ON",
"ENABLE_LOGGING": "OFF",
"ENABLE_PROFILING": "OFF"
}
},
{
"name": "debug",
"displayName": "Debug 构建",
"description": "开发调试版本",
"generator": "Ninja",
"binaryDir": "${sourceDir}/build/debug",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Debug",
"CMAKE_CXX_STANDARD": "17",
"CMAKE_INSTALL_PREFIX": "${sourceDir}/install/debug",
"BUILD_SHARED_LIBS": "ON",
"ENABLE_LOGGING": "ON",
"ENABLE_PROFILING": "ON"
}
}
]
}
你看,Release 和 Debug 两个 Preset,通过 cacheVariables 区分了构建类型和功能开关。团队成员只需要 cmake --preset release 或 cmake --preset debug,就能得到完全一致的构建环境。
核心总结:缓存变量是 CMake Presets 的「记忆系统」。用好它,你的构建配置就能做到「一次定义,到处复用」。我个人建议把项目所有可配置项都通过缓存变量暴露出来,然后在 Presets 里统一管理。这样既清晰,又便于团队协作。
嗯,关于缓存变量就聊这么多。记住一点:缓存变量设好了,构建就稳了一半。另一半是什么?等你用到自然就知道了。