CMake 变量Scope


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的变量去独立区域,大概的示意图如下:

img

如图所以,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++中的传引用(指针)调用

img

那么如果是使用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’进行修改

img

这时候可以看出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传递的。

img

使用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工作在同一空间之中。

img

如果想要在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中看到该变量

参考

cmake-变量作用域

CMake Variable Scope

更多内容

更多内容


文章作者: ZhongSY
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 ZhongSY !
评论
  目录