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
的引數可以使用產生器表達式
。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
請求掃描輸入檔案的隱含依賴項。給定的語言指定應使用其對應依賴項掃描器的程式語言。目前僅支援
C
和CXX
語言掃描器。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 Makefiles
、MSYS Makefiles
和MinGW Makefiles
產生器,這將為配方行新增+
前綴。有關更多資訊,請參閱 GNU Make 文件。其他產生器會靜默忽略此選項。
此關鍵字不能與
APPEND
一起使用(請參閱政策CMP0175
)。Job server 感知只能在第一次呼叫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
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 中新增:如果檔案未在
OUTPUTS
或BYPRODUCTS
中列出,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.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.cxx
僅目標 foo
需要,而輸出 bar.cxx
僅目標 bar
需要,但 *兩個* 目標都間接地需要 table.csv
。由於 foo
和 bar
是可能同時建置的獨立目標,我們透過將其自訂命令放在單獨的目標 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]
[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 多組態
產生器的跨組態功能。有關更多資訊,請參閱產生器文件。