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
將
COMMAND
和DEPENDS
選項的值附加到第一個指定輸出的自訂命令。之前必須已經有使用相同輸出的這個命令呼叫。如果先前的呼叫透過產生器運算式指定輸出,則目前的呼叫指定的輸出在評估產生器運算式後,至少在一個組態中必須符合。在這種情況下,附加的命令和依賴關係適用於所有組態。
當給定
APPEND
時,目前會忽略COMMENT
、MAIN_DEPENDENCY
和WORKING_DIRECTORY
選項,但未來可能會使用它們。BYPRODUCTS
在版本 3.2 中新增。
指定命令預期會產生的檔案,但這些檔案的修改時間可能不比依賴關係新。如果副產品名稱是相對路徑,它將會相對於對應於目前來源目錄的建置樹目錄來解譯。每個副產品檔案都會自動標記
GENERATED
來源檔案屬性。請參閱政策
CMP0058
以了解此功能背後的動機。Ninja
產生器支援明確指定副產品,以告知ninja
建置工具如何在副產品遺失時重新產生它們。當其他建置規則(例如自訂命令)依賴副產品時,這也很有用。 Ninja 需要為另一個規則所依賴的任何產生檔案提供建置規則,即使存在順序依賴,以確保副產品在建置其依賴項之前可用。Makefile 產生器 會在
make clean
期間移除BYPRODUCTS
和其他GENERATED
檔案。此關鍵字無法與
APPEND
一起使用(請參閱政策CMP0175
)。所有副產品必須在第一次對輸出檔案呼叫add_custom_command(OUTPUT...)
時設定。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
指定命令所依賴的檔案。每個引數都會轉換為如下的依賴關係:
如果參數是目標的名稱(由
add_custom_target()
、add_executable()
或add_library()
指令建立),則會建立目標級別的依賴關係,以確保在使用此自訂指令的任何目標之前先建置該目標。此外,如果目標是可執行檔或函式庫,則會建立檔案級別的依賴關係,以便在重新編譯目標時重新執行自訂指令。如果參數是絕對路徑,則會在該路徑上建立檔案級別的依賴關係。
如果參數是已新增至目標或已設定來源檔案屬性的來源檔案名稱,則會在該來源檔案上建立檔案級別的依賴關係。
如果參數是相對路徑,並且存在於目前的來源目錄中,則會在目前來源目錄中的該檔案上建立檔案級別的依賴關係。
否則,會在相對於目前二進位目錄的路徑上建立檔案級別的依賴關係。
如果任何依賴項是同一目錄(
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
請求掃描輸入檔案的隱含依賴關係。給定的語言指定應使用其對應依賴項掃描器的程式設計語言。目前僅支援
C
和CXX
語言掃描器。必須為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 Makefiles
、MSYS Makefiles
和MinGW Makefiles
產生器,這會在配方行中新增+
字首。請參閱 GNU Make 文件,以取得更多資訊。其他產生器會無聲地忽略此選項。
此關鍵字不能與
APPEND
一起使用(請參閱原則CMP0175
)。只能在首次呼叫輸出檔案的add_custom_command(OUTPUT...)
時指定工作伺服器感知。
MAIN_DEPENDENCY
指定指令的主要輸入來源檔案。它會被視為給定給
DEPENDS
選項的任何值,但也建議 Visual Studio 產生器將自訂指令掛在何處。每個來源檔案最多可以有一個指令指定其為主要依賴項。編譯指令(即針對函式庫或可執行檔)會被視為隱含的主要依賴項,會被自訂指令規格無聲地覆寫。如果給定
APPEND
,目前會忽略此選項,但未來的版本可能會使用它。OUTPUT
指定指令預期產生的輸出檔案。每個輸出檔案都會自動標記
GENERATED
來源檔案屬性。如果自訂指令的輸出實際上不是在磁碟上建立為檔案,則應使用SYMBOLIC
來源檔案屬性標記它。如果輸出檔案名稱是相對路徑,則其絕對路徑是透過相對於以下位置解譯來決定的:
對應於目前來源目錄的建置目錄(
CMAKE_CURRENT_BINARY_DIR
),或目前的來源目錄(
CMAKE_CURRENT_SOURCE_DIR
)。
除非來源樹中的路徑在目前目錄的其他位置被提及為絕對來源檔案路徑,否則會優先使用建置目錄中的路徑。
輸出檔案路徑不得包含
<
或>
字元。在 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 產生器指定
DEPFILE
和IMPLICIT_DEPENDS
選項。在 3.21 版本加入: 加入了對 VS 2012 及更高版本的 Visual Studio 產生器以及
Xcode
產生器的支援。也加入了對產生器 表達式
的支援。在 3.29 版本加入: 如果檔案未列在
OUTPUTS
或BYPRODUCTS
中,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.c
。someTool
會被建置為相依性,但 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
。由於 foo
和 bar
是可以並行建置的獨立目標,我們透過將產生 table.csv
的自訂命令放置在單獨的目標 generate_table_csv
中,來防止它們競爭產生 table.csv
。產生 foo.cxx
和 bar.cxx
的自訂命令各自指定對 generate_table_csv
的目標級別依賴性,因此使用它們的目標 foo
和 bar
將在目標 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
產生器的跨組態功能。請參閱產生器文件以取得更多資訊。