快速掌握CMake「三、CMake缓存」
「CMake」是一个跨平台的C++项目管理解决方案,它可以帮助用户方便地管理大型C++项目,支持生成不同平台的Makefile。本系列文章可以帮助你快速掌握CMake,所有内容来源于Mastering Cmake。
本篇文章为该系列的第三篇。你可以将CMake缓存理解为一个配置文件。当你在项目中第一次运行CMake时,会在build目录的顶层生成CMakeCache.txt
文件,CMake使用这个文件来存储一系列全局缓存变量。
缓存文件有几个用途。首先是存储用户的设定,这样当再次运行CMake时,他们就不需要重新输入各种选项。例如,option
命令创建一个布尔变量并将其存储在缓存中。
option(USE_JPEG "Do you want to use the jpeg library") |
这行代码会创建一个名为USE_JPEG
的遍历,并将其放入缓存中。这样,用户就可以在用户界面中设置这个变量,它的值将保留下来,以便用户将来再次运行CMake。要在缓存中创建一个变量,可以使用类似option
,find_file
命令,或者可以使用标准的set
命令,但要加上CACHE
选项。
set(USE_JPEG ON CACHE BOOL "include jpeg support?") |
当你使用CACHE
选项时,你可以提供变量的类型,以及一个字符串作为它的描述文档。cmake-gui会根据变量的类型来控制如何设置和显示该变量,但是值总是作为字符串存储在缓存文件中。
缓存的另一个目的是允许CMake本身在CMake运行之间持久地存储值。这些缓存项对用户是不可见的,且无法调整。通常,这些值是系统相关的变量,需要CMake来编译和运行程序来确定它们的值。一旦确定了这些值,它们就会存储在缓存中,以避免每次CMake运行时都要重新计算它们。CMake通常会尝试将这些变量限制为不应更改的属性(例如你的计算机的字节顺序)。如果你的设备有重大变化,比如更换了操作系统或者编译器,那么你需要将这些缓存文件全部删除。
有些项目非常复杂,在缓存中设置一个值可能会导致在下一次构建缓存时出现新选项。例如,VTK支持使用MPI执行分布式计算。这需要构建过程确定MPI库和头文件的位置,并让用户调整它们的值。但是只有在VTK中打开另一个选项VTK_USE_PARALLEL
时,MPI才可用。因此,为了避免让不知道MPI是什么的人感到困惑,这些选项在打开VTK_USE_PARALLEL
之前都是隐藏的。因此,CMAKE在缓存区域中显示VTK_USE_PARALALE
选项,如果用户打开该选项并将CMake重新配置,则将出现MPI的选项,然后可以进行MPI的相关设置。这个过程的规则是持续构建缓存,直到缓存不再发生变化为止。对于大多数项目,此过程可能只有一次,而对于某些复杂的项目来说,它可能是两次或更多。
你可能想直接编辑缓存文件,或通过给项目初始化缓存文件来初始化项目。这可能不起作用,并可能在未来引起其他问题。首先,CMake缓存的语法可能会发生变化。其次,缓存文件包含完整的路径,这使得它们不适合在目录之间移动。
一旦变量存储在缓存中,它的缓存值通常不能从CMakeLists文件中修改。这背后的原因是,一旦CMake将变量及其初始值放入缓存,用户就可以从GUI修改该值。如果CMake的下一次调用将它们覆盖为set
命令设置的值,那么用户将永远无法从CMake界面中修改缓存的值。一个set(FOO ON CACHE BOOL“doc”)
命令通常只会在缓存中没有变量时生效。一旦该变量已经存在于缓存中,那么该命令将不起作用。
在极少数情况下,你可能确实需要更改缓存变量的值,可以将FORCE
选项与set
命令的CACHE
选项结合使用。FORCE
选项将导致set
命令覆盖并更改变量的缓存值。
关于变量及其与缓存的交互,最后需要说明几点。如果一个变量在缓存中,它仍然可以在CMakeLists文件中使用不带缓存选项的set
命令来覆盖。当引用的变量没有在当前作用域中定义时,将检查缓存值。set命令将为「当前作用域」定义一个变量,而不改变缓存中的值。
# assume that FOO is set to ON in the cache |
缓存中的变量还有一个属性,用于指示它们是否是高级的。默认情况下,执行ccmake
或cmake-gui
命令时,不显示高级缓存项。这样用户就可以专注于他们应该考虑更改的缓存项。高级缓存项是用户可以修改的其他选项,但通常不会修改。对于一个大型软件项目来说,拥有50个或更多的选项并不罕见,而高级属性允许将软件项目划分为针对大多数用户的关键选项(key option)和针对高级用户的高级选项(advanced option)。对于一些项目来说,可以仅包含高级选项。要创建一个高级缓存项,可以使用mark_as_advanced
命令。
在一些场景中,你可能想要限制一些缓存项的取值范围。你可以通过设置STRINGS
命令来实现这一点。下面的CMakeLists代码通过创建一个名为CRYPTOBACKEND
的缓存项来说明这一点,注意它的STRINGS
属性的取值范围被设置为包含三个选项的集合。
set(CRYPTOBACKEND "OpenSSL" CACHE STRING |
用户当运行cmake-gui
,选择CRYPTOBACKEND缓存项时,他们将会看到一个下拉菜单来选择他们想要的选项。
设置CMake的初始值
有时你可能需要在不运行GUI的情况下设置缓存条目。这在设置夜间仪表板时很常见,或者您将创建许多具有相同缓存值的构建树。在这些情况下,CMake缓存可以用两种不同的方式初始化。第一种方法是在CMake命令上使用-DCACHE VAR:TYPE=VALUE
参数传递缓存值。例如,考虑以下UNIX脚本:
#!/bin/tcsh |
这种方式也可以用于Windows上的批处理文件。
第二种方法是使用cmake
的-C
选项创建一个要加载的文件。在这种情况下,不是使用-D选项设置缓存,而是通过让CMake解析文件来实现。该文件的语法是标准的CMakeLists语法,它通常是一系列set
命令,例如:
# Build the vtkHybrid kit. |
在某些情况下,可能某个缓存变量已经存在,而你希望强制以某种方式设置缓存值。例如,假设你想要打开Hybrid,即使用户之前已经运行了CMake并关闭了它。那么你可以:
# Build the vtkHybrid kit always. |
另一种选择是你想要设置然后隐藏选项,这样用户以后就不会试图调整它们。这可以使用类型INTERNAL
来完成。INTERNAL
缓存变量默认是以FORCE
方式设置的,并且不会显示在缓存编辑器中。
# Build the vtkHybrid kit always and don't distract |