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.

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/31446.shtml

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

相关文章

Nexus npm仓库如何设置同步频率

在 Nexus Repository Manager 中&#xff0c;设置同步频率可以确保你的代理或镜像仓库能够及时获取外部仓库中的最新包。以下是设置同步频率的一般步骤&#xff1a; 登录到 Nexus 管理界面&#xff1a;使用管理员账号登录到 Nexus Repository Manager 的 Web 管理界面。 选择仓…

SpringBoot复习:(24)DeferredImportSelector

功能&#xff1a; 定一一个字符串数组&#xff0c;每个元素都是一个类的全限定名&#xff08;包名类名&#xff09;&#xff0c;把这些类的实例注册到Spring 容器。 一、定义要注册的类&#xff1a; package cn.edu.tju.service;import java.util.Arrays; import java.util.Li…

Android11 设置备用DNS

在Android11 版本的rom 产品开发过程中&#xff0c;遇到一个问题&#xff0c;发现分配的DNS不可用的情况&#xff0c;所以需要设置备用DNS。 直接上代码 //frameworks/base/services/core/java/com/android/server/ConnectivityService //ConnectivityService.java --> //…

【脚踢数据结构】链表(1)

(꒪ꇴ꒪ )&#xff0c;Hello我是祐言QAQ我的博客主页&#xff1a;C/C语言,Linux基础,ARM开发板&#xff0c;软件配置等领域博主&#x1f30d;快上&#x1f698;&#xff0c;一起学习&#xff0c;让我们成为一个强大的攻城狮&#xff01;送给自己和读者的一句鸡汤&#x1f914;&…

机器学习基础之《特征工程(3)—特征预处理》

一、什么是特征预处理 通过一些转换函数将特征数据转换成更加适合算法模型的特征数据过程 处理前&#xff0c;特征值是数值&#xff0c;处理后&#xff0c;进行了特征缩放 1、包含内容 数值型数据的无量纲化&#xff1a; 归一化 标准化 2、特征预处理API sklearn.preproces…

什么是训练数据?

算法从数据中学习。算法从得到的训练数据中找到关系&#xff0c;形成理解&#xff0c;做出决策&#xff0c;并评估信心。训练数据越好&#xff0c;模型的表现就越好。 实际上&#xff0c;与算法本身一样&#xff0c;训练数据的质量和数量与数据项目的成功有很大关系。 现在&…

Java项目作业~ 通过html+Servlet+MyBatis,完成站点信息的添加功能

需求&#xff1a; 通过htmlServletMyBatis&#xff0c;完成站点信息的添加功能。 以下是站点表的建表语句&#xff1a; CREATE TABLE websites (id int(11) NOT NULL AUTO_INCREMENT,name char(20) NOT NULL DEFAULT COMMENT 站点名称,url varchar(255) NOT NULL DEFAULT ,…

html2canvas截图生成图片并保存到本地的解决方案

html2canvas截图生成图片并保存到本地的解决方案 一、构建HTML容器二、html2canvas截图封装函数避坑指南1.尺寸过大而无法成功生成图片 html2canvas是一款JavaScript插件&#xff0c;能够将网页上的HTML元素转化为Canvas对象&#xff0c;从而可以将网页截图输出为图片或者PDF文…

Go学习第八天

签名 func (a *Account) Sign(message []byte) ([]byte, error) {hash : crypto.Keccak256Hash(message)signature, err : crypto.Sign(hash.Bytes(), a.privateKeyECDSA)if err ! nil {log.Fatal(err)}signMsg : []byte(hexutil.Encode(signature))return signMsg, err }验签…

CentOS7 安装远程桌面

换源 设置镜像源为清华源&#xff1a; sudo sed -e s|^mirrorlist|#mirrorlist|g \-e s|^#baseurlhttp://mirror.centos.org/centos|baseurlhttps://mirrors.tuna.tsinghua.edu.cn/centos|g \-i.bak \/etc/yum.repos.d/CentOS-*.repo详见 https://mirrors.tuna.tsinghua.edu.…

函数与方法有区别?

有区别&#xff0c;当然是有区别。 不管是java、rust还是go&#xff0c;他们都是不一样的。 先看定义&#xff1a; 函数&#xff08;Function&#xff09; 是一段独立的代码块&#xff0c;用于执行特定的任务。函数可以被多次调用&#xff0c;并且可以接受参数和返回结果。在G…

尼科彻斯定理

目录 1.题目概述 2.题解 思路分析 具体实现 1.题目概述 验证尼科彻斯定理&#xff0c;即&#xff1a;任何一个整数m的立方都可以写成m个连续奇数之和。 例如&#xff1a; 1^31 2^335 3^37911 4^313151719 输入一个正整数m&#xff08;m≤100&#xff09;&#xff0c;将…

pytorch 训练过程内存泄露/显存泄露debug记录:dataloader和dataset导致的泄露

背景 微调 mask-rcnn 代码&#xff0c;用的是 torchvision.models.detection.maskrcnn_resnet50_fpn 代码&#xff0c;根据该代码的注释&#xff0c;输入应该是&#xff1a; images, targetsNone (List[Tensor], Optional[List[Dict[str, Tensor]]]) -> Tuple[Dict[str, Te…

【大数据】-- 部署 Flink kubernetes operator

目录 1.说明 1.1 版本 1.2 kubernetes 环境 1.3 参考 2.安装步骤 2.1 安装本地 kubernetes 环境

Oracle 使用 CONNECT_BY_ROOT 解锁层次结构洞察:在 SQL 中导航数据关系

CONNECT_BY_ROOT 是一个在 Oracle 数据库中使用的特殊函数&#xff0c;它通常用于在层次查询中获取根节点的值。在使用 CONNECT BY 子句进行层次查询时&#xff0c;通过 CONNECT_BY_ROOT 函数&#xff0c;你可以在每一行中获取根节点的值&#xff0c;而不仅仅是当前行的值。 假…

Vue3 实现产品图片放大器

Vue3 实现类似淘宝、京东产品详情图片放大器功能 环境&#xff1a;vue3tsvite 1.创建picShow.vue组件 <script lang"ts" setup> import {ref, computed} from vue import {useMouseInElement} from vueuse/core/*获取父组件的传值*/ defineProps<{images:…

从支付或退款之回调处理的设计,看一看抽象类的使用场景

一、背景 抽象类&#xff0c;包含抽象方法和实例方法&#xff0c;抽象方法待继承类去实例化&#xff0c;正是利用该特性&#xff0c;以满足不同支付渠道的差异化需求。 我们在做多渠道支付的时候&#xff0c;接收支付或退款的回调报文&#xff0c;然后去处理。这就意味着&…

【python 深度学习】解决遇到的问题

目录 一、RuntimeError: module compiled against API version 0xc but this version of numpy is 0xb 二、AttributeError: module ‘tensorflow’ has no attribute ‘flags’ 三、conda 更新 Please update conda by running 四、to search for alternate channels that…

Tomcat部署SpringBoot项目

1.修改打包方式 pom.xml 里 加上 <packaging>war</packaging>2.移除内嵌的Tomcat <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-tomcat</artifactId><scope>provided</scope…

Java-jar和war包的区别

jar包和war包的区别&#xff1a; 1、war是一个web模块&#xff0c;其中需要包括WEB-INF&#xff0c;是可以直接运行的WEB模块&#xff1b;jar一般只是包括一些class文件&#xff0c;在声明了Main_class之后是可以用java命令运行的。 2、war包是做好一个web应用后&#xff0c;通…