CMake Cache

CMake cache 可以被视为配置文件。第一次在项目上运行 CMake 时,它会在构建树的顶级目录中生成一个 CMakeCache.txt 文件。CMake 使用此文件存储一组全局缓存变量,这些变量的值会跨项目构建树中的多次运行而持续存在。

这个缓存有几个用途。第一个用途是存储用户的选择和选项,以便当他们再次运行 CMake 时无需重新输入该信息。例如,option 命令会创建一个布尔变量并将其存储在缓存中。

option(USE_JPEG "Do you want to use the jpeg library")

以上这行命令将创建一个名为 USE_JPEG 的变量并将其放入缓存中。通过这种方式,用户可以从用户界面设置该变量,其值将在用户将来再次运行 CMake 的情况下保留。若要在缓存中创建一个变量,请使用类似 optionfind_file 或带有 CACHE 选项的标准 set 命令的命令。

set(USE_JPEG ON CACHE BOOL "include jpeg support?")

使用 CACHE 选项时,你还可以提供变量的类型和说明文档字符串。变量的类型由 cmake-gui 用于控制该变量的设置和显示方式,但该值始终以字符串形式存储在缓存文件中。

缓存的另一个用途是允许 CMake 本身在 CMake 运行之间持续存储值。这些条目可能对用户不可见或不可调节。通常,这些值是系统相关的变量,要求 CMake 编译并运行一个程序以确定其值。一旦确定了这些值,它们就会存储在缓存中,以避免每次运行 CMake 时都必须重新计算它们。CMake 通常会尝试将这些变量限制为永不更改的属性(例如你所使用机器的字节顺序)。如果你显著地更改了计算机,无论是更改操作系统还是切换到其他编译器,你都将需要删除缓存文件(可能还需要所有二叉树的对象文件、库和可执行文件)。

一些项目非常复杂,缓存中设置一个值可能会导致下一次构建缓存时出现新的选项。例如,VTK 支持使用 MPI 来执行分布式计算。这需要构建过程来确定 MPI 库和头文件所在位置并允许用户调整其值。但是,仅当另一个选项 VTK_USE_PARALLEL 首先在 VTK 中启用时 MPI 才可用。因此,为了避免对于不知道 MPI 是什么的人感到困惑,这些选项在 VTK_USE_PARALLEL 启用之前都是隐藏的。因此,如果用户启用 VTK_USE_PARALLEL 选项并在 CMake 中重新配置,CMake 会在缓存区域中显示 VTK_USE_PARALLEL 选项,然后会出现用于 MPI 的新选项,以便他们随后进行设置。规则是不断构建缓存,直至其不再改变。对于大多数项目来说,这只需要一次。对于一些复杂的项目来说,可能需要两次或更多次。

您可能很想直接编辑缓存文件,或通过提供预填充的 CMakeCache.txt 文件来“初始化”项目。这可能不起作用,并且将来可能引起更多问题。首先,CMake 缓存的语法可能会发生变化。第二,缓存文件包含完整路径,这使其不适合在二进制树之间移动。

一旦变量在缓存中,通常无法从 CMakeLists 文件中修改其“缓存”值。其背后的原因是,一旦 CMake 将变量连同其初始值放入缓存中,用户便可以通过 GUI 修改此值。如果 CMake 的下一次调用将其更改覆盖回 set 值,则用户将永远无法进行 CMake 不会覆盖的更改。set(FOO ON CACHE BOOL "doc") 命令通常仅在缓存中不包含该变量时才会执行某些操作。一旦该变量存在于缓存中,该命令将不起作用。

在极少数情况下,如果您确实希望更改缓存变量的值,请将 FORCE 选项与 CACHE 选项结合使用 set 命令。FORCE 选项将导致 set 命令覆盖并更改变量的缓存值。

关于变量及其与缓存的交互作用,应该做出几点最终说明。如果变量位于缓存中,它仍然可以使用 set 命令在 CMakeLists 文件中覆盖,而无需 CACHE 选项。当在当前作用域中未定义引用的变量时,将检查缓存值。在不更改缓存中的值的情况下,set 命令将为当前作用域定义一个变量。

# assume that FOO is set to ON in the cache

set(FOO OFF)
# sets foo to OFF for processing this CMakeLists file
# and subdirectories; the value in the cache stays ON

位于缓存中的变量也具有一个属性,指示它们是否高级。默认情况下,当运行 ccmakecmake-gui 时,不会显示高级缓存条目。这样做的目的在于,可以让用户重点关注应该考虑更改的缓存条目。高级缓存条目是用户可以修改的其他选项,但通常不会修改。一个大型软件项目拥有 50 个或更多选项的情况并不少见,高级属性可以让软件项目将其划分为大多数用户关注的关键选项和高级用户关注的高级选项。根据项目不同,可能没有非高级缓存条目。要使缓存条目高级,可以使用 mark_as_advanced 命令与变量(又名缓存条目)的名称结合使用。

在某些情况下,你可能希望将缓存条目限制为有限的预定义选项集。你可以通过对缓存条目的 STRINGS 属性进行设置来实现此目的。以下 CMakeLists 代码会通过创建已命名的属性 CRYPTOBACKEND,然后对其 STRINGS 属性设置一组三个选项来对此进行说明。

set(CRYPTOBACKEND "OpenSSL" CACHE STRING
    "Select a cryptography backend")
set_property(CACHE CRYPTOBACKEND PROPERTY STRINGS
             "OpenSSL" "LibTomCrypt" "LibDES")

当运行 cmake-gui,并且用户选择了 CRYPTOBACKEND 缓存条目时,他们将会看到一个下拉菜单,以便选择他们想要的选项。

设置 CMake 的初始值

有时,可能需要在不运行 GUI 的情况下设置缓存项。在设置 nightly 仪表板或使用相同缓存值创建许多构建树时,这是很常见的。在这种情况下,有两种不同的方式可以初始化 CMake 缓存。第一种方法是使用 -DCACHE_VAR:TYPE=VALUE 参数在 CMake 命令行上传递缓存值。例如,考虑 UNIX 机器上的以下 nightly 仪表板脚本

#!/bin/tcsh

cd ${HOME}

# wipe out the old binary tree and then create it again
rm -rf Foo-Linux
mkdir Foo-Linux
cd Foo-Linux

# run cmake to setup the cache
cmake -DBUILD_TESTING:BOOL=ON <etc...> ../Foo

# generate the dashboard
ctest -D Nightly

可在 Windows 上使用批处理文件采用相同想法。

第二种方法是创建一个文件,以使用 cmake-C 选项进行加载。在这种情况下,不是使用 -D 选项设置缓存,而是通过 CMake 解析的文件进行设置。此文件的语法是标准的 CMakeLists 语法,通常是一系列 set 命令,例如

# Build the vtkHybrid kit.
set(VTK_USE_HYBRID ON CACHE BOOL "doc string")

在某些情况下,可能存在现有缓存,并且希望强制将缓存值设置为特定方式。例如,假设即使用户先前已运行并关闭了 CMake,也想打开 Hybrid。然后,您可以执行以下操作

# Build the vtkHybrid kit always.
set(VTK_USE_HYBRID ON CACHE BOOL "doc" FORCE)

另一个选择是设置并隐藏选项,以便用户不会在以后受到调整它们的诱惑。这可以通过类型 INTERNAL 来完成。 INTERNAL 缓存变量意味着 FORCE,并且永远不会在缓存编辑器中显示。

# Build the vtkHybrid kit always and don't distract
# the user by showing the option.
set(VTK_USE_HYBRID ON CACHE INTERNAL "doc")