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 的參數可以使用 generator expressions

COMMAND_EXPAND_LISTS

在 3.8 版本中新增。

COMMAND 參數中的清單將會展開,包括使用 generator expressions 建立的清單,允許正確展開 ${CC} "-I$<JOIN:$<TARGET_PROPERTY:foo,INCLUDE_DIRECTORIES>,;-I>" foo.cc 之類的 COMMAND 參數。

此關鍵字不能與 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 清單中的每個檔案指定語言。從掃描中發現的依賴關係會在建置時新增至自訂指令的依賴關係中。請注意,目前僅 Makefile 產生器支援 IMPLICIT_DEPENDS 選項,其他產生器會忽略它。

注意

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

JOB_POOL

在 3.15 版本中新增。

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

此關鍵字不能與 APPEND 一起使用(請參閱原則 CMP0175)。只能在首次呼叫輸出檔案的 add_custom_command(OUTPUT...) 時指定工作集區。

JOB_SERVER_AWARE

在 3.28 版本中新增。

指定指令是否感知 GNU Make 工作伺服器。

對於 Unix MakefilesMSYS MakefilesMinGW Makefiles 產生器,這會在配方行中新增 + 字首。請參閱 GNU Make 文件,以取得更多資訊。

其他產生器會無聲地忽略此選項。

此關鍵字不能與 APPEND 一起使用(請參閱原則 CMP0175)。只能在首次呼叫輸出檔案的 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 中。

此關鍵字不能與 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 產生器的支援。

注意

不能同時為 Makefile 產生器指定 DEPFILEIMPLICIT_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)。Depfile 只能在第一次呼叫 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 僅需要輸出 foo.cxx,而目標 bar 僅需要輸出 bar.cxx,但兩個目標都間接地需要 table.csv。由於 foobar 是可以並行建置的獨立目標,我們透過將產生 table.csv 的自訂命令放置在單獨的目標 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])

這會定義一個新的命令,該命令將與建置指定的 <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 Multi-Config 產生器的跨組態功能。請參閱產生器文件以取得更多資訊。

另請參閱