热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

CMake函数和宏(function和macro):使用函数和宏提高代码可读性

CMake之func

CMake之function和macro

  • 介绍
    • CMake简介
    • function和macro的概念
  • function
    • function的语法和用法
    • function的参数传递
    • function的返回值
    • 示例代码
  • macro
    • macro的语法和用法
    • macro的参数传递
    • macro的变量作用域
    • 示例代码
  • function和macro的区别
    • 参数传递
    • 返回值
    • 变量作用域
    • 代码示例
  • function和macro的优缺点以及使用场景
    • function的优点:
    • function的缺点:
    • macro的优点:
    • macro的缺点:
    • function的使用场景:
    • macro的使用场景:
  • 总结


介绍

CMake简介

CMake是一个开源的跨平台构建工具,它可用于生成可定制的构建过程,如Makefiles、Visual Studio项目或Xcode项目。CMake使用CMakeLists.txt文件来描述构建过程,这些文件包含了构建项目所需的信息,包括源代码、库、头文件和可执行文件等。


function和macro的概念

在CMake中,function和macro都是用来实现代码重用的工具。它们的主要区别在于参数传递和作用域。
function和macro都可以在CMakeLists.txt文件中定义和调用。在调用时,function和macro的参数传递方式不同。function的参数传递采用传值方式,而macro的参数传递采用文本替换方式。
另外,function和macro的作用域也有所不同。在CMake中,function的作用域是局部作用域,而macro的作用域是全局作用域。这意味着在function中定义的变量只在function中有效,而在macro中定义的变量则在整个CMakeLists.txt文件中有效。
使用function和macro,可以将一些常用的操作封装起来,比如生成安装目录、编译选项等。这样可以减少代码的重复性,提高代码的可维护性和可读性。




function

function的语法和用法


在CMake中,function是用来实现代码重用的工具。function的语法如下:

function(function_name arg1 arg2 ...)# function body
endfunction()

其中,function_name是函数名,arg1、arg2等是函数的参数。在function的body中,可以使用CMake语句来实现具体的操作。

function的参数传递


function的参数传递采用传值方式。这意味着在调用function时,实参的值会被传递到形参中。例如:

function(add_numbers num1 num2)math(EXPR result "${num1} + ${num2}")message("The result is ${result}")
endfunction()add_numbers(1 2)

在上面的例子中,add_numbers函数有两个参数num1和num2。在调用函数时,传递了实参1和2,这些实参的值会被传递到num1和num2中。

function的返回值


function可以有返回值,返回值可以通过set命令设置。例如:

function(add_numbers num1 num2)math(EXPR result "${num1} + ${num2}")set(${result_var} ${result} PARENT_SCOPE)
endfunction()add_numbers(1 2 RESULT)
message("The result is ${RESULT}")

在上面的例子中,add_numbers函数计算了num1和num2的和,并将结果通过set命令设置到了result_var变量中。在调用函数时,传递了实参1和2,并将返回值保存到了RESULT变量中。



示例代码


以下是一个示例函数,在CMakeLists.txt中定义了一个函数,用于生成一个静态库:

function(create_static_library LIBRARY_NAME SOURCE_FILES)add_library(${LIBRARY_NAME} STATIC ${SOURCE_FILES})set_target_properties(${LIBRARY_NAME} PROPERTIES OUTPUT_NAME ${LIBRARY_NAME})set_target_properties(${LIBRARY_NAME} PROPERTIES ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
endfunction()set(SOURCE_FILES foo.cpp bar.cpp)
create_static_library(my_library ${SOURCE_FILES})

在上面的示例代码中,create_static_library函数有两个参数LIBRARY_NAME和SOURCE_FILES。函数的作用是创建一个名为LIBRARY_NAME的静态库,其中包含了SOURCE_FILES中指定的文件。函数通过add_library命令创建了一个静态库,并通过set_target_properties命令设置了输出名称和输出路径。在调用函数时,传递了实参my_library和${SOURCE_FILES}变量。最终,create_static_library函数会生成一个名为my_library的静态库。



macro

Macro是CMake中的一种宏定义,可以将一些常用的代码片段定义为一个宏,当需要使用时直接调用宏即可,可以减少代码的重复性,提高代码的可读性和可维护性。

macro的语法和用法


宏定义的基本格式为:

macro(宏名 参数列表) 宏体 endmacro()

其中,宏名为标识符,参数列表为用括号括起来的形式参数列表,宏体为用endmacro()结束的宏定义体,宏名和宏体之间用空格隔开。

示例:

macro(PRINT_HELLO_WORLD) message("Hello World!") endmacro()

macro的参数传递


宏定义可以接受参数,参数传递方式类似于函数的参数传递,可以传递常量、变量或表达式等。参数传递的格式为:$(参数名)。

示例:

macro(PRINT_MESSAGE message) message(${message}) endmacro()

macro的变量作用域


宏定义中的变量作用域与函数中的变量作用域不同,宏定义中的变量作用域是在宏定义体内,即在宏定义体中定义的变量在宏体外无法访问。

示例:

cmake_minimum_required(VERSION 3.5)#定义一个宏,用于打印传入的消息和变量值
macro(PRINT_MESSAGE_AND_VALUE message value)#在当前宏中定义的变量,只在当前宏中有效
set(local_var "This is a local variable") message("${message}: ${value}") message("local_var: ${local_var}") endmacro()#定义一个全局变量
set(global_var "This is a global variable")#打印全局变量的值
message("global_var: ${global_var}")#调用宏,打印传入的消息和变量值
PRINT_MESSAGE_AND_VALUE("Print global_var" ${global_var})#如果在宏中使用了外部定义的变量,需要在宏调用时将其传入
#调用宏,打印传入的消息和变量值,以及宏中定义的局部变量
PRINT_MESSAGE_AND_VALUE("Print local_var" "This is a parameter")#此处打印的local_var为空,因为它只在上面的宏中定义,在此处无法访问

示例代码



cmake_minimum_required(VERSION 3.5)
#定义一个宏,用于打印"Hello world!"
macro(PRINT_HELLO_WORLD) message("Hello World!") endmacro()#定义一个宏,用于打印传入的消息
macro(PRINT_MESSAGE message) message(${message}) endmacro()#定义一个宏,用于计算传入的两个数的最大值并打印
macro(PRINT_MAX a b)#定义一个变量max,并将其初值设置为a
set(max ${a})#如果b比max大,则将max的值设为b
if(${b} GREATER ${a}) set(max ${b}) endif()#打印最大值
message("max=${max}") endmacro()#调用宏,打印"Hello world!"
PRINT_HELLO_WORLD()#定义一个变量msg,并将其值设置为"Hello CMake!"
set(msg "Hello CMake!")#调用宏,打印变量msg的值
PRINT_MESSAGE(${msg})#调用宏,计算传入的两个数的最大值并打印
PRINT_MAX(10 20)



function和macro的区别

参数传递

function和macro在参数传递方面有所不同。在function中,参数传递是通过参数列表来完成的,参数有类型和顺序,类似于C语言函数的参数传递方式。而在macro中,参数传递是通过文本替换来完成的,因此参数没有类型和顺序限制,可以传递任何文本。

返回值

function可以有返回值,而macro没有返回值。在function中,可以使用return语句返回值,返回值的类型可以是任何CMake支持的类型。而在macro中,不能使用return语句返回值,因为macro的返回值是通过文本替换来实现的。

变量作用域

变量作用域: function和macro在变量作用域方面也有所不同。在function中,变量的作用域是函数内部,函数外部无法访问函数内部定义的变量。而在macro中,变量的作用域是整个CMake文件,因此可以在文件中的任何地方访问和修改宏中定义的变量。

代码示例

以下是一个使用function和macro实现同样功能的示例代码:

#使用function实现
function(ADD_ONE num) math(EXPR result "${num} + 1") return(${result}) endfunction()#调用function,将10加1,并将结果赋值给变量res
ADD_ONE(10 res) message("Result: ${res}")#使用macro实现
macro(ADD_ONE num) math(EXPR result "${num} + 1") set(${ARGV1} ${result}) endmacro()#调用macro,将10加1,并将结果赋值给变量res
ADD_ONE(10 res) message("Result: ${res}")

在这个示例中,我们实现了将一个数加1的功能,使用function和macro两种方式分别实现。可以看出,function使用return语句返回结果,而macro使用set命令将结果赋值给一个参数。另外,调用方式也有所不同,function使用函数调用的方式,而macro使用文本替换的方式。




function和macro的优缺点以及使用场景
  • function的优点:

参数传递和返回值更加灵活,可以实现复杂的逻辑处理;
变量作用域仅限于函数内部,避免了变量命名冲突的问题;
可以使用递归调用实现复杂的算法;
在CMake文件中调用function更加直观,易于理解。

  • function的缺点:

由于使用return语句返回结果,因此会创建新的变量,占用额外的内存空间;
递归调用会导致堆栈溢出的问题;
由于函数调用需要额外的资源开销,因此在处理大量数据时可能会影响性能。

  • macro的优点:

参数传递更加灵活,可以传递任意文本;
可以直接修改CMake文件中的变量,更加方便;
在处理大量数据时性能更好,因为不需要额外的资源开销。

  • macro的缺点:

由于使用文本替换,因此不能实现复杂的逻辑处理;
变量作用域是整个CMake文件,容易出现变量命名冲突的问题;
不能使用递归调用。

  • function的使用场景:

实现复杂的逻辑处理;
需要递归调用的场景;
在CMake文件中调用function更加直观,易于理解。

  • macro的使用场景:

实现简单的文本替换;
需要直接修改CMake文件中的变量的场景;
在处理大量数据时性能更好的场景。


综上所述,function和macro各有优缺点,在不同的场景下选择适合的方法可以使CMake的使用更加高效和方便。




总结

在这篇博客中,我们将详细介绍CMake中function和macro的概念、语法和用法,并通过示例代码演示它们的使用。我们还将比较function和macro之间的区别,并讨论它们在实际应用中的使用场景和最佳实践。
通过本文的学习,读者将能更好地理解和应用CMake中的function和macro,提高代码的可重用性和可维护性。


推荐阅读
  • Commit1ced2a7433ea8937a1b260ea65d708f32ca7c95eintroduceda+Clonetraitboundtom ... [详细]
  • baresip android编译、运行教程1语音通话
    本文介绍了如何在安卓平台上编译和运行baresip android,包括下载相关的sdk和ndk,修改ndk路径和输出目录,以及创建一个c++的安卓工程并将目录考到cpp下。详细步骤可参考给出的链接和文档。 ... [详细]
  • Linux 程序设计学习笔记----动手编写makefile文件
    nsitionalENhttp:www.w3.orgTRxhtml1DTDxhtml1-transitional.dtd ... [详细]
  • 本文介绍了lua语言中闭包的特性及其在模式匹配、日期处理、编译和模块化等方面的应用。lua中的闭包是严格遵循词法定界的第一类值,函数可以作为变量自由传递,也可以作为参数传递给其他函数。这些特性使得lua语言具有极大的灵活性,为程序开发带来了便利。 ... [详细]
  • Linux服务器密码过期策略、登录次数限制、私钥登录等配置方法
    本文介绍了在Linux服务器上进行密码过期策略、登录次数限制、私钥登录等配置的方法。通过修改配置文件中的参数,可以设置密码的有效期、最小间隔时间、最小长度,并在密码过期前进行提示。同时还介绍了如何进行公钥登录和修改默认账户用户名的操作。详细步骤和注意事项可参考本文内容。 ... [详细]
  • [译]技术公司十年经验的职场生涯回顾
    本文是一位在技术公司工作十年的职场人士对自己职业生涯的总结回顾。她的职业规划与众不同,令人深思又有趣。其中涉及到的内容有机器学习、创新创业以及引用了女性主义者在TED演讲中的部分讲义。文章表达了对职业生涯的愿望和希望,认为人类有能力不断改善自己。 ... [详细]
  • 不同优化算法的比较分析及实验验证
    本文介绍了神经网络优化中常用的优化方法,包括学习率调整和梯度估计修正,并通过实验验证了不同优化算法的效果。实验结果表明,Adam算法在综合考虑学习率调整和梯度估计修正方面表现较好。该研究对于优化神经网络的训练过程具有指导意义。 ... [详细]
  • 自动轮播,反转播放的ViewPagerAdapter的使用方法和效果展示
    本文介绍了如何使用自动轮播、反转播放的ViewPagerAdapter,并展示了其效果。该ViewPagerAdapter支持无限循环、触摸暂停、切换缩放等功能。同时提供了使用GIF.gif的示例和github地址。通过LoopFragmentPagerAdapter类的getActualCount、getActualItem和getActualPagerTitle方法可以实现自定义的循环效果和标题展示。 ... [详细]
  • Android系统移植与调试之如何修改Android设备状态条上音量加减键在横竖屏切换的时候的显示于隐藏
    本文介绍了如何修改Android设备状态条上音量加减键在横竖屏切换时的显示与隐藏。通过修改系统文件system_bar.xml实现了该功能,并分享了解决思路和经验。 ... [详细]
  • C++字符字符串处理及字符集编码方案
    本文介绍了C++中字符字符串处理的问题,并详细解释了字符集编码方案,包括UNICODE、Windows apps采用的UTF-16编码、ASCII、SBCS和DBCS编码方案。同时说明了ANSI C标准和Windows中的字符/字符串数据类型实现。文章还提到了在编译时需要定义UNICODE宏以支持unicode编码,否则将使用windows code page编译。最后,给出了相关的头文件和数据类型定义。 ... [详细]
  • 3.223.28周学习总结中的贪心作业收获及困惑
    本文是对3.223.28周学习总结中的贪心作业进行总结,作者在解题过程中参考了他人的代码,但前提是要先理解题目并有解题思路。作者分享了自己在贪心作业中的收获,同时提到了一道让他困惑的题目,即input details部分引发的疑惑。 ... [详细]
  • IjustinheritedsomewebpageswhichusesMooTools.IneverusedMooTools.NowIneedtoaddsomef ... [详细]
  • Android日历提醒软件开源项目分享及使用教程
    本文介绍了一款名为Android日历提醒软件的开源项目,作者分享了该项目的代码和使用教程,并提供了GitHub项目地址。文章详细介绍了该软件的主界面风格、日程信息的分类查看功能,以及添加日程提醒和查看详情的界面。同时,作者还提醒了读者在使用过程中可能遇到的Android6.0权限问题,并提供了解决方法。 ... [详细]
  • 32位ubuntu编译android studio,32位Ubuntu编译Android 4.0.4问题
    问题一:在32位Ubuntu12.04上编译Android4.0.4源码时,出现了关于emulator的错误,关键是其Makefile里的 ... [详细]
  • 本文介绍了在使用vue和webpack进行异步组件按需加载时可能出现的报错问题,并提供了解决方法。同时还解答了关于局部注册组件和v-if指令的相关问题。 ... [详细]
author-avatar
西北人6668_733
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有