【CMake 入门与进阶(10)】 CMake如何定义函数,内部参数及作用域(附代码)

news2024/12/28 5:35:01

        前几篇已经学习了cmake 中常用的命令 command、变量 variable ,相信大家已经掌握了 cmake 工具的基本使用方法;本文我们进一步学习 cmake,看看 cmake 还有哪些东西。

定义函数

        在 cmake 中我们也可以定义函数,cmake 提供了 function()命令用于定义一个函数,使用方法如下所示:

function(<name> [arg1 [arg2 [arg3 ...]]])
 command1(args ...)
 command2(args ...)
 ...
endfunction(<name>)

        endfunction 括号中的可写可不写,如果写了,就必须和 function 括号中的一致。

        1、基本使用方法

        第一个参数 name 表示函数的名字,arg1、arg2…表示传递给函数的参数。调用函数的方法其实就跟使用命令一样,一个简单地示例如下所示:

# function 函数测试
# 函数名: xyz
function(xyz arg1 arg2)
    message("${arg1} ${arg2}")
endfunction()

# 调用函数
xyz(Hello World)

        打印信息如下:

2、 使用 return()命令

        在 function()函数中也可以使用 C 语言中的 return 语句退出函数,如下所示:

# function 函数测试
# 函数名: xyz
function(xyz)
    message(Hello)
    return() # 退出函数
    message(World)
endfunction()

# 调用函数
xyz()

        执行结果如下:

         只打印了 Hello,并没有打印 World,说明 return()命令是生效的,执行 return()命令之后就已经退出当前函数了,所以并不会打印 World。

        但是需要注意的是,return 并不可以用于返回参数。

3、可变参函数

        在 cmake 中,调用函数时实际传入的参数个数不需要等于函数定义的参数个数(甚至函数定义时,参数个数为 0),但是实际传入的参数个数必须大于等于函数定义的参数个数,如下所示:

# function 函数测试
# 函数名: xyz
function(xyz arg1)
    message(${arg1})
endfunction()

# 调用函数
xyz(Hello World China)

        函数 xyz 定义时只有一个参数,但是实际调用时我们传入了 3 个参数,注意这并不会报错,是符合 function()语法规则的,会正常执行,打印信息如下:

         从打印信息可知,message()命令打印出了调用者传入的第一个参数,也就是 Hello。

        这种设计有什么用途呢?正如我们的标题所言,这种设计可用于实现可变参函数(与 C 语言中的可变参数函数概念相同);但是有个问题,就如上例中所示,用户传入了 3 个参数,但是函数定义时并没有定义这些形参,函数中如何引用到第二个参数 World 以及第三个参数 China 呢?其实 cmake 早就为大家考虑到了,并给出了相应的解决方案,就是接下来向大家介绍的内部变量。

4、函数的内部变量

        function()函数中可以使用内部变量,所谓函数的内部变量,指的就是在函数内部使用的内置变量,这些内部变量如下所示:

函数中的内部变量说明
ARGVXX 是一个数字,譬如 ARGV0、ARGV1、ARGV2、ARGV3…,这些变量表示函数的参数,ARGV0 为第一个参数、ARGV1 位第二个参数,依次类推!
ARGV实际调用时传入的参数会存放在 ARGV 变量中(如果是多个参数,那它就是一个参数列表)
ARGN假如定义函数时参数为 2 个,实际调用时传入了 4 个,则 ARGN 存放了剩下的 2 个参数(如果是多个参数,那它也是一个参数列表)
ARGC调用函数时,实际传入的参数个数

        试验一下:

# function 函数测试
# 函数名: xyz
function(xyz arg1 arg2)
     message("ARGC: ${ARGC}")
     message("ARGV: ${ARGV}")
     message("ARGN: ${ARGN}")
     message("ARGV0: ${ARGV0}")
     message("ARGV1: ${ARGV1}")

     # 循环打印出各个参数
     set(i 0)
     foreach(loop ${ARGV})
         message("arg${i}: " ${loop})
         math(EXPR i "${i} + 1")
     endforeach()
endfunction()

# 调用函数
xyz(A B C D E F G)

        执行结果如下“

 5、函数的作用域

        在 cmake 中,通过 function()命令定义的函数类似于一个自定义命令(实际上并不是),当然,事实上,cmake 提供了自定义命令的方式,譬如通过 add_custom_command()来实现,如果大家有兴趣,可以自己去学习下,笔者便不再进行介绍了。 使用 function()定义的函数,我们需要对它的使用范围进行一个简单地了解,譬如有如下工程目录结构:

├── build
├── CMakeLists.txt
├── hello
  ├── CMakeLists.txt

        我们在顶层目录下定义了一个函数 xyz,顶层 CMakeLists.txt 源码内容如下:

# CMakeLists.txt
cmake_minimum_required("VERSION" "3.5")
project(HELLO VERSION 1.1.0)

# 函数名: xyz
function(xyz)
    message("Hello World!")
endfunction()

# 加载子源码
add_subdirectory(hello)

        接着我们在子源码中调用 xyz()函数,hello 目录下的 CMakeLists.txt 如下所示:

# hello 目录下的 CMakeLists.txt
message("这是子源码")
xyz() # 调用 xyz()函数

        大家觉得这样子可以调用成功吗?事实上,这是没问题的,父源码中定义的函数、在子源码中是可以调用的,打印信息如下:

         那反过来,子源码中定义的函数,在父源码中可以使用吗?我们来进行测试,顶层 CMakeLists.txt 源码内容如下:

# CMakeLists.txt
cmake_minimum_required("VERSION" "3.5")
project(HELLO VERSION 1.1.0) #设置工程版本号为 1.1.0

# 加载子源码
add_subdirectory(hello)
message("这是父源码")
xyz()

        在父源码中调用 xyz()函数,在子源码中定义 xyz()函数,如下所示:

message("这是子源码")
# 函数名: xyz
function(xyz)
    message("Hello World!")
endfunction()

        进入到 build 目录执行 cmake,如下所示:

         事实证明,这样也是可以的,说明通过 function()定义的函数它的使用范围是全局的,并不局限于当前源码、可以在其子源码或者父源码中被使用。

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

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

相关文章

基于图神经网络的切片级漏洞检测及解释方法

源自&#xff1a;软件学报 作者&#xff1a;胡雨涛 王溯远 吴月明 邹德清 李文科 金海 摘 要 随着软件的复杂程度越来越高, 对漏洞检测的研究需求也日益增大. 软件漏洞的迅速发现和修补, 可以将漏洞带来的损失降到最低. 基于深度学习的漏洞检测方法作为目前新兴的检测手…

云原生之深入解析Kubernetes中Kubectl Top是如何进行资源监控

一、Kubectl top 的使用 kubectl top 是基础命令,但是需要部署配套的组件才能获取到监控值:1.8 以下:部署 heapter;1.8 以上:部署 metric-server;kubectl top node:查看 node 的使用情况:kubectl top pod:查看 pod 的使用情况:不指定 pod 名称,则显示命名空间下所有…

TSception:从EEG中捕获时间动态和空间不对称性用于情绪识别

TSception&#xff1a;从EEG中捕获时间动态和空间不对称性用于情绪识别&#xff08;论文复现&#xff09; 摘要模型结构代码实现写在最后 **这是一篇代码复现&#xff0c;原文通过Pytorch实现&#xff0c;本文中使用Keras对该结构进行复现。**该论文发表在IEEE Transactions on…

【Python 随练】古典问题:兔子繁殖问题

题目&#xff1a; 古典问题&#xff1a;有一对兔子&#xff0c;从出生后第 3 个月起每个月都生一对兔子&#xff0c;小兔子长到第三个月&#xff0c;后每个月又生一对兔子&#xff0c;假如兔子都不死&#xff0c;问每个月的兔子总数为多少&#xff1f; 简介&#xff1a; 在本…

三、DSMP/OLS等夜间灯光数据贫困地区识别——MPI和灯光指数拟合、误差分析

一、前言 当我们准备好MPI和灯光指数(包括总灯光指数和平均灯光指数)之后,接下来主要的过程就是通过将MPI和灯光指数拟合,构建多维度指数估算模型,这里我解释一下前文中的MPI计算过程,其实利用熵值法确定指标权重,并通过各 指 标 归 一 化 数 值 乘 以 对 应 的 权 重 …

UG NX二次开发(C#)-用UFun函数导出图像(Image)

文章目录 1、前言2、在UG NX中交互导出图像的操作2.1 打开一个三维模型2.2 打开导出图像的界面3、采用UFun函数来实现3.1 搜索image的方法3.2 帮助说明3.3 应用环境3.4 方法应用4、后记1、前言 在UG NX二次开发过程中,三维CAD模型有时需要导出为图像,如.png、.jpg、.bmp、.t…

类与封装的概念

类通常分为以下两个部分 类的实现细节 类的使用方式 当使用类时&#xff0c;不需要关心其实现细节 当创建类时&#xff0c;才需要考虑其内部实现细节 封装的基本概念 根据经验&#xff1a;并不是类的每个属性都是对外公开的 如&#xff1a;女孩子不希望外人知道自己的体重…

【系统开发】尚硅谷 - 谷粒商城项目笔记(二):搭建分布式系统基本环境

文章目录 搭建分布式系统基本环境引入spring-cloud-alibaba依赖Nacos作为注册中心Feign 远程调用Nacos作为配置中心Nacos配置中心进阶Nacos加载多配置集GateWay网关网关路由分发解释 搭建分布式系统基本环境 引入spring-cloud-alibaba依赖 在common的pom.xml中加入 &#xff…

Socket网络通信过程 与 IO多路复用原理

0、引言 本文主要讲述Socket网络编程的基本知识、IO多路复用的select、poll、epoll实现原理以及比较&#xff0c;并解答了一些socket建立连接、阻塞的常见问题。 1、什么是Socket、网络通信的过程 Socket 的中文名叫作插口&#xff0c;事实上&#xff0c;双方要进行网络通信前…

HTML(一)

一.HTML的标准结构 <!doctype html> 声明文档类型<html> HTML根标签<head> 头标签<title></title> 标题标签</head><body> 主题标签...</body></html> 二.标签介绍 2.1 段落标签 1.注释标签 <!--我是一个注释--…

送外卖适合什么蓝牙耳机,推荐几款适合户外佩戴的骨传导耳机

骨传导耳机&#xff0c;是通过震动的方式将声音转化为不同频率的机械振动&#xff0c;由于不需要通过耳膜就可以听到声音&#xff0c;骨传导耳机在保留传统耳机的优点的基础上&#xff0c;解决了传统耳机不能在开放环境中使用的问题。那么在骨传导耳机中&#xff0c;究竟有哪些…

MobaXterm 常用设置

MobaXterm 是用于远程计算的工具箱&#xff0c;作为一个 Windows 应用程序&#xff0c;它为程序员、网站管理员、IT管理员和几乎所有需要以更简单的方式处理远程工作的用户量身定制了大量功能。MobaXterm 提供了所有重要的远程网络工具(SSH, X11, RDP, VNC, FTP, MOSH&#xff…

消息队列常见问题整理

前言 消息队列&#xff08;Message Queue&#xff09;&#xff0c;从广义上讲是一种消息队列服务中间件&#xff0c;提供一套完整的信息生产、传递、消费的软件系统。 消息队列所涵盖的功能远不止于队列&#xff08;Queue&#xff09;&#xff0c;其本质是两个进程传递信息的…

Java Web程序设计的学习

属于B/S结构、服务器软件&#xff1a;Apache Tomcat、 Web 项目 目录结构&#xff1a; 1.src目录&#xff1a;存放Java源文件 2.WebRoot目录&#xff1a; 存在两个子目录&#xff1a; META-INF目录 WEB-INF目录&#xff1a;&#xff08;lib目录&#xff1a;存放驱动…

Notepad++安装json插件

Notepad是Windows操作系统下的一套文本编辑器(软件版权许可证:GPL)&#xff0c;有完整的中文化接口及支持多国语言编写的功能(UTF8技术)。 Notepad功能比 Windows 中的Notepad(记事本)强大&#xff0c;除了可以用来制作一般的纯文字说明文件&#xff0c;也十分适合编写计算机程…

MySQL数据表:对数据的基础操作(增、删、查、改)以及运算符的讲解

目录 前言 一.增加数据 二.查询数据 2.1查询数据表中所有信息 2.2查询表中指定的列信息 2.3查询通过计算的列 2.4使用别名代替列名 2.5查询不带有重复值的列 2.6将查询的结果进行排序 2.7条件查询 2.7.1条件查询的种类 2.7.2使用运算符查询的讲解 2.8分页查询 …

2015年全国硕士研究生入学统一考试管理类专业学位联考写作试题

2015年1月真题&#xff1a; 四、写作&#xff1a;第56~57小题&#xff0c;共65 分。其中论证有效性分析30 分&#xff0c;论说文35 分。 56、论证有效性分析&#xff1a; 分析下述论证存在的缺陷和漏洞&#xff0c;选择若干要点&#xff0c;写一篇600 字的文章&#xff0c;对…

MyCat2介绍以及部署和读写分离/分库分表(MyCat2.0)

一&#xff0c;MyCat入门 1.什么是mycat 官网&#xff1a;http://www.mycat.org.cn/​ mycat是数据库中间件 它可以干什么&#xff1f; 读写分离数据分片&#xff1a;垂直拆分&#xff0c;水平拆分多数据源整合 2.数据库中间件 ​ 中间件&#xff1a;是一类连接软件组件和…

KSM01.2B-061C-35N-M1-HP0-SE-NN伺服电机力士乐

​ KSM01.2B-061C-35N-M1-HP0-SE-NN伺服电机力士乐 KSM01.2B-061C-35N-M1-HP0-SE-NN伺服电机力士乐 从应用对象的规模上来说&#xff1a; PLC一般应用在小型自控场所&#xff0c;比如设备的控制或少量的模拟量的控制及联锁&#xff0c;而大型的应用一般都是DCS。当然&#x…

STM32开发——DMA(数据搬运)

目录 1.DMA简介 2.从内存到内存搬运 2.1CubeMX设置 2.2函数代码 3.内存到外设 3.1CubeMX配置 3.2 函数代码 4.外设到内存 4.1CubeMX配置 4.1函数代码 1.DMA简介 DMA(Direct Memory Access&#xff0c;直接存储器访问) 提供在外设与内存、存储器和存储器、外设 与外设…