CMake 变量

news2024/12/28 20:40:34

目录

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/bash

cmake -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.coloradmin.cn/o/709542.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

解决uview-plus组件样式修改不生效

一、问题描述 使用 ::v-deep 、/deep/ 等各种 deep 写法后&#xff0c;修改 uview-plus组件样式依旧不生效 二、解决方案 在子组件中写页面布局&#xff0c;在父组件中写CSS样式 目录结构&#xff1a; 父组件中&#xff1a;引入子组件&#xff0c;使用::v-deep修改样式 子组件…

git配置密钥及提交代码到仓库

原文合集地址如下&#xff0c;有需要的朋友可以关注 本文地址 合集地址 一、git下载及安装 Git官网&#xff1a;www.git-scm.com/ 下载安装包进行安装。 点击downloads下载自己需要的安装包。本文基于windows系统。 下载安装包后双击exe文件&#xff0c;如何一系列next操作…

提升文件管理效率:轻松批量归类文件,按名称细分管理

现代生活中&#xff0c;我们每天都面对着大量的电子文件&#xff0c;如文档、照片、音乐和视频等。这么多文件堆积在一起&#xff0c;怎样快速找到需要的文件成了一个挑战。现在有应该方法可以帮助您提升文件管理效率&#xff0c;方法如下&#xff1a; 首先&#xff0c;第一步…

AutoSAR系列讲解(入门篇)4.6-BSW的Watchdog功能

一、架构与术语解释 前面都挺难的吧&#xff1f;实践出真知&#xff0c;后面实践篇的时候&#xff0c;大家应该就能明白了。这一节就来讲个简单的功能------看门狗。看门狗想必大家应该都再熟悉不过了吧&#xff0c;主要就下面三层结构&#xff0c;简单明了&#xff0c;这节确实…

从入门到精通:解锁Linux开发工具和编译器的力量

目录 一.编辑器vim的使用1.vim的基本概念2.vim的使用二.编译器gcc/g1.编译器的使用2.编译器是如何完成的&#xff1f;3.动态库与静态库 一.编辑器vim的使用 1.vim的基本概念 vim是一个方便编程的功能特别丰富的文本编辑器&#xff0c;凭借他简洁的三种模式以及丰富的快捷键操…

Arduino IDE的安装

https://www.arduino.cc/en/software/

AI 绘画 - 建筑绘图辅助设计之 Controlnet

前情提要 2023-06-17 周六 杭州 阴 小记: 早上还是可以听到淅淅沥沥的雨声&#xff0c;或许梅雨季快要来了&#xff0c;潮湿的感觉说不上多讨厌&#xff0c;可是也没有那么喜欢&#xff1b;最近在追动画《飞出个未来》&#xff0c;我是把这个动画当作哲学课来看的&#xff0c…

linux模块的变量与函数导出与引用

在Linux内核中&#xff0c;不同模块之间可以通过导出和引用函数或变量的方式来进行交互。具体而言&#xff0c;Linux内核提供了一些导出和引用符号的机制&#xff0c;这些机制可以使得不同模块之间能够访问并使用彼此的函数或变量。 导出符号的方式一般有两种&#xff1a; 使…

【动态规划算法练习】day12

文章目录 一、978. 最长湍流子数组1.题目简介2.解题思路3.代码4.运行结果 二、413. 等差数列划分1.题目简介2.解题思路3.代码4.运行结果 三、1567. 乘积为正数的最长子数组长度1.题目简介2.解题思路3.代码4.运行结果 总结 一、978. 最长湍流子数组 1.题目简介 978. 最长湍流子…

python输出颜色(终端控制台)

python输出颜色&#xff08;终端控制台&#xff09; 1、终端ANSI2、Python自带的函数库ctypes3、colorama 1、终端ANSI 更多查看 ECHOX.bat输出文本背景和文字颜色 其中特殊字符print("Black :[30m f0 [0m Black :[40m b0 [0m")即是print("Black :\033[30m f0 …

3.设计模式之后七种模式桥接装饰者组合外观享元代理模板

1.桥接模式 bridge(抽象类的实现的子类,通过聚合间接调用接口方法 就是桥) 实现和抽象分开,使他可以独立改变结构型设计模式基于类的最小设计原则(增加功能,增加最少个数的类),通过封装 聚合和继承让不同类实现不同职责 图 23桥接模式原理图 图 26桥接模式传统解决手机操作问题…

(六)Spring源码解析:Spring AOP源码解析

〇、AOP概念 Aspect&#xff1a;切面 给业务方法增加到功能&#xff0c;切面泛指交叉业务逻辑。上例中的事务处理、日志处理就可以理解为切面。常用的切面是通知&#xff08;Advice&#xff09;。实际就是对主业务逻辑的一种增强。 Pointcut&#xff1a;切入点 切入点指声明的…

Nerf-Wild神经辐射场论文学习笔记 Neural Radiance Fields for Unconstrained Photo Collections

前言&#xff1a; 本文为记录自己在Nerf学习道路的一些笔记&#xff0c;包括对论文以及其代码的思考内容。公众号&#xff1a; AI知识物语 B站讲解&#xff1a;出门吃三碗饭 本篇文章主要针对其数学公式来学习其内容&#xff0c;欢迎批评指正&#xff01;&#xff01;&#x…

10-C++学习笔记-字符串

&#x1f4da; 前言 字符串是在编程中广泛使用的数据类型&#xff0c;用于表示一系列字符。在C中&#xff0c;我们可以使用C风格字符串和string类来处理字符串操作。本篇学习笔记将详细介绍字符串的相关知识。 &#x1f4d6; 1 C风格字符串 ✨ C风格字符串初始化 C风格字符…

什么是EMC存储 Clarrion存储的cache dirty或者cache lost(CACD)?

CACD是Cant assign, Cache Dirty的缩写&#xff0c;DELL EMC的专业术语。 在开始之前&#xff0c;先介绍下cache dirty的概念&#xff0c;朴素的语言就是有了脏数据&#xff0c;脏数据当然就是不能使用的数据了。为什么数据会脏呢&#xff1f;先从存储的基本概念聊起来。 为了加…

PoseiSwap 将向 Zepoch 节点持有者发放新一轮空投,生态启动在即

目前&#xff0c;随着各类 Layer2 空投不断内卷&#xff0c;越来越多的用户疲于参与其中&#xff08;参与交互也很有可能难以获得空投资格&#xff09;。Nautilus Chain 作为目前模块化 Layer3 架构链&#xff0c;在初期就明确了空投计划&#xff0c;即所有上线的应用都将会拿出…

各类农作物分布遥感监测数据大全

最近收集整理了大量的农作物分布的遥感监测数据&#xff0c;废话不多说&#xff0c;分享给大家&#xff0c;后面会持续更新&#xff01;&#xff01; 数据查看地址&#xff1a; https://www.dilitanxianjia.com/%e9%81%a5%e6%84%9f%e8%a7%a3%e8%af%91%e5%90%8e%e6%88%90%e6%9…

LeetCode 0002. 两数相加

【LetMeFly】2.两数相加 力扣题目链接&#xff1a;https://leetcode.cn/problems/add-two-numbers/ 给你两个 非空 的链表&#xff0c;表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的&#xff0c;并且每个节点只能存储 一位 数字。 请你将两个数相加&#xff…

2016年全国硕士研究生入学统一考试管理类专业学位联考逻辑试题——纯享题目版

&#x1f3e0;个人主页&#xff1a;fo安方的博客✨ &#x1f482;个人简历&#xff1a;大家好&#xff0c;我是fo安方&#xff0c;考取过HCIE Cloud Computing、CCIE Security、CISP、RHCE、CCNP RS、PEST 3等证书。&#x1f433; &#x1f495;兴趣爱好&#xff1a;b站天天刷&…

华为OD机试真题 Java 实现【开心消消乐】【2023 B卷 100分】

目录 一、题目描述二、输入描述三、输出描述四、Java算法源码五、效果展示1、输入2、输出3、说明 一、题目描述 给定一个N行M列的二维矩阵&#xff0c;矩阵中每个位置的数字取值为0或1。矩阵示例如&#xff1a; 1 1 0 0 0 0 0 1 0 0 1 1 1 1 1 1 现需要将矩阵中所有的1进行反…