在 CMake 中,set(... CACHE ...) 与不加 CACHEset(...) 是有本质区别的,它们设置的是不同作用域中的变量,并影响后续行为、用户配置方式等。

下面系统地说明二者区别:

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-guiccmake 中看到并修改
  • 一般用于用户可配置的值,如安装路径、构建选项、编译器选项等
  • 在不同目录、不同作用域中都能访问

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-guiccmake 可显示该变量
  • 用户可在配置阶段修改值
  • 跨子项目可见(除非手动 unset)

5. 使用场景对比

场景是否使用 CACHE
设置用户可配置的选项(开关)
提供默认安装路径或构建参数
脚本中间逻辑变量、临时变量
函数/模块中传递值否(或用 PARENT_SCOPE

6. 工具链与变量提升

在 toolchain 文件中,如果用户提前 set(VCPKG_TARGET_TRIPLET mytriplet)(未加 CACHE),toolchain 中必须用:

set(VCPKG_TARGET_TRIPLET "${VCPKG_TARGET_TRIPLET}" CACHE STRING "" FORCE)

目的是把原来在普通作用域设置的值“提升”为缓存变量,防止后续默认值覆盖。