CMake变量可见性
变量是CMake的基本存储单元,与别的语言的变量在理解上别无二致。CMake变量名大小写敏感,通常与数字、字母、_、-构成。
但是不同的是需要注意CMake变量的作用域。
主要有以下几个作用域
- 目录作用域
- 文件作用域
- 函数作用域
- Persistent Cache
add_subdirector vs include
假设有以下CMake Project
CMake_Test
|__Child
| |_ CMakeLists.txt
|_ CMakeLists.txt
其中CMake_Test目录中的CMakeLists.txt文件内容如下:
# parent CMakeLists.txt
cmake_minimum_required(VERSION 3.2)
project(Test_CMake)
set(A "parent")
add_subdirectory(child)
message("Parent A val ${A}")
child中的CMakeLists.txt
# child CMakeLists.txt
set(A "child")
message("Child A val ${A}")
输出
Child A val child
Parent A val parent
发现子目录的变量只会作用与自身并不会影响Parent目录。是什么原因?
实际上是add_subdirectory
命令;在add_subdirectory
被执行的时候,会创建一块独立的区域去执行子目录的CMakeLists.txt文件,同时会拷贝一份A的变量去独立区域,大概的示意图如下:
如图所以,Child中是Parent的副本。
改变CMakeLists.txt
# parent CMakeLists.txt
cmake_minimum_required(VERSION 3.2)
project(Test_CMake)
add_subdirectory(child)
set(A "parent")
message("Parent A val ${A}")
输出
Child A val
Parent A val parent
得出结论 ==add_subdirectory
只会对之前可见的变量做拷贝==
现在改变Parent CMakeLists.txt的内容
# parent CMakeLists.txt
cmake_minimum_required(VERSION 3.2)
project(Test_CMake)
set(A "parent")
include(child)
message("Parent A val ${A}")
执行结果如下:
Child A val child
Parent A val child
与add_subdirectory
相反include
使得child与parent的scope一致,所以当我们include中set的时候会直接影响parent的值。
可以简单的理解为==add_subdirectory==是C++中的传值调用,==include==是C++中的传引用(指针)调用
那么如果是使用add_subdirectory
那么如何在child中改变parent的值,实现如下:
# child CMakeLists.txt
set(A "child" PARENT_SCOPE)
message("Child A val ${A}")
输出
Child A val parent
Parent A val child
简单理解:
加入PARENT_SCOPE
会直接修改parent目录下Ade值,但是并不会对当前目录下的copy A’进行修改
这时候可以看出add_subdirectory
的时候是目录作用域,每个目录下的CMakeLists.txt是隔离的。
include
时候是文件作用域,都作用在parent CmakeLists
Macro vs Function
# parent CMakeLists.txt
cmake_minimum_required(VERSION 3.2)
project(Test_CMake)
function(fun)
set(A "fuc A")
endfunction()
set(A "parent")
fun()
# include(child/CMakeLists.txt)
add_subdirectory(child)
message("Parent A val ${A}")
输出
Child A val parent
Parent A val child
说明这时候function中set
的变量就好像是==函数定义的局部变量不会影响到外部==
如果是传值呢????
# parent CMakeLists.txt
cmake_minimum_required(VERSION 3.2)
project(Test_CMake)
function(fun param)
set(${param} "fuc A")
endfunction()
set(A "parent")
fun(A)
# include(child/CMakeLists.txt)
add_subdirectory(child)
message("Parent A val ${A}")
输出
Child A val parent
Parent A val child
就算是传值也是copy传递的。
使用macro代替function
# parent CMakeLists.txt
cmake_minimum_required(VERSION 3.2)
project(Test_CMake)
function(fun param)
set(${param} "fuc A")
endfunction()
macro(funmacro param)
set(A "macro fun")
endmacro()
set(A "parent")
# fun(A)
funmacro(A)
# include(child/CMakeLists.txt)
add_subdirectory(child)
message("Parent A val ${A}")
输出
Child A val child
Parent A val macro fun
-- Configuring done
-- Generating done
如果改为传参模式
# parent CMakeLists.txt
cmake_minimum_required(VERSION 3.2)
project(Test_CMake)
function(fun param)
set(${param} "fuc A")
endfunction()
macro(funmacro param)
set(${param} "macro fun")
message("param ${param}")
endmacro()
set(A "parent")
# fun(A)
funmacro(A)
# include(child/CMakeLists.txt)
add_subdirectory(child)
message("Parent A val ${A}")
输出
param A
Child A val child
Parent A val macro fun
通过结果可知,macro与include类似,与Parent工作在同一空间之中。
如果想要在add_subdirectory
中定义函数改变Parent中的值,就需要在set中加入PARENT_SCOPE
。
也就是说function与macro,前者是函数作用域后者是文件作用域。
Persistent Cache
缓存变量,拥有着独立的scope,只能通过特定的请求改变其值,比如set
,uset
的时候带上Cache
选项。Cache变量在整个CMake工程的编译声明周期中都有效。工程中任意的目录都可以访问Cache变量,==类似于全局静态变量==。==需要注意的是,CMake是从上到下进行解析CMakeLists,tx文件的。==
set(cache_var1 “persistent-缓存变量1” CACHE STRING “abc”)
编译后,可以在bulid/CMakeCache.txt中看到该变量