重复执行 cmake -B build 会有什么区别?
可以看到第二次的输出少了很多,这是因为 CMake 第一遍需要检测编译器 和 C++ 特性等比较耗时,检测完会把结果存储到缓存中,这样第二遍运行 cmake -B build 时就可以直接用缓存的值,就不需要再检测一遍了。
如何清除缓存?删 build 大法了解一下
然而有时候外部的情况有所更新,这时候 CMake 里缓存的却是旧的值,会导致一系列问题。 这时我们需要清除缓存,最简单的办法就是删除 build 文件夹,然后重新运行 cmake -B build。
缓存是很多 CMake 出错的根源,因此如果出现诡异的错误,可以试试看删 build 全部重新构建。
经典 CMake 笑话:“99%的cmake错误可以用删build解决”“删 build 大法好”。
清除缓存,其实只需删除 build/CMakeCache.txt 就可以了
删 build 虽然彻底,也会导致编译的中间结果(.o文件)都没了,重新编译要花费很长时间。如果只想清除缓存,不想从头重新编译,可以只删除 build/CMakeCache.txt 这个文件。这文件里面装的就是缓存的变量,删了他就可以让 CMake 强制重新检测一遍所有库和编译器。
build/CMakeCache.txt 的内容

find_package 就用到了缓存机制
变量缓存的意义在于能够把 find_package 找到的库文件位置等信息,储存起来。 这样下次执行 find_package 时,就会利用上次缓存的变量,直接返回。 避免重复执行 cmake -B 时速度变慢的问题。
设置缓存变量
语法是:set(变量名 “变量值” CACHE 变量类型 “注释”)

缓存的 myvar 会出现在 build/CMakeCache.txt 里

常见问题:我修改了 CMakeLists.txt 里 set 的值,却没有更新?
为了更新缓存变量,有的同学偷懒直接修改 CMakeLists.txt 里的值,这是没用的。 因为 set(... CACHE ...) 在缓存变量已经存在时,不会更新缓存的值! CMakeLists.txt 里 set 的被认为是“默认值”因此不会在第二次 set 的时候更新。

缓存变量到底该如何更新?标准解法:通过命令行 -D 参数
更新缓存变量的正确方法,是通过命令行参数:cmake -B build -Dmyvar=world
命令行 -D 参数太硬核了,有没有图形化的缓存编辑器?

在 Linux 中,可以运行 ccmake -B build 来启动基于终端的可视化缓存编辑菜单。 在 Windows 则可以 cmake-gui -B build 来启动图形界面编辑各个缓存选项。 当然,直接用编辑器打开 build/CMakeCache.txt 修改后保存也是可以的。 CMakeCache.txt 用文本存储数据,就是可供用户手动编辑,或是被第三方软件打开并解析的。
缓存变量到底该如何更新?暴力解决:删 build 大法
用万能的“删 build 大法”当然是可以的。这样重新执行的时候缓存变量不存在, 从而 set 会重新设置缓存的值为 world。建议初学者每次修改 CMakeLists.txt 时, 都删一下 build/CMakeCache.txt 方便调试。

也可以通过指定 FORCE 来强制 set 更新缓存
set 可以在后面加一个 FORCE 选项,表示不论缓存是否存在,都强制更新缓存。 不过这样会导致没办法用 -Dmyvar=othervalue 来更新缓存变量。

缓存变量除了 STRING 还有哪些类型?
STRING 字符串,例如 “hello, world”FILEPATH 文件路径,例如 “C:/vcpkg/scripts/buildsystems/vcpkg.cmake”PATH 目录路径,例如 “C:/Qt/Qt5.14.2/msvc2019_64/lib/cmake/”BOOL 布尔值,只有两个取值:ON 或 OFF。
- 注意:TRUE 和 ON 等价,FALSE 和 OFF 等价;YES 和 ON 等价,NO 和 OFF 等价。
案例:添加一个 BOOL 类型的缓存变量,用于控制要不要启用某特性



CMake 对 BOOL 类型缓存的 set 指令提供了一个简写:option
option(变量名 “描述” 变量值)等价于: set(变量名 CACHE BOOL 变量值 “描述”)
经典问题:小彭老师,我option设为OFF了为什么他还是ON呀?


因为在CMakeLists.txt里直接改option是错的,官方解法是通过-D参数来改
刚刚说了,option 等价于 set(... CACHE BOOL ...)。 因此在CMakeLists.txt里改同样不会立即更新缓存里的值。 官方推荐做法是通过 -D变量名:BOOL=ON/OFF 来改缓存变量。 这是cmake官方认为正确的缓存更新方式,但是很多人不知道, 还是傻傻的去改option里的值,然后发现没有效果,开始怀疑 cmake是不是出bug了,其实是官方宣传力度不够。
或者不要option了,直接用set加个FORCE即可始终强制更新缓存
当然最方便的还是删build大法,或者删build/CMakeCache.txt大法。 删build大法总能把缓存变量强制初始化为CMakeLists.txt里的值。
绕开缓存的方法:使用普通变量,但仅当没有定义时设定为默认值
一般来说CMake自带的变量(如CMAKE_BUILD_TYPE)都会这样设置。 这样项目的使用者还是可以用-D来指定参数,不过会在ccmake里看不到。

