宏¶
开始记录宏,以便稍后作为命令调用
macro(<name> [<arg1> ...])
<commands>
endmacro()
定义一个名为 <name>
的宏,它接受名为 <arg1>
等的参数。在宏之后列出的命令,但在匹配的 endmacro()
之前,直到宏被调用才会执行。
根据传统,endmacro()
命令接受可选的 <name>
参数。如果使用,它必须与打开的 macro
命令的参数完全一致。
有关宏内策略行为的详细信息,请参阅 cmake_policy()
命令文档。
有关 CMake 宏与 functions
的区别,请参阅下面的 宏与函数 部分。
调用¶
宏调用不区分大小写。定义为
macro(foo)
<commands>
endmacro()
的宏可以通过以下任何方式调用:
foo()
Foo()
FOO()
cmake_language(CALL foo)
等等。但是,强烈建议您坚持使用宏定义中选择的字母大小写。通常,宏使用全小写名称。
在版本 3.18 中添加: cmake_language(CALL ...)
命令也可以用来调用宏。
参数¶
当宏被调用时,宏中记录的命令首先会通过用传递的参数替换形式参数 (${arg1}
等) 来修改,然后像普通命令一样调用。
除了引用形式参数,您还可以引用值 ${ARGC}
,它将被设置为传递给宏的参数数量,以及 ${ARGV0}
,${ARGV1}
,${ARGV2}
等,它们将包含传递的参数的实际值。这有助于创建具有可选参数的宏。
此外,${ARGV}
包含传递给宏的所有参数列表,而 ${ARGN}
包含最后一个预期参数之后的参数列表。引用超出 ${ARGC}
的 ${ARGV#}
参数的行为未定义。检查 ${ARGC}
是否大于 #
是确保 ${ARGV#}
作为额外参数传递给函数的唯一方法。
宏与函数¶
macro
命令与 function()
命令非常相似。尽管如此,它们之间还是存在一些重要的区别。
在函数中,ARGN
,ARGC
,ARGV
和 ARGV0
,ARGV1
等是通常意义上的 CMake 变量。在宏中,它们不是,它们是字符串替换,就像 C 预处理器对宏的操作一样。这会带来一些后果,如下面的 参数注意事项 部分所述。
宏和函数之间的另一个区别是控制流。函数通过将控制权从调用语句转移到函数体来执行。宏的执行方式就好像宏体被粘贴到调用语句的位置一样。这意味着宏体中的 return()
不会只终止宏的执行;相反,控制权将从宏调用范围返回。为了避免混淆,建议在宏中完全避免使用 return()
。
与函数不同,CMAKE_CURRENT_FUNCTION
,CMAKE_CURRENT_FUNCTION_LIST_DIR
,CMAKE_CURRENT_FUNCTION_LIST_FILE
,CMAKE_CURRENT_FUNCTION_LIST_LINE
变量不会为宏设置。
参数注意事项¶
由于 ARGN
,ARGC
,ARGV
,ARGV0
等不是变量,因此您无法使用以下命令:
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
在第一种情况下,您可以使用 if(${ARGV1})
。在第二种和第三种情况下,检查是否将可选变量传递给宏的正确方法是使用 if(${ARGC} GREATER 2)
。在最后一种情况下,您可以使用 foreach(loop_var ${ARGN})
,但这会跳过空参数。如果您需要包含它们,您可以使用
set(list_var "${ARGN}")
foreach(loop_var IN LISTS list_var)
请注意,如果您在调用宏的范围内有一个同名变量,使用未引用的名称将使用现有变量,而不是参数。例如
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
。如果您需要真正的 CMake 变量和/或更好的 CMake 范围控制,您应该查看 function 命令。