CMake 中 function 和 macro 的区别
通过代码直观地来看看区别。
set(var "ABC")
macro(Moo arg)
message("arg = ${arg}") # 输出原值 ABC
set(arg "abc")
message("# After change the value of arg.")
message("arg = ${arg}") # 输出原值 ABC
endmacro()
message("=== Call macro ===")
Moo(${var})
function(Foo arg)
message("arg = ${arg}") # 输出原值 ABC
set(arg "abc")
message("# After change the value of arg.") # 输出修改后的值 abc
message("arg = ${arg}")
endfunction()
message("=== Call function ===")
Foo(${var})
上面的例子来自 function-vs-macro-in-cmake。其中最佳答案的评论中还提到了一个非常有用的 cmake 参数 --trace-expand,该指令会将 cmake 中的宏定义展开,这样就方便了我们仔细研究 cmake 中的宏定义。
通过执行 cmake .. --trace-expand 我们可以知道以下事实:
关于 macro 宏定义的事实
1. 原代码的解析
在上面的例子中,宏定义 Moo 接受的参数其实是 var 的值,字符串 "ABC"。
在宏定义体中,需要引用参数的话,只能写 ${参数}。宏定义会将所有 ${参数} 的地方进行直接简单粗暴地替换为字符串"ABC"。
因此上面的代码中,当我们调用 Moo(${var}) 时,其实展开后的宏定义代码块变为了:
Moo(ABC)
message(arg = ABC)
set(arg abc)
message(# After change the value of arg.)
message(arg = ABC)
因此,宏定义中的 set 方法试图改变宏定义中传进来的参数 arg 是不可能的。set(arg "abc") 只是定义了一个变量 arg,且赋值为字符串 ‘abc’。
在 CMake 中,只要是不带空格的值,其本质上都是字符串。因此上面的 message(arg = ABC) 同 message(arg = "ABC") 是一样的。
2. 原代码的变形
如果我们将上面宏定义中的 set 方法修改为 set(${arg} "abc&