CMake 变量

news/2024/12/29 18:23:45/

目录

cmake普通变量

如何取消变量

cmake环境变量

cmake缓存变量

普通变量使用:

缓存变量使用:

cmake变量的作用域

 block()

block demo:

function 函数作用域简单 demo

高级变量

总结:


和其他语言一样,cmake完全可以看做是一种编程语言,他有变量,有函数等.

cmake普通变量

cmake定义变量的命令如下:

 set(<variable> <value>... [PARENT_SCOPE])
  • cmake变量的约定:
  • cmake当所有的变量的值是为字符串
  • 当给出变量的值不包括空格的时候,可以不使用双引号,但是都建议加上双引号,不然一些奇怪的问题很难调试.
  • cmake使用空格或者分号作为字符串的分隔符
  • cmake中想要获取变量的值和shell脚本一样,采用${var}的形式
  • 使用cmake变量前不需要这个变量已经定义了,如果使用了未定义的变量,那么它的值就是一个空的字符串.
    • 默认情况下使用未定义的字符串不会有警告信息,但是可以通过cmake的-warn-uninitialzed的选项启用警告信息.
    • 使用未定义的变量非常常见,如果出现问题也不一定是因为变量未定义导致的,所以-warn-uninitialzed选项用处很有限.
  • 变量的值可以包含换行,也可以包含引号,不过需要转义.

第一个参数是必须的,代表要定义的变量的变量名.

第二个参数也是必须的,代表要定义的变量的值,根据上述cmake变量的约定,,我们知道这里的value应该是一个字符串,而且不管有没有空格,都建议用双引号引起来.

当然,第二个参数可以是一个以空格或者分号隔开的字符串,这样定义的变量将是一个列表.

第三个参数是个可选参数,意思是定义这个变量的作用域属于父作用域.

例如:

1.set(src "*.cpp")2.set(src main.cpp a.cpp)3.set(CPR_BUILD_CMD [[
#!/bin/bashcmake -S . -B build
cmake --build build
)4.set(shellScript [=[
~!/bin/bash
[[ -n "${USER}" ]] && echo "Have USER"
]=]
)

1,2比较简单就不说了,

3表示换行的,跟lua语言相似,使用[[开头 使用]]结尾

4表示换行中也有换行,使用[=[这个中间可以使用任意字符这里使用=了,结束的时候时候必须使用]=],因为要跟前面对饮起来.

如何取消变量

set(asd)
unset(asd)

unset就取消了这个变量.

cmake环境变量

不管是Windows,Linux还是macos都有环境变量的概念.我们经常使用的环境变量要数PATH这个环境变量了.Windows上可以在高级环境设置->环境变量中看到,Linux和macos上可以使用echo $PATH 或者export这条命令看到环境变量PATH的值.

除了PATH这个环境变量,对于日常开发中,我们通常还会有自定义的环境变量.比如我们安装了一个第三方软件,然后需要将一些安装目录导出到环境变量,这个时候就可能会用到自定义环境变量.

有些环境变量,只有我们自己的项目需要,所以就没必要为整个系统配置这类环境变量.cmake为我们提供了定义环境变量的方式,这样就可以让cmake定义的环境变量只在当前运行的cmake进程中生效,不会影响到系统或者其他进程的环境变量.

cmake定义的环境变量和获取环境变量的值的普通变量类似,只需要多加一个ENV标识符.


set(ENV{PATH} "/opt/myDir")    # 定义系统环境变量,只在cmake进程中有set(ENV{PATH} "/opt/myDir:ENV{PATH}")    #定义只在cmake进程使用的环境变量和系统环境一起打印message(STATUS "PATH=$ENV{PATH}") #打印字符

设置环境变量和使用环境变量在简单的cmake项目中很少见,大型跨平台项目中就比较常见.

系统环境变量只在配置阶段有效,在编译阶段就找不到了为空了.

cmake缓存变量

与普通变量不同的是,缓存变量的值是可以缓存到CMakeLists.txt文件中, 当再次运行cmake时,可以从中获取上一次的值,而不是重新去评估.所以缓存变量的作用域时全局的.

cmake定义缓存变量的格式如下:

set(varName value... CACHE type "docstring" [FORCE])

和普通变量比起来,缓存变量携带了更多的信息.缓存变量有了类型了,而且可以为缓存变量添加一个说明信息.

从上面的cmake定义缓存变量的命令中,我们可以得到,第一个参数依然是变量名字,第二个参数是变量的值.缓存变量不同于普通变量是从第三个参数开始的.第三个参数是固定CACHE这个关键字,表示这条命令定义的是缓存变量.

第四个变量type是必选参数,而且其值必须是下列值之一.

  • BOOL
    • BOOL类型的变量值如果是ON,TRUE,1则被评估为真,如果是OFF,FALSE,0则被评估为假.
    • 当然除了上面列出来的值还有其他的值,但是判断真假就没有那么清晰了,所以建议定义BOOL类型的缓存变量的时候其值就采用上述列出的值,虽然不区分大小写,但是建议统一使用大写.
  • FILEPATH
    • 文件路径
  • STRING
    • 字符串
  • INTERNAL
    • 内部缓存变量不会对用户可见,一般是项目为了缓存某种内部信息时才使用的,cmake图形化界面工具也对其不可见.
    • 内部缓存变量默认时FORCE的
      • FORCE关键字代表每次运行都强制更新缓存变量的值,如果没有该关键字,当再次运行cmake的时候,cmake将使用CMakeCache.txt文件中缓存的值,而不是重新进行评估.

cmake自身是将所有的值均视为字符串的,这里指定类型只是为了提高cmake图形界面工具的用户体验.

第五个参数是一个说明性的字符串,可以为空,只在图形化cmake界面会展示.由于BOOL类型的变量使用频率非常高,cmake为其单独提供了一条命令.

option(optVal helpString [initialValue])

第一个参数是变量名字,第二个参数是提供帮助信息的字符串,initialValue是可选参数,代表缓存变量的值,如果没有提供,那该缓存变量的默认值认为是OFF.

上述命令等价于:

set(optVal initialValue CACHE BOOL helpString)

不过上述两个命令定义缓存变量是有一点点区别的,option()命令没有FORCE关键字.

更改缓存变量cmake -D的形式去更改.

普通变量使用:

那cmake什么时候该使用不同变量了?什么时候该使用缓存变量了?

普通变量适用于变量的值相对固定,而且只在某一个很小的作用域生效的场景.

缓存变量使用:

缓存变量适用于其可以随时更改,作用域作为全局的情况.经常在cmake中定义缓存变量,给一个默认值,如果用户想要更改缓存变量的值,可以通过cmake -D的形式去更改.

cmake变量的作用域

做C/C++开发,作用域并不陌生.作用域和变量是密切相关的.cmake有变量自然有作用域的概念.不过cmake作用域可不简单针对变量.

cmake有策略这么一个概念,策略也有作用域.

在C/C++中我们可以使用{},函数,类等产生新的作用域.同时也有全局作用域的概念.在cmake中,通常在使用add_subdirectory()命令或者定义函数的时候产生新的作用域.自cmake 3.25以后可以使用block()在任意位置产生新的作用域.

cmake环境变量和缓存变变量的作用域是全局的.cmake普通变量的作用域受到不同cmake命令的影响.

在定义cmake普通变量的时候,如果没有PARENT_SCOPE选项.那该变量的作用域就在当CMakeLists.txt中,或者在当前函数,或者当前block()中.如果有PARENT_SCOPEcmake定义的变量就在父作用域.

demo:

set(A "aaa")

A 就在当前的CMakeLists.txt文件中.通过message是可以打印出来的.

如果有PARENT_SCOPE(离开当前作用域才会生效)

set(A "aaa" PARENT_SCOPE)

使用message是打印不出来的

cmake_minimum_required(VERSION 3.25 FATAL_ERROR) set(A "aaa")message(STATUS "A=${A}")set(B "bbb" PARENT_SCOPE)message(STATUS "B=${B}")

 block()

 block([SCOPE_FOR [POLICIES] [VARIABLES] ] [PROPAGATE <var-name>...])<commands>endblock()

第一个参数是可选的,[SCOPE_FOR [POLICIES] [VARIABLES] ]

POLICIES:策略

VARIABLES变量

PROPAGATE : 传播

该命令需要cmake 大于等于3.25版本,该命令用于创建新的作用域(变量作用域,策略作用域)

block demo:

set (x 1)
block()set(x 2)set(y 3)message(STATUS "x = ${x}")message(STATUS "y = ${y}")endblock()message(STATUS "top x = ${x}")
message(STATUS "top y = ${y}")

 x的作用域在外面,在block()里面新建一个x的值,和y的值,在作用域中打印,作用域里面的x和y的值就是当前作用域里面的值,x会把外面作用域的值覆盖了,出了block作用域,block作用域里面的赋值全部失效所以在外面x=1,y未定义为空.

set (x 1 PARENT_SCOPE)
set (y 3 PARENT_SCOPE)
block()set(x 2 PARENT_SCOPE)unset(y PARENT_SCOPE)message(STATUS "x = ${x}")message(STATUS "y = ${y}")endblock()message(STATUS "top x = ${x}")
message(STATUS "top y = ${y}")

 这个例子有PARENT_SCOPE关键字,所以在外面定义的x和y的值是在上一层生效,而在block中定义x和取消定义y是也是在上层生效.所x和y在block中打印的值都是空,出了block作用域,在block作用域定义的x和取消y的操作生效了,所以打印x为2 y为空.

set (x 1)
set (z 5)
block(PROPAGATE x z)set(x 2)set(y 3)unset(z)message(STATUS "x = ${x}")message(STATUS "y = ${y}")message(STATUS "z = ${z}")endblock()message(STATUS "top x = ${x}")
message(STATUS "top y = ${y}")
message(STATUS "top z = ${z}")

 PROPAGATE这个关键字是传播出去的意思.PROPAGATE x 和 z就说明,x和z的在block中的操作被传播出去了.

在顶层设置x和z的值,block中重新赋值x和y取消定义z,所以在block中打印x = 2, y =3 z =空,由于在block外层.未定义y block也未传播出去y,所以x依旧等于2, y和z为空. 

set (x 1)
set (z 5)
block(SCOPE_FOR VARIABLES PROPAGATE x z)set(x 2)set(y 3)unset(z)message(STATUS "x = ${x}")message(STATUS "y = ${y}")message(STATUS "z = ${z}")endblock()message(STATUS "top x = ${x}")
message(STATUS "top y = ${y}")
message(STATUS "top z = ${z}")

这个和上面的一样SCOPE_FOR VARIABLES不写就是默认值.

function 函数作用域简单 demo

set(A "aaa")
set(B "bbb")function(text_007)set(C "ccc")message(STATUS "test_007 A=${A}")message(STATUS "test_007 B=${B}")message(STATUS "test_007 C=${C}")
endfunction()text_007()message(STATUS "top test_007 A=${A}")
message(STATUS "top test_007 B=${B}")
message(STATUS "top test_007 C=${C}")

函数作用域,在函数体内可以打印A B C,由于C是在函数体内定义的变量,出了函数体就C就被析构了所以在函数体外C为空.

set(A "aaa" PARENT_SCOPE)
set(B "bbb" PARENT_SCOPE)function(text_007)set(C "ccc" PARENT_SCOPE)message(STATUS "test_007 A=${A}")message(STATUS "test_007 B=${B}")message(STATUS "test_007 C=${C}")
endfunction()text_007()message(STATUS "top test_007 A=${A}")
message(STATUS "top test_007 B=${B}")
message(STATUS "top test_007 C=${C}")

PARENT_SCOPE,在上一层起作用,函数体内的C定义了C,但是在函数体内不起作用在函数体外起作用.所以C在外层有值,AB在哪里都没有值.

set(A "aaa" PARENT_SCOPE)
set(B "bbb")function(text_007)unset(B)set(C "ccc" PARENT_SCOPE)message(STATUS "test_007 A=${A}")message(STATUS "test_007 B=${B}")message(STATUS "test_007 C=${C}")
endfunction()text_007()message(STATUS "top test_007 A=${A}")
message(STATUS "top test_007 B=${B}")
message(STATUS "top test_007 C=${C}")

B在函数体内设置未定义,所以在函数体内为空,但是在函数体外是可以打印的.

set(A "aaa" PARENT_SCOPE)
set(B "bbb")function(text_007)unset(B PARENT_SCOPE)set(C "ccc" PARENT_SCOPE)message(STATUS "test_007 A=${A}")message(STATUS "test_007 B=${B}")message(STATUS "test_007 C=${C}")
endfunction()text_007()message(STATUS "top test_007 A=${A}")
message(STATUS "top test_007 B=${B}")
message(STATUS "top test_007 C=${C}")

 B在函数体内设置未定义,但是在上一次生效,所以在函数体内打印的不受影响,但是在函数体外B为空.

高级变量

mark_as_advanced([CLEAR|FORCE] <var1> ...)

这个在cmake_gui里可以看到的, 第一个参数有两个,

CLEAR: 不标记为高级变量

FORCE: 标记为高级变量

如果这两个关键字都没有,那只有在该变量从未标记过高级变量或非高级变量时才将其标记为高级变量的

总结:

PARENT_SCOPE修饰的变量在上一层生效,函数体内对变量的操作不会对体外变量产生影响,除非使用PARENT_SCOPE.

block的PROPAGATE关键字导出,这个是可以在block中修改外部变量的,如果没有PROPAGATE这个变量和function作用差不多.        


http://www.ppmy.cn/news/684771.html

相关文章

事务的传播

七种传播机制支持当前事务不支持当前事务嵌套事务 七种传播机制 事务传播机制&#xff1a;解决一个事务在多个方法传递的问题 传播机制有以下7种 REQUIRED (默认)&#xff1a;如果当前存在事务&#xff0c;则加入该事务&#xff0c;如果不存在事务&#xff0c;则创建一个新事务…

美的集团的命,智能家居来续?

进入六月&#xff0c;6.18电商大战正式打响&#xff0c;玩家们可以说都是铆足了劲的比拼。截止至6月10日12时&#xff0c;在苏宁618悟空榜上&#xff0c;美的占尽了优势&#xff0c;甚至在家用空调、空调挂机和空调柜机三大榜单里&#xff0c;超越格力夺得榜首。 但是作为家电…

颜值经济风暴来袭,国产美容仪如何站稳脚跟?

站在风口上的医美市场&#xff0c;正迎来新的种子选手。 贝佐斯带肉毒素上天&#xff0c;马斯克重金植发&#xff0c;医美的万亿市场&#xff0c;无数资本赚得盆满钵满。爱美之路上&#xff0c;诞生了无数暴利故事&#xff1a;热玛吉、水光针、植发…… 而下一个&#xff0c;…

第27届郑州全国商品交易会 全面营造“促消费、惠民生”主题氛围

2021年10月13日下午&#xff0c;第27届郑州全国商品交易会新闻发布会在郑州国际会展中心举行。郑州市政府副秘书长、第27届郑州全国商品交易会筹委会办公室主任王义民&#xff0c;郑州市商务局局长、第27届郑州全国商品交易会筹委会办公室副主任张波&#xff0c;河南省商务厅国…

为未来企业而定义

为未来企业而定义 一、未来企业到底应该是什么样&#xff1f; 我把企业简单粗暴分为&#xff1a;农业、制造业、零售与服务业。而世界也是经历了&#xff1a;农业从牛犁耕种到现代大农业、制造业从手工作坊到现代大工业制造、零售业从小卖店到商超MALL到电商、服务业从人工服务…

论物联网与大数据、云计算、工业物联网、区块链

论物联网与大数据、云计算、工业物联网、区块链 我们当今的时代飞速发展&#xff0c;物联网、大数据、云计算这些名词在我们的生活中出现的越来越频繁&#xff0c;看似高大上的三者其实却和我们的生活息息相关。本篇文章就物联网、大数据以及云计算对三者之间的关系以及应用进行…

止血、回血 苏宁易购正在复苏路上

扛住二三季度的至暗时刻&#xff0c;苏宁易购正在稳住其基本盘面。 在10月29日苏宁易购披露的2021年前三季度业绩报告中&#xff0c;公司前三季度营收达到1155.74亿元。虽然财务数据上公司仍处于“三十年发展历程中最艰难的时期”&#xff0c;但从其生产经营数据看&#xff0c…

原厂服务

一、未来企业到底应该是什么样&#xff1f;我把企业简单粗暴分为&#xff1a;农业、制造业、零售与服务业。而世界也是经历了&#xff1a;农业从牛犁耕种到现代大农业、制造业从手工作坊到现代大工业制造、零售业从小卖店到商超MALL到电商、服务业从人工服务到知识信息服务。现…