macro¶
开始录制一个宏,以便稍后作为命令调用
macro(<name> [<arg1> ...])
<commands>
endmacro()
定义一个名为 <name> 的宏,该宏接受名为 <arg1>、... 的参数。宏之后、匹配 endmacro() 之前的命令直到宏被调用时才执行。
为了兼容旧版本,endmacro() 命令接受一个可选的 <name> 参数。如果使用,它必须是开头 macro 命令参数的逐字重复。
有关宏内策略的行为,请参阅 cmake_policy() 命令文档。
有关 CMake 宏和 函数 之间的区别,请参阅下面的 宏与函数 部分。
调用¶
宏调用不区分大小写。一个宏定义为
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 命令。