首页 > 技术文章 > CMake中的两种变量(Variable types in CMake)

newneul 2018-01-27 22:06 原文

  在CMake中存在两种变量:normal variables and cache varialbes .正常变量就像是脚本内部变量,相当于程序设计中定义的局部变量那样。而CMakeLists.txt相当于一个函数,第一个执行的CMakeLists.txt相当于主函数。所以正常变量。不能跨越CMakeLists.txt文件(they are not persisted across CMake runs)。cache变量如果在set中设置成了INTERNAL,那么它与正常变量是一样的效果,就是两个CMakeLists.txt内部定义的变量不能共享(前提是这两个CMakeLists.txt之间没有包含关系,比如在src中有一个CMakeLIsts.txt在inc中有一个CMakeLists.txt ),也就是局部变量的作用仅仅在函数内部一样的效果,而正常变量的作用域仅在当前的CMakeLists.txt中。如果cache没有被设置成INTERNAL,那么相当于全局变量。都是在第一个执行的CMakeLists.txt中设置好的,当然可以在被包含的子CMakeLists.txt中修改cache值,此时也会影响父/主的CMakeLists.txt,这个变量用来配置整个工程的,配置好后会对整个工程适用。
normal variables and cache variables ,两种同名不同类型的变量在同一个CMakeLists.txt中,可以同时存在但是要有不同的值,就相当于程序中的全局变量和局部变量的名字可以是一样的。这两个同名变量,CMake首先搜索使用的是设置好了的正常变量,只有正常变量没有被设置的时候,才会默认的搜索使用设置好了的cache变量。如果一个cache变量被修改或者增加的时候,CMake会自动移除同范围内的同名的normal变量(也就是同一个CMakeLists.txt)。为了避免两种变量发生的冲突或者正常变量无意间隐藏cache变量,在工程中我们避免设置相同名字的normal变量和cache变量(Normally projects should avoid using normal and cache variables of the same name),但是在有些工程中我们可能会使用正常变量来隐藏cache变量的这一技巧。比如我们常见的工程目录,在一个工程中我们在主文件夹下面会有一个CMakeLists.txt文件,然后在src文件夹中也会有一个CMakeLists.txt,然后在主文件中的CMakeLists.txt中add_subdirectories(src),主 子 CMakeLists.txt建立起了联系,这个时候我们在主文件的CMakeLists.txt中设置一个cache变量 比如设置编译器选项,通常情况下,src子目录中的编译器选项也是被设置成了与父目录的编译器同样的,但是假设在子目录中我们想要单独为子目录设置不一样的编译器选项,那么我们必须要建立一个同名的cache变量,当然之前已经有一个cache变量了,所以此时的set()仅仅是修改了那个cache变量的值,变为了适用于子目录的编译器选项,如果这样设置的话,那么主/父目录中的编译器选项就会被修改。为了避免这种情况,可以在主/父目录中的CMakeLists.txt中在设置一个正常的同名的变量,对应编译器选项的值。这样主CMakeLists.txt在执行的时候,正常变量会隐藏cache变量,直接访问normal varables 获取编译器选项的设定值,即使子目录修改cache变量的值也不会影响父目录的编译器选项的设置情况。

补充一点:If <value> is not specified then the variable is removed instead of set. See also: the unset() command.通过下面的设定可以删除指定的变量(原文没有指出是哪种变量,所以默认是normal 和cache两种变量都可以)。
set(<variable> <value1> ... <valueN>)
参考资料:
1、https://cmake.org/cmake/help/v3.0/command/set.html

推荐阅读