• CMake变量可见性学习


    CMake变量可见性


    变量是CMake的基本存储单元,与别的语言的变量在理解上别无二致。CMake变量名大小写敏感,通常与数字、字母、_、-构成。

    但是不同的是需要注意CMake变量的作用域。

    主要有以下几个作用域

    • 目录作用域
    • 文件作用域
    • 函数作用域
    • Persistent Cache

    add_subdirector vs include

    假设有以下CMake Project

    CMake_Test
    |__Child
    |	 |_ CMakeLists.txt
    |_ CMakeLists.txt
    
    • 1
    • 2
    • 3
    • 4

    其中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}")
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    child中的CMakeLists.txt

    # child CMakeLists.txt
    
    set(A "child")
    
    message("Child A val ${A}")
    
    • 1
    • 2
    • 3
    • 4
    • 5

    输出

    Child A val child
    Parent A val parent
    
    • 1
    • 2

    发现子目录的变量只会作用与自身并不会影响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}")
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    输出

    Child A val 
    Parent A val parent
    
    • 1
    • 2

    得出结论 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}")
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    执行结果如下:

    Child A val child
    Parent A val child
    
    • 1
    • 2

    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}")
    
    • 1
    • 2
    • 3
    • 4
    • 5

    输出

    Child A val parent
    Parent A val child
    
    • 1
    • 2

    简单理解:

    加入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}")
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    输出

    Child A val parent
    Parent A val child
    
    • 1
    • 2

    说明这时候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}")
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    输出

    Child A val parent
    Parent A val child
    
    • 1
    • 2

    就算是传值也是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}")
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    输出

    Child A val child
    Parent A val macro fun
    -- Configuring done
    -- Generating done
    
    • 1
    • 2
    • 3
    • 4

    如果改为传参模式

    		# 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}")
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    输出

    param A
    Child A val child
    Parent A val macro fun
    
    • 1
    • 2
    • 3

    通过结果可知,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

    更多内容

    更多内容

  • 相关阅读:
    IDEA插件Mybatis Log Plugin的安装及其使用教程
    Java创建对象的最佳方式:单例模式(Singleton)
    NVS 错误码对应的原因
    C语言练习百题之#include应用
    【数通 | BGP】使用eNSP进行IBGP的简单配置
    Java字符串内幕:String、StringBuffer和StringBuilder的奥秘
    聊聊关于图像分割的损失函数 - BCEWithLogitsLoss
    【毕业设计】大数据共享单车数据分析系统 - python
    【前端】Jquery UI +PHP 实现表格拖动排序
    一次违法网站的渗透经历
  • 原文地址:https://blog.csdn.net/ahelloyou/article/details/126380537