macro

開始錄製巨集,以便稍後作為指令調用

macro(<name> [<arg1> ...])
  <commands>
endmacro()

定義一個名為 <name> 的巨集,它接受名為 <arg1>, ... 的參數。在 macro 之後,但在匹配的 endmacro() 之前的指令,在巨集被調用之前不會執行。

根據傳統,endmacro() 指令接受一個可選的 <name> 參數。如果使用,它必須與開頭的 macro 指令的參數完全相同。

請參閱 cmake_policy() 指令文件,以了解巨集中 policy 的行為。

請參閱以下 巨集 vs 函數 章節,了解 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#} 作為額外參數傳遞給函式的唯一方法。

巨集 vs 函數

macro 指令與 function() 指令非常相似。儘管如此,它們之間還是存在一些重要的差異。

在函數中,ARGNARGCARGVARGV0ARGV1、... 是 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 指令。

參見