【CMake 入门与进阶(14)】 CMake中变量的作用域(附代码)

        如同 C 语言一样,在 cmake 中,变量也有作用域的概念,本文我们就来聊一聊关于 cmake 中变量作用域的问题。

        对于函数作用域,当在函数内通过 set 将变量 var 与当前函数作用域绑定时,变量 var 仅在函数作用域内有效,出了这个作用域,如果这个作用域外也有同名的变量 var,那么使用的将是域外同名变量 var;func1()内部调用 func2(),嵌套调用的函数 func2()内部如果也引用变量 var,那么该变量 var 应该是 func1()内部定义的变量,如果有的话;如果 func1()内部没有绑定变量 var,那么就会使用 func1()作用 域外定义的变量 var,依次向外搜索。

        以上这段话大家可能不好理解,我们通过几个示例来看看函数作用域。

        ①、函数内部引用函数外部定义的变量

        示例代码如下所示:

# 函数 xyz
function(xyz)
    message(${ABC}) #引用变量 ABC
endfunction()

set(ABC "Hello World") #定义变量 ABC

xyz() # 调用函数

        ABC 是函数外部定义的一个变量,在函数 xyz 中引用了该变量,打印信息如下:

         所以可知,函数内可以引用函数外部定义的变量。

        ②、函数内定义的变量是否可以被外部引用

# 函数 xyz
function(xyz)
    set(ABC "Hello World")#定义变量 ABC
endfunction()

xyz() # 调用函数

if(DEFINED ABC)
    message("true")
    message("${ABC}") #引用函数内定义的变量 ABC
else()
    message("false")
endif()

        函数内定义了变量 ABC,外部调用函数之后,通过 if(DEFINED ABC)来判断变量 ABC 是否有定义,如果定义了该变量打印 true 并将变量打印出来,如果没有定义该变量则打印 false。测试结果如下:

         所以可知,函数内部定义的变量仅在函数内部可使用,出了函数之后便无效了,这其实跟 C 语言中差不多,函数中定义的变量可以认为是局部变量,外部自然是无法去引用的。

        ③、函数内定义与外部同名的变量

        测试代码如下所示:

# 函数 xyz
function(xyz)
    message("函数内部")
    message("${ABC}")
    set(ABC "Hello China!")#设置变量 ABC
    message("${ABC}")
endfunction()

set(ABC "Hello World!")#定义变量 ABC
xyz() # 调用函数
message("函数外部")
message("${ABC}")

        在这段代码中,我们在函数外定义了变量 ABC="Hello World!",在函数内去设置变量 ABC="Hello China!",函数执行完之后,在外部调用 message()打印变量 ABC。如果按照 C 语言中的理解,那么函数外部打印 ABC 变量的值应该等于"Hello China!"(大家不要去关注变量的定义是否需要放在函数定义之前,这种解释性脚本语言是没有类似于 C 语言中申明这种概念的,函数虽然定义了,但是调用函数是在定义变量之后的),但事实是不是这样呢,我们来看看打印信息:

         从打印信息可知,事实并非我们上面所假设那样,函数内调用 set 去设置变量 ABC,并不是设置了外部变量 ABC 的值,而是在函数新创建了一个变量 ABC,这个与 C 语言是不一样的,跟 Python 很像,如果大家学过 Python 的话应该就知道。

        所以函数内部的代码中,调用 set 之前,引用了变量 ABC,此时它会搜索函数内是否定义了该变量,如果没有,它会向外搜索,结果就找到了外部定义的变量 ABC,所以函数内部的第一条打印信息是"Hello World!";调用 set 之后,函数内也创建了一个变量 ABC,此时再次引用 ABC 将使用函数内定义的变量,而非是外部定义的变量,所以第二条打印信息是"Hello China!"。

        ④、函数内如何设置外部定义的变量

        那如果需要在函数内修改外部定义的变量,该如何做呢?譬如下面这段代码:

# 函数 xyz
function(xyz)
    set(ABC "Hello China!")
endfunction()

set(ABC "Hello World!")
xyz() # 调用函数
message("${ABC}")

        通过前面的介绍可知,xyz()函数内通过 set 只是创建了一个在函数内部使用的变量 ABC,而并非是去修改外部定义的变量 ABC,那如何能使得函数内可以去修改外部定义的变量呢?其实也非常简单,set 命令提供了一个可选选项 PARENT_SCOPE,只需在调用 set 命令时在参数列表末尾加上 PARENT_SCOPE 关键字即可,如下所示:

# 函数 xyz
function(xyz)
    set(ABC "Hello China!" PARENT_SCOPE) #加上 PARENT_SCOPE
endfunction()
set(ABC "Hello World!")
xyz() # 调用函数
message("${ABC}")

         再来看看打印信息:

         打印信息证明,加上 PARENT_SCOPE 之后确实可以,那 PARENT_SCOPE 选项究竟是什么? 官方给出的解释是这样的:如果添加了 PARENT_SCOPE 选项,则变量将设置在当前作用域范围之上的作用域范围内,每个目录(在这里“目录”指的是包含了 CMakeLists.txt 的目录)或函数都会创建一个新作用域,此命令会将变量的值设置到父目录或上层调用函数中。

        ⑤、函数的返回值如何实现?

        前面给大家介绍函数的时候提到过,cmake 中函数也可以有返回值,但是不能通过 return()命令来实现, 由于当时没介绍 PARENT_SCOPE,所以没法给大家讲解如何去实返回值,现在我们已经知道了 PARENT_SCOPE 选项的作用,其实就是通过这个选项来实现函数的返回值功能。

        先来看个示例:

# 顶层 CMakeLists.txt
cmake_minimum_required(VERSION 3.5)
project(TEST)

# 定义一个函数 xyz
# 实现两个数相加,并将结果通过 out 参数返回给调用者
function(xyz out var1 var2)
    math(EXPR temp "${var1} + ${var2}")
    set(${out} ${temp} PARENT_SCOPE)
endfunction()
xyz(out_var 5 10)
message("${out_var}")

        打印结果如下:

         看到这里不知道大家明白了没,其实很简单,调用 xyz()函数时,传入的 out_var 是作为一个参数传入进去的,而不是变量名,但现在需要将其变成一个变量名,怎么做呢?那就是在函数中获取参数 out 的值,将参数 out 的值作为变量名,然后用 set 创建该变量,并添加了 PARENT_ SCOPE 选项。所以通过 message 便 可以打印出该变量,因为这个变量在源码中定义了。


        关于 cmake,笔者就给大家介绍这么多,已经基本够用了;其实还有很多的命令以及变量没有介绍到, 但完全可以自己去看,然后去实战测试!

        本专栏完结~

猜你喜欢

转载自blog.csdn.net/cj_lsk/article/details/131348993