CMake中的函数与宏

时间:2014-06-19 02:48:47

标签: cmake

The official document of CMake 2.8.12macro

  

调用时,首先记录宏中的命令   通过用参数替换形式参数($ {arg1})来修改   传递,然后作为普通命令调用。

和约function

  

调用时,首先记录在函数中的命令   通过用参数替换形式参数($ {arg1})来修改   传递,然后作为普通命令调用。

显然,两个引号几乎相同但令我困惑。在调用函数时,首先替换参数,就像宏一样吗?

5 个答案:

答案 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文档是如此令人误解,以至于基本上是错误的。应该像这样澄清/修复:

  • 宏:调用宏时,宏中记录的命令先被修改,然后再运行,方法是用传递的参数替换形式参数($ {arg1})。

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真的让我大开眼界!

我还发现下面的教程带有一些具体示例,有助于理解变量范围概念。

引自Learn cmake in 15 mins

在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