在 CMake 中,set(... CACHE ...) 与不加 CACHE 的 set(...) 是有本质区别的,它们设置的是不同作用域中的变量,并影响后续行为、用户配置方式等。
下面系统地说明二者区别:
1. 不加 CACHE:设置的是普通变量
set(FOO "bar")- 设置的是** 当前作用域(directory scope)** 中的变量
- 不会影响其他目录中的变量,除非使用
PARENT_SCOPE显式传递 - 适合用在 CMake 脚本逻辑内部(比如函数、模块、条件逻辑中)
- 不会自动出现在 CMake GUI 或 ccmake 的缓存中
2. 加 CACHE:设置的是缓存变量
set(FOO "bar" CACHE STRING "description")- 设置的是缓存变量(cache variable)
- 存储在
CMakeCache.txt中,跨 CMake 多次运行持久存在 - 可在
cmake-gui或ccmake中看到并修改 - 一般用于用户可配置的值,如安装路径、构建选项、编译器选项等
- 在不同目录、不同作用域中都能访问
Note
通过 cmake -D 传入的参数默认就是 CACHE 变量,即等价于在 CMakeLists.txt 中写 set(... CACHE ...)。
3. CACHE 设置规则细节
- 当你使用
set(... CACHE ...)时,如果缓存中已经存在该变量,CMake 默认不会覆盖它(除非使用FORCE),如果存在的是普通变量,set(... CACHE ...)仍然会在缓存中创建该变量,但由于优先级规则,普通变量会继续被使用
Note
CMake 中变量查找的优先级是:普通变量 > 缓存变量,所以即使缓存中有同名变量,普通变量也会优先被使用
-
例如:
set(FOO "old" CACHE STRING "desc") set(FOO "new" CACHE STRING "desc") # 不会生效 set(FOO "new" CACHE STRING "desc" FORCE) # 会强制覆盖
4. 示例比较
不加 CACHE(局部变量):
set(MY_OPTION ON)- 设置的是当前目录有效的变量
- 后续
add_subdirectory()的子模块里不可见
加 CACHE(全局可见、可配置):
set(MY_OPTION ON CACHE BOOL "Enable feature X")cmake-gui和ccmake可显示该变量- 用户可在配置阶段修改值
- 跨子项目可见(除非手动 unset)
5. 使用场景对比
| 场景 | 是否使用 CACHE |
|---|---|
| 设置用户可配置的选项(开关) | 是 |
| 提供默认安装路径或构建参数 | 是 |
| 脚本中间逻辑变量、临时变量 | 否 |
| 函数/模块中传递值 | 否(或用 PARENT_SCOPE) |
6. 工具链与变量提升
在 toolchain 文件中,如果用户提前 set(VCPKG_TARGET_TRIPLET mytriplet)(未加 CACHE),toolchain 中必须用:
set(VCPKG_TARGET_TRIPLET "${VCPKG_TARGET_TRIPLET}" CACHE STRING "" FORCE)目的是把原来在普通作用域设置的值“提升”为缓存变量,防止后续默认值覆盖。