add_custom_command

將自訂建置規則新增至產生的建置系統。

add_custom_command 主要有兩種簽章。

產生檔案

第一個簽章用於新增自訂命令以產生輸出

add_custom_command(OUTPUT output1 [output2 ...]
                   COMMAND command1 [ARGS] [args1...]
                   [COMMAND command2 [ARGS] [args2...] ...]
                   [MAIN_DEPENDENCY depend]
                   [DEPENDS [depends...]]
                   [BYPRODUCTS [files...]]
                   [IMPLICIT_DEPENDS <lang1> depend1
                                    [<lang2> depend2] ...]
                   [WORKING_DIRECTORY dir]
                   [COMMENT comment]
                   [DEPFILE depfile]
                   [JOB_POOL job_pool]
                   [JOB_SERVER_AWARE <bool>]
                   [VERBATIM] [APPEND] [USES_TERMINAL]
                   [CODEGEN]
                   [COMMAND_EXPAND_LISTS]
                   [DEPENDS_EXPLICIT_ONLY])

這會定義一個命令來產生指定的 OUTPUT 檔案。在相同目錄(CMakeLists.txt 檔案)中建立的目標,若將自訂命令的任何輸出指定為來源檔案,則會被賦予一個規則,在建置時使用該命令來產生檔案。

請勿在多個可能並行建置的獨立目標中列出輸出,否則規則的實例可能會衝突。相反地,請使用 add_custom_target() 命令來驅動該命令,並使其他目標依賴於該目標。請參閱下方的範例:為多個目標產生檔案

選項如下

APPEND

COMMANDDEPENDS 選項值附加到第一個指定的輸出的自訂命令。先前必須已呼叫過具有相同輸出的此命令。

如果先前的呼叫透過產生器表達式指定了輸出,則目前呼叫指定的輸出在評估產生器表達式後,必須在至少一個組態中匹配。在這種情況下,附加的命令和依賴項適用於所有組態。

當給定 APPEND 時,目前會忽略 COMMENTMAIN_DEPENDENCYWORKING_DIRECTORY 選項,但未來可能會使用。

BYPRODUCTS

在版本 3.2 中新增。

指定命令預期產生的檔案,但其修改時間可能不比依賴項新。如果副產品名稱是相對路徑,它將相對於目前來源目錄對應的建置樹目錄進行解釋。每個副產品檔案都將自動標記為 GENERATED 來源檔案屬性。

請參閱政策 CMP0058 以了解此功能背後的動機。

顯式指定副產品受到 Ninja 產生器的支援,以告知 ninja 建置工具在副產品遺失時如何重新產生它們。當其他建置規則(例如自訂命令)依賴於副產品時,它也很有用。Ninja 需要任何產生的檔案的建置規則,另一個規則依賴於該檔案,即使存在僅限順序的依賴項,以確保副產品在它們的依賴項建置之前可用。

Makefile 產生器 將在 make clean 期間移除 BYPRODUCTS 和其他 GENERATED 檔案。

此關鍵字不能與 APPEND 一起使用(請參閱政策 CMP0175)。所有副產品都必須在第一次呼叫 add_custom_command(OUTPUT...) 時為輸出檔案設定。

在版本 3.20 中新增:BYPRODUCTS 的引數可以使用一組受限制的 產生器表達式依賴目標的表達式 不允許。

在版本 3.28 中變更:在使用 檔案集 的目標中,自訂命令副產品現在被視為私有,除非它們在非私有檔案集中列出。請參閱政策 CMP0154

COMMAND

指定在建置時執行的命令列。通常至少會給定一個 COMMAND,但某些模式可能會省略它,例如使用 APPEND 在單獨的呼叫中新增命令。

如果指定了多個 COMMAND,它們將按順序執行,但一定組合到有狀態的 shell 或批次腳本中。若要執行完整的腳本,請使用 configure_file() 命令或 file(GENERATE) 命令來建立它,然後指定一個 COMMAND 來啟動它。

可選的 ARGS 引數是為了向後相容性,將被忽略。

如果 COMMAND 指定可執行目標名稱(由 add_executable() 命令建立),如果以下任一項為真,它將自動替換為在建置時建立的可執行檔的位置

  • 目標未被交叉編譯(即 CMAKE_CROSSCOMPILING 變數未設定為 true)。

  • 在版本 3.6 中新增:目標正在被交叉編譯,並且提供了模擬器(即其 CROSSCOMPILING_EMULATOR 目標屬性已設定)。在這種情況下,CROSSCOMPILING_EMULATOR 的內容將在目標可執行檔的位置之前添加到命令的前面。

如果以上條件均不滿足,則假定命令名稱是在建置時在 PATH 上找到的程式。

COMMAND 的引數可以使用 產生器表達式。使用 TARGET_FILE 產生器表達式來引用命令列中稍後的目標位置(即作為命令引數而不是作為要執行的命令)。

每當以下基於目標的產生器表達式之一用作要執行的命令或在命令引數中提及時,將自動新增目標級別的依賴項,以便在任何使用此自訂命令的目標之前建置提及的目標(請參閱政策 CMP0112)。

  • TARGET_FILE

  • TARGET_LINKER_FILE

  • TARGET_SONAME_FILE

  • TARGET_PDB_FILE

此目標級別的依賴項不新增檔案級別的依賴項,這會導致每次重新編譯可執行檔時都重新執行自訂命令。使用 DEPENDS 選項列出目標名稱以新增此類檔案級別的依賴項。

COMMENT

在建置時執行命令之前顯示給定的訊息。如果給定 APPEND,這將被忽略,儘管未來的版本可能會使用它。

在版本 3.26 中新增:COMMENT 的引數可以使用 產生器表達式

DEPENDS

指定命令依賴的檔案。每個引數都轉換為依賴項,如下所示

  1. 如果引數是目標的名稱(由 add_custom_target()add_executable()add_library() 命令建立),則會建立目標級別的依賴項,以確保在任何使用此自訂命令的目標之前建置目標。此外,如果目標是可執行檔或程式庫,則會建立檔案級別的依賴項,以導致每次重新編譯目標時都重新執行自訂命令。

  2. 如果引數是絕對路徑,則會在該路徑上建立檔案級別的依賴項。

  3. 如果引數是已新增至目標或已在其上設定來源檔案屬性的來源檔案的名稱,則會在該來源檔案上建立檔案級別的依賴項。

  4. 如果引數是相對路徑,並且它存在於目前的來源目錄中,則會在目前來源目錄中的該檔案上建立檔案級別的依賴項。

  5. 否則,會在相對於目前二進制目錄的路徑上建立檔案級別的依賴項。

如果任何依賴項是同一目錄(CMakeLists.txt 檔案)中另一個自訂命令的 OUTPUT,CMake 會自動將另一個自訂命令帶入建置此命令的目標中。

在版本 3.16 中新增:如果任何依賴項被列為同一目錄中目標或其任何建置事件的 BYPRODUCTS,則會新增目標級別的依賴項,以確保副產品可用。

如果未指定 DEPENDS,則每當 OUTPUT 遺失時,命令就會執行;如果命令實際上沒有建立 OUTPUT,則規則將始終執行。

在版本 3.1 中新增:DEPENDS 的引數可以使用 產生器表達式

COMMAND_EXPAND_LISTS

在版本 3.8 中新增。

COMMAND 引數中的列表將會展開,包括使用 產生器表達式 建立的列表,允許 COMMAND 引數(例如 ${CC} "-I$<JOIN:$<TARGET_PROPERTY:foo,INCLUDE_DIRECTORIES>,;-I>" foo.cc)正確展開。

此關鍵字不能與 APPEND 一起使用(請參閱政策 CMP0175)。如果附加的命令需要設定此選項,則必須在第一次呼叫 add_custom_command(OUTPUT...) 時為輸出檔案設定。

CODEGEN

在版本 3.31 中新增。

將自訂命令新增至全域 codegen 目標,該目標可用於在避免大多數建置圖的情況下執行自訂命令。

此選項僅受 Ninja 產生器Makefile 產生器 支援,並且其他產生器會忽略它。此外,僅當政策 CMP0171 設定為 NEW 時,才允許此選項。

此關鍵字不能與 APPEND 一起使用(請參閱政策 CMP0175)。它只能在第一次呼叫 add_custom_command(OUTPUT...) 時為輸出檔案設定。

IMPLICIT_DEPENDS

請求掃描輸入檔案的隱含依賴項。給定的語言指定應使用其對應依賴項掃描器的程式語言。目前僅支援 CCXX 語言掃描器。IMPLICIT_DEPENDS 列表中的每個檔案都必須指定語言。從掃描中發現的依賴項會在建置時新增到自訂命令的依賴項中。請注意,IMPLICIT_DEPENDS 選項目前僅適用於 Makefile 產生器,其他產生器將忽略它。

注意

此選項不能與 DEPFILE 選項同時指定。

JOB_POOL

在版本 3.15 中新增。

Ninja 產生器指定 pool。與 USES_TERMINAL 不相容,後者暗示 console pool。使用未由 JOB_POOLS 定義的 pool 會導致 ninja 在建置時產生錯誤。

此關鍵字不能與 APPEND 一起使用(請參閱政策 CMP0175)。Job pools 只能在第一次呼叫 add_custom_command(OUTPUT...) 時為輸出檔案指定。

JOB_SERVER_AWARE

在版本 3.28 中新增。

指定命令可感知 GNU Make job server。

對於 Unix MakefilesMSYS MakefilesMinGW Makefiles 產生器,這將為配方行新增 + 前綴。有關更多資訊,請參閱 GNU Make 文件

其他產生器會靜默忽略此選項。

此關鍵字不能與 APPEND 一起使用(請參閱政策 CMP0175)。Job server 感知只能在第一次呼叫 add_custom_command(OUTPUT...) 時為輸出檔案指定。

MAIN_DEPENDENCY

指定命令的主要輸入來源檔案。這與給定 DEPENDS 選項的任何值一樣處理,但也向 Visual Studio 產生器建議將自訂命令掛在哪裡。每個來源檔案最多可以有一個命令將其指定為主要依賴項。編譯命令(即對於程式庫或可執行檔)計為隱含的主要依賴項,該依賴項會被自訂命令規範靜默覆寫。

如果給定 APPEND,目前會忽略此選項,但未來的版本可能會使用它。

OUTPUT

指定命令預期產生的輸出檔案。每個輸出檔案都將自動標記為 GENERATED 來源檔案屬性。如果自訂命令的輸出實際上未作為磁碟上的檔案建立,則應使用 SYMBOLIC 來源檔案屬性標記它。

如果輸出檔案名稱是相對路徑,則其絕對路徑由相對於以下位置解釋來確定

  1. 目前來源目錄對應的建置目錄(CMAKE_CURRENT_BINARY_DIR),或

  2. 目前來源目錄(CMAKE_CURRENT_SOURCE_DIR)。

除非來源樹中的路徑在目前目錄中的其他位置被提及為絕對來源檔案路徑,否則建置目錄中的路徑是首選的。

輸出檔案路徑不能包含 <> 字元。

在版本 3.20 中新增:OUTPUT 的引數可以使用一組受限制的 產生器表達式依賴目標的表達式 不允許。

在版本 3.28 中變更:在使用 檔案集 的目標中,自訂命令輸出現在被視為私有,除非它們在非私有檔案集中列出。請參閱政策 CMP0154

在版本 3.30 中變更:輸出檔案路徑現在可以使用 # 字元,除非使用 Borland Makefiles 產生器。

USES_TERMINAL

在版本 3.2 中新增。

如果可能,命令將被授予直接存取終端的權限。對於 Ninja 產生器,這會將命令置於 console pool 中。

此關鍵字不能與 APPEND 一起使用(請參閱政策 CMP0175)。如果附加的命令需要存取終端,則必須在第一次呼叫 add_custom_command(OUTPUT...) 時為輸出檔案設定。

VERBATIM

命令的所有引數都將為建置工具正確轉義,以便調用的命令接收每個未更改的引數。請注意,在 add_custom_command 甚至看到引數之前,CMake 語言處理器仍然使用一個層級的轉義。VERBATIM 的使用是建議的,因為它可以實現正確的行為。當未給定 VERBATIM 時,行為是平台特定的,因為沒有工具特定特殊字元的保護。

此關鍵字不能與 APPEND 一起使用(請參閱政策 CMP0175)。如果附加的命令需要被視為 VERBATIM,則必須在第一次呼叫 add_custom_command(OUTPUT...) 時為輸出檔案設定。

WORKING_DIRECTORY

使用給定的目前工作目錄執行命令。如果它是相對路徑,它將相對於目前來源目錄對應的建置樹目錄進行解釋。

如果給定 APPEND,目前會忽略此選項,但未來的版本可能會使用它。

在版本 3.13 中新增:WORKING_DIRECTORY 的引數可以使用 產生器表達式

DEPFILE

在版本 3.7 中新增。

指定一個 depfile,其中包含自訂命令的依賴項。它通常由自訂命令本身發出。僅當產生器支援此關鍵字時,才可以使用此關鍵字,如下詳述。

預期的格式與 gcc 使用 -M 選項產生的格式相容,並且獨立於產生器或平台。

使用 BNF 表示法和正規擴展指定的正式語法如下

depfile       ::=  rule*
rule          ::=  targets (':' (separator dependencies?)?)? eol
targets       ::=  target (separator target)* separator*
target        ::=  pathname
dependencies  ::=  dependency (separator dependency)* separator*
dependency    ::=  pathname
separator     ::=  (space | line_continue)+
line_continue ::=  '\' eol
space         ::=  ' ' | '\t'
pathname      ::=  character+
character     ::=  std_character | dollar | hash | whitespace
std_character ::=  <any character except '$', '#' or ' '>
dollar        ::=  '$$'
hash          ::=  '\#'
whitespace    ::=  '\ '
eol           ::=  '\r'? '\n'

注意

作為 pathname 的一部分,任何斜線和反斜線都解釋為目錄分隔符。

在版本 3.7 中新增:Ninja 產生器自首次新增關鍵字以來就支援 DEPFILE

在版本 3.17 中新增:新增 Ninja Multi-Config 產生器,其中包括對 DEPFILE 關鍵字的支援。

在版本 3.20 中新增:新增對 Makefile 產生器 的支援。

注意

DEPFILE 不能與 Makefile 產生器IMPLICIT_DEPENDS 選項同時指定。

在版本 3.21 中新增:新增對 VS 2012 及更高版本的 Visual Studio 產生器Xcode 產生器的支援。也新增了對 產生器表達式 的支援。

在版本 3.29 中新增:如果檔案未在 OUTPUTSBYPRODUCTS 中列出,Ninja 產生器 現在會將依賴項合併到其「deps log」資料庫中。

DEPFILE 與上面列出的產生器以外的產生器一起使用會產生錯誤。

如果 DEPFILE 引數是相對的,則它應該相對於 CMAKE_CURRENT_BINARY_DIR,並且 DEPFILE 內部的任何相對路徑也應該相對於 CMAKE_CURRENT_BINARY_DIR。請參閱政策 CMP0116,對於 Makefile 產生器Visual Studio 產生器Xcode 產生器,該政策始終為 NEW

此關鍵字不能與 APPEND 一起使用(請參閱政策 CMP0175)。Depfiles 只能在第一次呼叫 add_custom_command(OUTPUT...) 時為輸出檔案設定。

DEPENDS_EXPLICIT_ONLY

在版本 3.27 中新增。

表示命令的 DEPENDS 引數表示命令所需的所有檔案,並且不需要隱含的依賴項。

如果沒有此選項,如果任何目標使用自訂命令的輸出,CMake 將考慮該目標的依賴項作為自訂命令的隱含依賴項,以防此自訂命令需要由這些目標隱含建立的檔案。

可以透過將 CMAKE_ADD_CUSTOM_COMMAND_DEPENDS_EXPLICIT_ONLY 設定為 ON,在所有自訂命令上啟用此選項。

此關鍵字不能與 APPEND 一起使用(請參閱政策 CMP0175)。它只能在第一次呼叫 add_custom_command(OUTPUT...) 時為輸出檔案設定。

只有 Ninja 產生器 實際上使用此資訊來移除不必要的隱含依賴項。

另請參閱 OPTIMIZE_DEPENDENCIES 目標屬性,這可能提供另一種方法來減少在某些情況下目標依賴性的影響。

範例:產生檔案

自訂命令可用於產生原始碼檔案。例如,以下程式碼

add_custom_command(
  OUTPUT out.c
  COMMAND someTool -i ${CMAKE_CURRENT_SOURCE_DIR}/in.txt
                   -o out.c
  DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/in.txt
  VERBATIM)
add_library(myLib out.c)

新增一個自訂命令來執行 someTool 以產生 out.c,然後將產生的原始碼編譯為程式庫的一部分。只要 in.txt 變更,產生規則就會重新執行。

在版本 3.20 中新增:可以使用產生器運算式來指定每個組態的輸出。例如,以下程式碼

add_custom_command(
  OUTPUT "out-$<CONFIG>.c"
  COMMAND someTool -i ${CMAKE_CURRENT_SOURCE_DIR}/in.txt
                   -o "out-$<CONFIG>.c"
                   -c "$<CONFIG>"
  DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/in.txt
  VERBATIM)
add_library(myLib "out-$<CONFIG>.c")

新增一個自訂命令來執行 someTool 以產生 out-<config>.c,其中 <config> 是組建組態,然後將產生的原始碼編譯為程式庫的一部分。

在版本 3.31 中新增:使用 CODEGEN 選項將自訂命令的輸出新增至內建的 codegen 目標。這對於在不建置整個專案的情況下,使產生的程式碼可用於靜態分析非常有用。例如

add_executable(someTool someTool.c)

add_custom_command(
  OUTPUT out.c
  COMMAND someTool -o out.c
  CODEGEN)

add_library(myLib out.c)

使用者可以建置 codegen 目標來產生 out.csomeTool 會被建置為依賴項,但 myLib 完全不會被建置。

範例:為多個目標產生檔案

如果多個獨立的目標需要相同的自訂命令輸出,則必須將其附加到所有目標都依賴的單一自訂目標上。請考慮以下範例

add_custom_command(
  OUTPUT table.csv
  COMMAND makeTable -i ${CMAKE_CURRENT_SOURCE_DIR}/input.dat
                    -o table.csv
  DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/input.dat
  VERBATIM)
add_custom_target(generate_table_csv DEPENDS table.csv)

add_custom_command(
  OUTPUT foo.cxx
  COMMAND genFromTable -i table.csv -case foo -o foo.cxx
  DEPENDS table.csv           # file-level dependency
          generate_table_csv  # target-level dependency
  VERBATIM)
add_library(foo foo.cxx)

add_custom_command(
  OUTPUT bar.cxx
  COMMAND genFromTable -i table.csv -case bar -o bar.cxx
  DEPENDS table.csv           # file-level dependency
          generate_table_csv  # target-level dependency
  VERBATIM)
add_library(bar bar.cxx)

輸出 foo.cxx 僅目標 foo 需要,而輸出 bar.cxx 僅目標 bar 需要,但 *兩個* 目標都間接地需要 table.csv。由於 foobar 是可能同時建置的獨立目標,我們透過將其自訂命令放在單獨的目標 generate_table_csv 中,來防止它們競爭產生 table.csv。產生 foo.cxxbar.cxx 的自訂命令各自指定了對 generate_table_csv 的目標級依賴性,因此使用它們的目標 foobar 將在目標 generate_table_csv 建置完成後才會建置。

建置事件

第二種簽名將自訂命令新增到目標,例如程式庫或可執行檔。這對於在建置目標之前或之後執行操作很有用。該命令成為目標的一部分,並且僅在目標本身被建置時執行。如果目標已經建置,則該命令將不會執行。

add_custom_command(TARGET <target>
                   PRE_BUILD | PRE_LINK | POST_BUILD
                   COMMAND command1 [ARGS] [args1...]
                   [COMMAND command2 [ARGS] [args2...] ...]
                   [BYPRODUCTS [files...]]
                   [WORKING_DIRECTORY dir]
                   [COMMENT comment]
                   [VERBATIM]
                   [COMMAND_EXPAND_LISTS]
                   [USES_TERMINAL])

這定義了一個新的命令,該命令將與建置指定的 <target> 相關聯。<target> 必須在目前目錄中定義;不得指定在其他目錄中定義的目標。

命令何時發生取決於指定以下哪個選項

PRE_BUILD

此選項對於 Visual Studio 產生器 具有獨特的行為。當使用 Visual Studio 產生器之一時,該命令將在目標內執行任何其他規則之前執行。對於所有其他產生器,此選項的行為與 PRE_LINK 相同。因此,建議避免使用 PRE_BUILD,除非已知正在使用 Visual Studio 產生器。

PRE_LINK

在原始碼編譯完成後,但在連結二進制檔案或執行靜態程式庫的程式庫管理員或封存工具之前執行。這不適用於由 add_custom_target() 命令建立的目標。

POST_BUILD

在目標內的所有其他規則都執行完成後執行。

當使用 TARGET 形式時,專案應始終指定上述三個關鍵字之一。請參閱政策 CMP0175

簽名中顯示的所有其他關鍵字的含義與命令的 add_custom_command(OUTPUT) 形式相同。必須至少給定一個 COMMAND,請參閱政策 CMP0175

注意

由於產生器運算式可用於自訂命令,因此可以定義 COMMAND 行或整個自訂命令,這些命令對於某些組態評估為空字串。對於 Visual Studio 產生器,這些命令列或自訂命令將會針對特定組態省略,並且不會新增「空字串命令」。

這允許為每個組態新增個別的建置事件。

在版本 3.21 中新增:支援依賴目標的產生器運算式。

在版本 3.29 中新增:<target> 可以是 ALIAS 目標

範例:建置事件

POST_BUILD 事件可用於在連結後後處理二進制檔案。例如,以下程式碼

add_executable(myExe myExe.c)
add_custom_command(
  TARGET myExe POST_BUILD
  COMMAND someHasher -i "$<TARGET_FILE:myExe>"
                     -o "$<TARGET_FILE:myExe>.hash"
  VERBATIM)

將執行 someHasher 以在連結後在可執行檔旁邊產生 .hash 檔案。

在版本 3.20 中新增:可以使用產生器運算式來指定每個組態的副產品。例如,以下程式碼

add_library(myPlugin MODULE myPlugin.c)
add_custom_command(
  TARGET myPlugin POST_BUILD
  COMMAND someHasher -i "$<TARGET_FILE:myPlugin>"
                     --as-code "myPlugin-hash-$<CONFIG>.c"
  BYPRODUCTS "myPlugin-hash-$<CONFIG>.c"
  VERBATIM)
add_executable(myExe myExe.c "myPlugin-hash-$<CONFIG>.c")

將在連結 myPlugin 後執行 someHasher,例如,產生一個 .c 檔案,其中包含用於檢查 myPlugin 的雜湊值的程式碼,myExe 可執行檔可以使用該程式碼在載入之前驗證它。

Ninja 多組態

在版本 3.20 中新增:add_custom_command 支援 Ninja 多組態 產生器的跨組態功能。有關更多資訊,請參閱產生器文件。

另請參閱