macro
macro(<name> [<arg1> ...])
<commands>
endmacro()
定义一个名为name的宏(命名推荐使用全小写),参数为arg1, arg2, …,参数一般为下划线开头,是为了表明这些参数只能在宏中访问
function
function(<name> [<arg1> ...])
<commands>
endfunction()
定义一个名为name的函数(命名推荐使用全小写),参数为arg1, arg2, …,参数一般为下划线开头,是为了表明这些参数只能在函数中访问
marco和function对比
共同点
参数
${ARGC}
传递的参数个数${ARGV}
所有参数的列表,${ARGV0}, ${ARGV1}, ${ARGV2}
, … 为真正的传进来的参数,在使用${ARGV#}
时最好判断${ARGC}
,否则有可能出现未定义行为${ARGN}
保存了最后一个参数之后的参数列表
验证:
macro(xinling _name _time) # macro和function相同
message(STATUS "${ARGC} arguments: ${ARGV}")
message(STATUS "arguments: ${ARGV0}, ${ARGV1}, ${ARGV2}, ${ARGV3}, ${ARGV4}, ${ARGV5}")
message(STATUS "The last parameter list: ${ARGN}")
endmacro()
输出:
从结果可以看出:
${ARGV#}
超过参数个数的部分没有打印输出${ARGV}
和${ARGN}
都是以";"分隔输出
调用方式
macro/function(foo)
<commands>
endmacro()/endfunction()
都可以通过以下几种方式调用
foo() # 推荐和定义时的命名保持一致
Foo()
FOO()
cmake_language(CALL foo) # 3.18之后新增命令
差异
宏和函数之间的区别在于他们的变量范围。宏在调用者的范围内执行,而函数有自己的变量范围,换句话说,类似C++等编程语言,宏只是做替换,所以可以修改变量,但在函数中修改父作用域变量,但这必须通过PARENT_SCOPE显式表示:set(variable "any value" PARENT_SCOPE)
,否则函数内对父作用域的变量的修改只在函数的作用域内生效。
适用场景
什么时候用function或macro?需要仔细考虑变量的作用范围,如果功能可以使用函数实现,就尽量使用函数,因为它对父范围状态提供了更多的默认控制。
CMake模块中定义
在sub_cmake.cmake模块中定义函数或宏:
macro(define_macro)
message("start define colors")
# any command
endmacro()
在CMakeLists.txt中调用模块中的宏或函数
include方式一:通过设置CMAKE_MODULE_PATH,include命令指示CMake搜索${CMAKE_MODULE_PATH},查找名称为sub_cmake.cmake的模块
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
include(sub_cmake)
define_macro() # 调用include进来的模块中的函数或宏
include方式二:显式包含
include(cmake/colors.cmake)
两个命令:
- include
include(<file|module> [OPTIONAL] [RESULT_VARIABLE <var>] [NO_POLICY_SCOPE])
加载和运行file或module,会指示CMake搜索 ${CMAKE_MODULE_PATH}, 查找模块
- include_guard
include_guard([DIRECTORY|GLOBAL])
类似C中的#pragma once,防止多次包含模块,可选的参数为:
- DIRECTORY:应用于当前目录
- GLOBAL:应用于全局
指定参数宏或函数
命令cmake_parse_arguments
用来解析宏或函数的参数
cmake_parse_arguments(<prefix> <options> <one_value_keywords>
<multi_value_keywords> <args>...)
参数说明:(cmake官方文档中"<>"里的参数都是必须的)
- prefix:这个用来在取参数的时候用到,名字可以随意
- options:这个参数是相对独立的,就是说调用时有这个参数那么它的值为TRUE,否则就是FALSE。options就是这种参数的集合
- one_value_keywords:指定只有一个值的参数的集合
- multi_value_keywords:指定有多个值的参数的集合
取值:_keywordName,这里的keywordName就是options、one_value_keywords、multi_value_keywords中指定的参数
示例代码:
function(my_install)
set(options OPTIONAL FAST) # 注意:如果这里不使用set,请看下例
set(oneValueArgs DESTINATION RENAME)
set(multiValueArgs TARGETS CONFIGURATIONS)
cmake_parse_arguments(MY_INSTALL "${options}" "${oneValueArgs}"
"${multiValueArgs}" ${ARGN} )
message(STATUS "OPTIONAL: ${MY_INSTALL_OPTIONAL}")
message(STATUS "FAST: ${MY_INSTALL_FAST}")
message(STATUS "DESTINATION: ${MY_INSTALL_DESTINATION}")
message(STATUS "RENAME: ${MY_INSTALL_RENAME}")
message(STATUS "TARGETS: ${MY_INSTALL_TARGETS}")
message(STATUS "CONFIGURATIONS: ${MY_INSTALL_CONFIGURATIONS}")
endfunction()
my_install(TARGETS foo bar DESTINATION bin OPTIONAL blub CONFIGURATIONS)
输出:
不使用set设置参数关键字的示例:
function(my_install)
set(multiValueArgs TARGETS CONFIGURATIONS)
cmake_parse_arguments(MY_INSTALL "OPTIONAL;FAST" "DESTINATION RENAME" "${multiValueArgs}" ${ARGN} )
...
# 其他内容和上例相同
my_install(TARGETS foo bar DESTINATION bin OPTIONAL blub CONFIGURATIONS)
输出:
所以不使用set的话在cmake_parse_arguments中用";"分隔关键字