cmake常用命令(1)——函数相关
一、function/endfunction
cmake中的函数与其他语言相似,表示一个命令集,可以被重复调用。形式如下:
function(<name> [<arg1> ...])<commands>
endfunction()
function:表示函数开始
<name>:函数名
<arg1> ...:表示参数与name用空格分隔,多个参数间用空格分隔,可省略。
<commands>:表示命令集。
enfunction:表示函数结束。endfunction实际形式为:
endfunction([<name>])
其中<name>可以省略,如果写必须与function的<name>完全一致。
1.调用
函数调用通过函数名(参数 )的形式调用,函数名不区分大小写,但是强烈建议与原函数名保持一致。
如对于函数:
#function mult arg
function(print2 arg num)message("function test argument " ${arg} " " ${num})
endfunction()
调用如下:
print2(1 2)
则打印内容如下:
function test argument 1 2
此外在3.18版本开始:可以通过cmake_language(CALL ...)的方式调用函数。
cmake_language(CALL print2 1 2)
2.参数
首先前面提到过,函数的参数是以空格分隔的。
其次,对于函数体内的<command>中想要使用参数,则可以使用${argname}的方式获取参数值。
除此之外,还提供了ARGC获取参数的数量,以及ARGV0, ARGV1, ARGV2...这样通用的形式获取参数内容,如果ARGV#的值(#)超过实际参数值,则忽略此参数引用,想要避免则需要根据ARGC进行判断。
最后,提供ARGV保存所有参数,ARGN用于获取所有预期参数之外的所有参数值。比如有三个参数1,3,5,而实际只是用了ARGV0,那么ARGN则表示35两个参数的合并值。
实际上ARGV#的方式对于不可变参数使用效果一般,但是对于不可变参数则能起到更好的效果(因为没别的方法获取参数)。
以下是一些函数使用的例子:
#function no arg
function(print1)message("function test no argument")
endfunction()
print1()
#print content:
#function test no argument#function mult arg
function(print2 arg num)message("function test argument " ${arg} " " ${num})
endfunction()
print2(1 2)
cmake_language(CALL print2 1 2)
#print content:
#function test argument 1 2
#function test argument 1 2#function argc argv
#可以通过ARGC获取当前参数总数
#既可以通过参数名,也可以通过ARGV#获取第几个参数,以及ARGN获取声明参数之后的实参
function(print3 var1 var2 )message("function test variable argument " ${ARGC} " " ${ARGV0} " " ${ARGV1} " " ${ARGN})
endfunction()print3(1 5 8 5)
#function test variable argument 4 1 5 85
#传入1,5对应var1 var2,而8和5则被放到ARGN#function select arg
#可变参数则必须ARGV#访问参数。
#ARGN表示已用参数之外的所有参数
function(print4 ...)message("function test variable argument " ${ARGC} " " ${ARGV0} " " ${ARGV1} " " ${ARGV2} " " ${ARGN})
endfunction()print4(1 11 11 11)
#function test variable argument 4 1 11 111111
#此处比较坑的是认为可变参数...表示一位形参,所以后面三个11都被放到ARGN中,而不是所有参数都放到ARGN中
其中ARGN的理解稍微复杂一点。
函数参数使用大坑:
对于函数:
function(printArg arg1 arg2)message("arg1:" ${arg1})message("arg2:" ${arg2})
endfunction()
set(VAR1 "hello")
set(VAR2 "world")
正确使用方式如下:
#正确使用
printArg(${VAR1} ${VAR2})
#print:
#arg1:hello
#arg2:world
而有时,不小心直接传入了变量名,则会得到错误的结果。
#错误使用
printArg(VAR1 VAR2)
#print:
#arg1:VAR1
#arg2:VAR2
除此之外,这样的结果也会造成理解上的错误:
function(printArg arg1 arg2)message("arg1:" ${arg1})message("arg2:" ${arg2})#导致理解为 ${arg#}也可以获取实参名进行父租用与变量设置,实际本质都是对VAR1这个变量名进行设置set(${arg1} 18 PARENT_SCOPE)set(${arg2} 20)
endfunction()
3.变量设置与作用域
对于函数体内的变量设置是通过set命令设置的:
set(<variable> <value>... [PARENT_SCOPE])¶
<variable>:变量名
<value>:变量值,可以是多个值
PARENT_SCOPE:父作用域。
当使用set命令时:
- 如果没有指定变量值,则表示变量设为未设置状态,与unset()命令效果相同。
- 如果指定了变量值,则更新变量的值。
对于PARENT_SCOPE参数,则用于表示当前操作的变量是属于父作用域的,而不会影响到当前作用域的变量。同时,PARENT_SCOPE设置的变量并不会生效于当前作用域。
set(VAR1 "hello")
set(VAR2 "world")#function variable arg
#通过set(PARENT_SCOPE)能够设置父目录的变量,而不影响当前目录的变量内容,而不是说类似于引用的方式。
function(print5 g0 arg1)message("function test variable argument " ${g0} " " ${arg1})set(VAR1 "test" PARENT_SCOPE)set(VAR2 PARENT_SCOPE)message("function test variable argument " ${VAR1} " " ${VAR2})#设置局部变量set(VAR1 "test11")#局部变量优先生效,而父变量未生效message("function test variable argument " ${VAR1} " " ${VAR2})# return(PROPAGATE ${g0} ${arg1})
endfunction()#变量传参需要传值
print5(${VAR1} ${VAR2})
message("print5:function test variable argument " ${VAR1} " " ${VAR2})
#print content:
#function test variable argument hello world
#function test variable argument hello world
#function test variable argument test11 world
#print5:function test variable argument test
二、return
表示从文件、目录或函数中返回。本节只是讲述并验证其在函数中的使用。
return([PROPAGATE <var-name>...])
参数的行为由策略CMP0140控制,除非策略被设置未NEW否则所有参数都会被忽略。
对于3.25版本以前return没有参数,仅仅用于终止当前函数。
1.PROPAGATE
自3.25版本引入,可省略。
主要作用是返回变量覆盖父作用域的变量值,类似于set(variable value PARENT_SCOPE)。
下面例子中VAR3的用法属于常规用法,而VAR1和VAR2则是通过传参时传入变量名(而非变量值),达到一种引用参数的效果。但是这里实际上与常规函数调用方式有所区别,还是少用比较好。
cmake_minimum_required(VERSION 3.25)
project(cmdTest_return)#首先,return可以不带参数,用于函数返回调用点。
#其次,return可以带PROPAGATE参数,用于返回更新父作用域的变量。
#但是这里实际上与正常函数调用方式有区别(实参传入的是变量名,而非值,后续操作的也是变量名),所以不建议这样使用。
#这里可以看到通过return返回的本质是在函数作用域修改父作用域的同名变量,再通过return返回变量名,从而更新父作用域的变量值
#不如直接使用set PARENT_SCOPE
set(VAR1 "hello")
set(VAR2 "world")
set(VAR3 "you")
function(returnTest ret_val1 ret_val2)message("before set:" ${ret_val1})set(${ret_val1} "test")unset(${ret_val2})set(VAR3 "me")return(PROPAGATE ${ret_val1} ${ret_val2} VAR3)
endfunction()returnTest(VAR1 VAR2)
message("after set:" ${VAR1} " " ${VAR2} " " ${VAR3})#print:
#before set:VAR1
#after set:testme
三、block/endblock
block([SCOPE_FOR [POLICIES] [VARIABLES] ] [PROPAGATE <var-name>...])<commands>
endblock()
SCOPE_FOR
如果SCOPE_FOR [POLICIES] [VARIABLES]没有设置,则默认为SCOPE_FOR POLICIES VARIABLES。
block和endblock中间产生一个新的变量作用域(VARIABLES)或者策略作用域(POLICIES)。
cmake_minimum_required(VERSION 3.25)
project(cmdTest_return)set(VAR1 "hello")
set(VAR2 "world")
set(VAR3 "you")block(SCOPE_FOR VARIABLES)set(VAR1 "newVar1")set(VAR2 "newVar2" PARENT_SCOPE)#当前作用域的VAR1和父作用域的VAR2、VAR3message("in block var:" ${VAR1} " " ${VAR2} " " ${VAR3})
endblock()#VAR2被block中修改为newVar2
message("after set:" ${VAR1} " " ${VAR2} " " ${VAR3})
#print:
#in block var:newVar1 world you
#after set:hello newVar2 you
PROPAGATE
与return的参数含义相同,用于覆盖父作用域中同名变量的值。这里由于是在一开始就使用,所以实际上类似于引用参数。
set(VAR1 "hello")
set(VAR2 "world")
set(VAR3 "you")block(PROPAGATE VAR1 VAR2)#对VAR1和VAR2的修改会同步到父作用域message("in block var:" ${VAR1} " " ${VAR2} " " ${VAR3})set(VAR1 "newVar1")set(VAR2 "newVar2")#同时会在当前作用域立即生效message("in block var:" ${VAR1} " " ${VAR2} " " ${VAR3})
endblock()
message("after set:" ${VAR1} " " ${VAR2} " " ${VAR3})#print:
#in block var:hello world you
#in block var:newVar1 newVar2 you
#after set:newVar1 newVar2 you
可以明显看到:
- 修改是立即生效的(在当前作用域也生效),这是与使用set(PARENT_SCOPE)不同的。
- 修改会同步到父作用域,类似于引用参数。
用于流程中
当block用于循环命令如while(),foreach()时,break()和continue()命令也会生效。
while(TRUE)block()...# the break() command will terminate the while() commandbreak()endblock()
endwhile()
四、macro
macro(<name> [<arg1> ...])<commands>
endmacro()
macro与函数类似,命令格式和调用方式都是相同的,但是两者有着本质区别:
- 首先,macro会在调用处展开,而不像函数会进入函数体中,因此当在macro中使用return时,并不是回到macro的调用处,而是从macro的return直接返回(从其调用处的作用域返回)
- 其次,macro中的变量ARGV#等参数只是字符串,而非变量(函数中是变量),因此它们不能用于一些需要变量的场合:
if(ARGV1) # ARGV1 is not a variable
if(DEFINED ARGV2) # ARGV2 is not a variable
if(ARGC GREATER 2) # ARGC is not a variable
foreach(loop_var IN LISTS ARGN) # ARGN is not a variable
- 注意,如果在调用宏的作用域中有一个同名的变量,使用未引用的名称将使用现有变量而不是参数。
macro(bar)foreach(arg IN LISTS ARGN)<commands>endforeach()
endmacro()function(foo)bar(x y z)
endfunction()foo(a b c)
将循环a;b;c而不是x;y;z.
相关文章:
cmake常用命令(1)——函数相关
一、function/endfunction cmake中的函数与其他语言相似,表示一个命令集,可以被重复调用。形式如下: function(<name> [<arg1> ...])<commands> endfunction() function:表示函数开始 <name>…...
阿里三年功能测试的一些感悟
一、前言 功能测试是测试工程师的基础功,很多人功能测试还做不好,就想去做性能测试、自动化测试。很多人对功能测试的理解就是点点点,如何自己不用心去悟,去研究,那么你的职业生涯也就停留在点点点上了。在这里&#…...

React源码解析18(4)------ completeWork的工作流程【mount】
摘要 经过上一章,我们得到的FilberNode已经具有了child和return属性。一颗Filber树的结构已经展现出来了。 那我们最终是想在页面渲染真实的DOM。所以我们现在要在completeWork里,构建出一颗离屏的DOM树。 之前在说FilberNode的属性时,我们…...
Kafka: 详解、使用教程和示例
Kafka: 详细介绍、使用教程和示例 什么是 Kafka? Kafka 是一个分布式的流处理平台,最初由 LinkedIn 开发,现已成为 Apache 基金会的顶级项目。它以高吞吐量、可靠性和可扩展性而闻名,被广泛应用于实时数据传输、日志收集、事件处…...

【LeetCode周赛】LeetCode第358场周赛
LeetCode第358场周赛 数组中的最大数对和翻倍以链表形式表示的数字限制条件下元素之间的最小绝对差 数组中的最大数对和 给你一个下标从0开始的整数数组nums。请你从nums中找出和最大的一对数,且这两个数数位上最大的数字相等。 返回最大和,如果不存在满…...

Node.js学习笔记-04
这第九章也是个大重点 九、玩转进程 Node在选型时决定在V8引擎之上构建,也就意味着它的模型与浏览器类似。 本章关于进程的介绍和讨论将会解决如下两个问题: 单进程单线程并非完美,如今CPU基本均是多核的,真正的服务器…...

基于dbn+svr的交通流量预测,dbn详细原理
目录 背影 DBN神经网络的原理 DBN神经网络的定义 受限玻尔兹曼机(RBM) DBN+SVR的交通流量预测 基本结构 主要参数 数据 MATALB代码 结果图 展望 背影 DBN是一种深度学习神经网络,拥有提取特征,非监督学习的能力,是一种非常好的分类算法,本文将DBN+SVR用于交通流量预测…...

【第一阶段】kotlin中反引号中的函数名特点
在kotlin中可以直接中文定义函数,使用反引号进行调用 eg: fun main() {2023年8月9日定义的函数(5) }private fun 2023年8月9日定义的函数(num:Int){println("反引号的用法$num") }执行结果 在Java中is,in可以定义方法,但是在kotlin中is,in是…...

数据分析-python学习 (1)numpy相关
内容为:https://juejin.cn/book/7240731597035864121的学习笔记 导包 import numpy as np numpy数组创建 创建全0数组,正态分布、随机数组等就不说了,提供了相应的方法通过已有数据创建有两种 arr1np.array([1,2,3,4,5]) 或者datanp.loadt…...
数据库的游标
数据库的游标(Cursor)是用于在数据库中进行数据操作的一个控制结构。它类似于在编程语言中使用的指针或迭代器,用于遍历数据库结果集并在结果集上执行各种操作。 游标允许我们在数据库查询的结果集中逐行移动,并对每一行执行特定…...

【设计模式】前端控制器模式
前端控制器模式(Front Controller Pattern)是用来提供一个集中的请求处理机制,所有的请求都将由一个单一的处理程序处理。该处理程序可以做认证/授权/记录日志,或者跟踪请求,然后把请求传给相应的处理程序。以下是这种…...

SQL | 过滤数据
4-过滤数据 4.1-使用WHERE子句 数据根据 WHERE 子句中指定的搜索条件进行过滤。WHERE 子句在表名( FROM 子句)之后给出。 select prod_name,prod_price from products where prod_price 3.49; 上述语句查询价格为3.49的行,然后输出名字和…...

【力扣每日一题】2023.8.13 合并两个有序数组
目录 题目: 示例: 分析: 代码: 题目: 示例: 分析: 题目给我们两个升序数组,让我们合并它们,要求合并之后仍然是升序,并且这个合并操作是在数组1原地修改…...

数据结构篇七:排序
文章目录 前言1.插入排序1.1 基本思想1.2 代码实现1.3 特性总结 2.希尔排序2.1 基本思想2.2 代码实现2.3 特性总结 3. 选择排序3.1 基本思想3.2 代码实现3.3 特性总结 4. 堆排序4.1 基本思想4.2 代码实现4.3 特性总结 5. 冒泡排序5.1 基本思想5.2 代码实现5.3 特性总结 6. 快速…...
Vue组件的边界情况
01.$root; 访问组件的根实例;用的不多,基本上在vuex上进行数据操作; 02.$parent/$children; 可以获得父组件或者子组件上边的数据;一般不建议使用$parent,因为如果获取这个值进行修改的话,也会更改父组件上…...
less、sass的使用及其区别
CSS预处理器 CSS 预处理器是一种扩展了原生 CSS 的工具,它们添加了一些编程语言的特性,以便更有效地编写、组织和维护样式代码。预处理器允许开发者使用变量、嵌套、函数、混合等功能,从而使 CSS 更具可读性、可维护性和重用性,特…...

[保研/考研机试] 猫狗收容所 C++实现
题目描述: 输入: 第一个是n,它代表操作序列的次数。接下来是n行,每行有两个值m和t,分别代表题目中操作的两个元素。 输出: 按顺序输出收养动物的序列,编号之间以空格间隔。 源代码ÿ…...

Kotlin 基础教程一
Kotlin 基本数据类型 Java | Kotlin byte Byte short Short int Int long Long float Float double Double boolean Boolean c…...

数据结构笔记--前缀树的实现
1--前缀树的实现 前缀树的每一个节点拥有三个成员变量,pass表示有多少个字符串经过该节点,end表示有多少个字符串以该节点结尾,nexts表示该字符串可以走向哪些节点; #include <iostream> #include <unordered_map>str…...
C/C++时间获取函数
time.h包含C/C中用于获取时间,和时间转换方面的函数。 1、time() 函数 time_t time(time_t *seconds) 返回自(1970-01-01 00:00:00 UTC)起经过的时间,以秒为单位。如果 seconds 不为空,则返回值也存储在变量 seconds …...

stm32G473的flash模式是单bank还是双bank?
今天突然有人stm32G473的flash模式是单bank还是双bank?由于时间太久,我真忘记了。搜搜发现,还真有人和我一样。见下面的链接:https://shequ.stmicroelectronics.cn/forum.php?modviewthread&tid644563 根据STM32G4系列参考手…...
脑机新手指南(八):OpenBCI_GUI:从环境搭建到数据可视化(下)
一、数据处理与分析实战 (一)实时滤波与参数调整 基础滤波操作 60Hz 工频滤波:勾选界面右侧 “60Hz” 复选框,可有效抑制电网干扰(适用于北美地区,欧洲用户可调整为 50Hz)。 平滑处理&…...

通过Wrangler CLI在worker中创建数据库和表
官方使用文档:Getting started Cloudflare D1 docs 创建数据库 在命令行中执行完成之后,会在本地和远程创建数据库: npx wranglerlatest d1 create prod-d1-tutorial 在cf中就可以看到数据库: 现在,您的Cloudfla…...

全球首个30米分辨率湿地数据集(2000—2022)
数据简介 今天我们分享的数据是全球30米分辨率湿地数据集,包含8种湿地亚类,该数据以0.5X0.5的瓦片存储,我们整理了所有属于中国的瓦片名称与其对应省份,方便大家研究使用。 该数据集作为全球首个30米分辨率、覆盖2000–2022年时间…...

CocosCreator 之 JavaScript/TypeScript和Java的相互交互
引擎版本: 3.8.1 语言: JavaScript/TypeScript、C、Java 环境:Window 参考:Java原生反射机制 您好,我是鹤九日! 回顾 在上篇文章中:CocosCreator Android项目接入UnityAds 广告SDK。 我们简单讲…...
【学习笔记】深入理解Java虚拟机学习笔记——第4章 虚拟机性能监控,故障处理工具
第2章 虚拟机性能监控,故障处理工具 4.1 概述 略 4.2 基础故障处理工具 4.2.1 jps:虚拟机进程状况工具 命令:jps [options] [hostid] 功能:本地虚拟机进程显示进程ID(与ps相同),可同时显示主类&#x…...
今日学习:Spring线程池|并发修改异常|链路丢失|登录续期|VIP过期策略|数值类缓存
文章目录 优雅版线程池ThreadPoolTaskExecutor和ThreadPoolTaskExecutor的装饰器并发修改异常并发修改异常简介实现机制设计原因及意义 使用线程池造成的链路丢失问题线程池导致的链路丢失问题发生原因 常见解决方法更好的解决方法设计精妙之处 登录续期登录续期常见实现方式特…...

关键领域软件测试的突围之路:如何破解安全与效率的平衡难题
在数字化浪潮席卷全球的今天,软件系统已成为国家关键领域的核心战斗力。不同于普通商业软件,这些承载着国家安全使命的软件系统面临着前所未有的质量挑战——如何在确保绝对安全的前提下,实现高效测试与快速迭代?这一命题正考验着…...
智能AI电话机器人系统的识别能力现状与发展水平
一、引言 随着人工智能技术的飞速发展,AI电话机器人系统已经从简单的自动应答工具演变为具备复杂交互能力的智能助手。这类系统结合了语音识别、自然语言处理、情感计算和机器学习等多项前沿技术,在客户服务、营销推广、信息查询等领域发挥着越来越重要…...

push [特殊字符] present
push 🆚 present 前言present和dismiss特点代码演示 push和pop特点代码演示 前言 在 iOS 开发中,push 和 present 是两种不同的视图控制器切换方式,它们有着显著的区别。 present和dismiss 特点 在当前控制器上方新建视图层级需要手动调用…...