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

简介: CMake函数和宏(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,提高代码的可重用性和可维护性。

目录
相关文章
|
28天前
|
资源调度 Serverless 计算机视觉
高斯函数 Gaussian Function
**高斯函数,或称正态分布,以数学家高斯命名,具有钟形曲线特征。关键参数包括期望值μ(决定分布中心)和标准差σ(影响分布的宽度)。当μ=0且σ²=1时,分布为标准正态分布。高斯函数广泛应用于统计学、信号处理和图像处理,如高斯滤波器用于图像模糊。其概率密度函数为e^(-x²/2σ²),积分结果为误差函数。在编程中,高斯函数常用于创建二维权重矩阵进行图像的加权平均,实现模糊效果。
18 1
|
2月前
|
存储 安全 编译器
【C++ 包装器类 std::function 和 函数适配器 std::bind】 C++11 全面的std::function和std::bind的入门使用教程
【C++ 包装器类 std::function 和 函数适配器 std::bind】 C++11 全面的std::function和std::bind的入门使用教程
33 0
|
2月前
|
SQL Oracle 关系型数据库
Flink的表值函数(Table-Valued Function,TVF)是一种返回值是一张表的函数
【2月更文挑战第17天】Flink的表值函数(Table-Valued Function,TVF)是一种返回值是一张表的函数
21 1
|
4月前
|
存储 SQL 安全
函数(Function)和存储过程(Stored Procedure)的区别(小白情感版)
函数(Function)和存储过程(Stored Procedure)的区别(小白情感版)
40 0
|
4月前
|
缓存
pytest 运行测试函数报错的解决办法 TypeError: calling <function xxx> returned None, not a test
pytest 运行测试函数报错的解决办法 TypeError: calling <function xxx> returned None, not a test
101 0
|
4月前
|
数据库
SAP ABAP 更新函数(Update Function Module)执行出错的原因分析试读版
SAP ABAP 更新函数(Update Function Module)执行出错的原因分析试读版
35 0
|
4月前
|
数据库
130. SAP ABAP 更新函数(Update Function Module)执行出错的原因分析
130. SAP ABAP 更新函数(Update Function Module)执行出错的原因分析
26 0
|
5月前
|
SQL
Greenplum【SQL 03】实现树结构+自定义函数+避免函数重复调用+ function cannot execute on a QE slice 问题处理(优化过程全记录)
Greenplum【SQL 03】实现树结构+自定义函数+避免函数重复调用+ function cannot execute on a QE slice 问题处理(优化过程全记录)
36 0
|
6月前
|
存储 前端开发 C语言
C++11的多线程、function和bind、可变函数模板-2
C++11的多线程、function和bind、可变函数模板
51 1
|
7月前
|
存储 数据安全/隐私保护
均匀散列函数(Uniform Hash Function)
均匀散列函数(Uniform Hash Function)是一种将不同长度的输入数据映射到相同大小的输出数据的散列函数。均匀散列函数的主要特点是,对于相同的输入数据,无论其长度如何,都会得到相同的输出散列值。这种散列函数常用于数据结构的存储和查找,例如哈希表、散列表等。
102 3

热门文章

最新文章