CMake 2.8.12的官方文件中提到macro
调用宏时,首先通过用传递的参数替换形式参数($ {arg1})来修改宏中记录的命令,然后将其作为普通命令来调用。
和关于 function
调用它时,函数中记录的命令首先通过用传递的参数替换形式参数($ {arg1})进行修改,然后作为普通命令调用。
显然,两个引号几乎相同,但使我感到困惑。像宏一样调用函数时,首先要替换参数吗?
CMake 2.8.12的官方文件中提到macro
调用宏时,首先通过用传递的参数替换形式参数($ {arg1})来修改宏中记录的命令,然后将其作为普通命令来调用。
和关于 function
调用它时,函数中记录的命令首先通过用传递的参数替换形式参数($ {arg1})进行修改,然后作为普通命令调用。
显然,两个引号几乎相同,但使我感到困惑。像宏一样调用函数时,首先要替换参数吗?
${ARGV}
从内部打印macro(my_macro)
,,function(my_func)
。并使用它们:set(a 123)
,my_macro("\\\${a}\\\\;\\\;;")
,my_func(\${a}\\;\;;)
。您将发现必须对所有$
,进行两次转义\
,;
才能正确地将未更改的整个字符串传递给嵌套命令。这是实际的cmake 3.14+
。
Answers:
我在下面编写了示例代码:
set(var "ABC")
macro(Moo arg)
message("arg = ${arg}")
set(arg "abc")
message("# After change the value of arg.")
message("arg = ${arg}")
endmacro()
message("=== Call macro ===")
Moo(${var})
function(Foo arg)
message("arg = ${arg}")
set(arg "abc")
message("# After change the value of arg.")
message("arg = ${arg}")
endfunction()
message("=== Call function ===")
Foo(${var})
输出为:
=== Call macro ===
arg = ABC
# After change the value of arg.
arg = ABC
=== Call function ===
arg = ABC
# After change the value of arg.
arg = abc
因此,似乎arg
被赋予的价值var
时调用Foo
,并${arg}
与刚刚替换字符串${var}
时调用Moo
。
所以我认为上述两个引号很容易使人迷惑,虽然官方文件还表示说:
请注意,在通常的CMake意义上,宏的参数和诸如ARGN之类的值不是变量。它们是字符串替换,非常类似于C预处理器对宏的处理。如果您需要真正的CMake变量和/或更好的CMake范围控制,则应查看function命令。
cmake --trace-expand
很有启发性
message("# arg in main scope = '${arg}'")
+在宏之前调用函数。
function()
和之间的另一个显着区别macro()
是的行为return()
。
请注意,与函数不同,宏在适当位置被扩展,因此无法处理return()。
因此,由于它已在适当位置扩展,因此它macro()
从调用方返回。在功能中,它只是退出function()
例:
macro(my_macro)
return()
endmacro()
function(my_function)
return()
endfunction()
my_function()
message(hello) # is printed
my_macro()
message(hi) # is not printed
我还发现下面的教程带有一些具体示例,这有助于理解可变范围的概念。
在CMake中,您可以使用一对function
/endfunction
命令来定义一个函数。这是将其参数的数值加倍的一个,然后输出结果:
function(doubleIt VALUE)
math(EXPR RESULT "${VALUE} * 2")
message("${RESULT}")
endfunction()
doubleIt("4") # Prints: 8
函数在自己的范围内运行。函数中定义的任何变量都不会污染调用方的作用域。如果要返回值,可以将变量的名称传递给函数,然后set
使用特殊参数调用命令PARENT_SCOPE
:
function(doubleIt VARNAME VALUE)
math(EXPR RESULT "${VALUE} * 2")
set(${VARNAME} "${RESULT}" PARENT_SCOPE) # Set the named variable in caller's scope
endfunction()
doubleIt(RESULT "4") # Tell the function to set the variable named RESULT
message("${RESULT}") # Prints: 8
同样,一对macro
/endmacro
命令定义一个宏。与函数不同,宏在与其调用程序相同的范围内运行。因此,在宏内定义的所有变量都在调用者的作用域中设置。我们可以用以下内容替换以前的功能:
macro(doubleIt VARNAME VALUE)
math(EXPR ${VARNAME} "${VALUE} * 2") # Set the named variable in caller's scope
endmacro()
doubleIt(RESULT "4") # Tell the macro to set the variable named RESULT
message("${RESULT}") # Prints: 8
函数和宏都接受任意数量的参数。未命名的参数通过名为的特殊变量以列表形式显示在函数中ARGN
。
这是一个函数,它将接收到的每个参数加倍,并在单独的行上打印每个参数:
function(doubleEach)
foreach(ARG ${ARGN}) # Iterate over each argument
math(EXPR N "${ARG} * 2") # Double ARG's numeric value; store result in N
message("${N}") # Print N
endforeach()
endfunction()
doubleEach(5 6 7 8) # Prints 10, 12, 14, 16 on separate lines
function
和之间至少还有一个重要的区别,尽管macro
:的语义相当明显return()
:在a中使用时macro
,您不会从宏返回,而是从调用函数返回。