The official document of CMake 2.8.12说macro
调用时,首先记录宏中的命令 通过用参数替换形式参数($ {arg1})来修改 传递,然后作为普通命令调用。
和约function
调用时,首先记录在函数中的命令 通过用参数替换形式参数($ {arg1})来修改 传递,然后作为普通命令调用。
显然,两个引号几乎相同但令我困惑。在调用函数时,首先替换参数,就像宏一样吗?
答案 0 :(得分:78)
我在下面写了一个示例代码:
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
时只是用{{1}}替换了字符串}。
所以我认为以上两个引号很容易让人困惑,虽然官方文件也说过:
它们是字符串替换,就像C预处理器一样 用宏。如果你想要真正的CMake变量和/或更好的CMake 范围控制你应该看一下函数命令。
答案 1 :(得分:28)
换句话说,函数推送和弹出新的变量范围(创建和更改的变量仅存在于函数中),而宏则不存在。但是,您可以使用PARENT_SCOPE
命令的set
参数覆盖函数默认行为。
答案 2 :(得分:3)
您引用的cmake文档是如此令人误解,以至于基本上是错误的。应该像这样澄清/修复:
cmake --trace-expand
准确显示了发生的情况。
相对于2.8.12,cmake 3.13.3文档没有变化。
答案 3 :(得分:3)
function()
和macro()
之间的另一个显着区别是return()
的行为。
来自cmake documentation of 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
答案 4 :(得分:2)
macro expansion, answered by Yantao Xie真的让我大开眼界!
我还发现下面的教程带有一些具体示例,有助于理解变量范围概念。
在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