cmake常用命令(1)——函数相关

这篇具有很好参考价值的文章主要介绍了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、VAR3
    message("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() command
     break()
  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.文章来源地址https://www.toymoban.com/news/detail-642390.html

到了这里,关于cmake常用命令(1)——函数相关的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 平台相关常用接口、函数

     1、接口主程序 1)接口参数数据校验。jsonschema 2)异常处理。  3)单/多进程 + 协程  2、进程相关常用函数 3、日志模块  4、dockefile 构建镜像  docker build -t wood_detect:test .  5、Docker-compose.yml方法构建镜像并部署 6、重写yaml文件

    2024年02月12日
    浏览(35)
  • nginx常用命令与相关理论

    进入安装目录的sbin文件夹下: ./nginx 或 systemctl start nginx.service 启动 ./nginx -s stop 或systemctl stop nginx.service 或 kill -9/-15 pid 快速停止 ./nginx -s quit 处理完当前工作后停止 systemctl restart nginx.service 或 ./nginx -s reopen 重启 ./nginx -s reload 或 systemctl reload nginx 重新加载配置文件 ./nginx -v 查

    2024年03月13日
    浏览(42)
  • adb 常用命令---2:手机相关应用列表

    命令行参数列表 查看系统应用 💗 查看第三方应用 💗 其他一系列命令🌟 查看某个包名中包含指定字符的应用 命令行参数列表 参数 含义 -l 将应用安装到保护目录 /mnt/asec -r 允许覆盖安装 -t 允许安装 AndroidManifest.xml 里 application 指定android:testOnly=\\\"true\\\"的应用 -s 将应用安装到

    2024年02月09日
    浏览(35)
  • 【Linux】与磁盘相关的常用命令(自用)

    本文将详细介绍以下几个常用的命令:df、du、fdisk、mkfs、lsblk、mount、umount和parted。 常用的磁盘相关命令: df :用于显示文件系统的磁盘空间使用情况。 df :显示所有挂载的文件系统的磁盘使用情况。 df -h :以人类可读的格式显示磁盘使用情况,以便更易于理解。 df -i :显

    2024年02月11日
    浏览(33)
  • 熟悉常用的IP相关命令-新版(2)

    目录 1.查看实验编址表 2.配置PC1的IP地址 3.配置PC2的IP地址 4.配置路由器R1接口IP地址 5.验证路由器R1配置结果 6.配置路由器R1接口IP地址 7.验证路由器R1的IP配置结果 8.查看路由器R1配置信息 9.测试路由器R1与PC间的连通性 10.测试PC-1与PC-2间的连通性 11.保存 本实验模拟简单的企业

    2024年02月04日
    浏览(38)
  • JVM相关面试题及常用命令参数

    常用命令: jps:查看进程及其相关信息 jmap:用来生成dump文件和查看堆相关的各类信息的命令 jstat:查看jvm运行时的状态信息 jstack:查看jvm线程快照的命令 jinfo:查看jvm参数和动态修改部分jvm参数 常用参数: -Xms:初始化堆大小 -Xmx:最大堆大小 -Xmn:新生代的内存空间大小

    2024年03月12日
    浏览(82)
  • Git仓库的创建、常用命令、如何在 Git 中忽略文件提交以及 .gitignore 文件的作用和相关内容

    Git 仓库是用来存储版本控制信息的地方,为我们提供了快速便捷的代码管理方式。它可以包含文件、文件夹、历史记录、元数据等。在 Git 中,仓库通常分为两种:本地仓库和远程仓库。 如果你想分享你的代码库,并且希望团队中的其他成员可以跟踪你的进度和变化,你可以

    2024年02月02日
    浏览(47)
  • centos升级cmake之相关问题解决

    1. yum安装(仓库默认版本) 2. 安装高版本cmake 2.1 一开始下载的是cmake-xxx.zip,在 ./bootstrap 一直会报错“ missing terminating \\\" character” ,后来搜到,zip好像是针对windows的,linux需要tar.gz。 2.2 下载并安装cmake 2.3 更改权限 bootstrap文件默认没有执行权限,直接执行会报错“ bash ./boots

    2024年02月10日
    浏览(44)
  • 【探索Linux】—— 强大的命令行工具 P.26(网络编程套接字基本概念—— socket编程接口 | socket编程接口相关函数详细介绍 )

    本文将深入探讨使用套接字进行网络通信的基本步骤,包括创建套接字、绑定地址、监听连接(对于服务器端)、连接远程主机(对于客户端)、以及发送和接收数据等操作。套接字编程涉及一系列系统调用和函数,如 socket() 、 bind() 、 listen() 、 connect() 、 send() 、 recv() 等。

    2024年03月10日
    浏览(84)
  • 【C语言_文件_进程_进程间通讯 常用函数/命令 + 实例】.md_update:23/10/27

    getpid(); fork(); vfork(); //_t 一律返回的是int //获取进程ID 就是pid pid_t getpid(void); //fork创建子进程 pid_t fork(void); //这里返回的是的pid = 0 就是子进程,pid 0 就是父进程; //所以可以通过判断pid的值,来区别父子进程需要执行的代码; //注意fork开辟的子进程,没有等待一说,父子进

    2024年02月07日
    浏览(45)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包