【CMake】cmake的add_custom_command和add_custom_target指令
在很多時候,需要在cmake中創建一些目標,如clean、copy等等,這就需要通過add_custom_target來指定。同時,add_custom_command可以用來完成對add_custom_target生成的target的補充。
add_custom_target
如果你寫過MakeFile,那么一定知道,可以設定很多的目標來make,如:
target ... : prerequisites ... command其中:
- target是下面的命令的目標,即下面命令是為了target而生的。這個目標可以是*.o文件,也可以是可執行文件;
 - prerequisites則是生成該目標所依賴的文件,如果找不到依賴的文件,下面的命令就不會執行且會中斷make;
 - command就是生成目標文件的命令,一般就是編譯命令。
 
那么,如果使用CMakeLists.txt如何也生成一個目標來make呢?
這就是add_custom_target的用處:增加一個沒有輸出的目標,使得它總是被構建。
add_custom_target(Name [ALL] [command1 [args1...]][COMMAND command2 [args2...] ...][DEPENDS depend depend depend ... ][BYPRODUCTS [files...]][WORKING_DIRECTORY dir][COMMENT comment][JOB_POOL job_pool][VERBATIM] [USES_TERMINAL][COMMAND_EXPAND_LISTS][SOURCES src1 [src2...]])乍一看,該命令有很多的參數,但其實我們并不需要全部了解,甚至一般情況下只需要用到其中的兩三個。
例如:
cmake_minimum_required(VERSION 3.0) project(test)add_custom_target(CopyTaskCOMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_CURRENT_SOURCE_DIR}/config ${CMAKE_CURRENT_SOURCE_DIR}/etcCOMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/log.txt ${CMAKE_CURRENT_SOURCE_DIR}/etc)運行該CMakeLists.txt:
mkdir build && cd build cmake .. make CopyTask運行結果為:
yngzmiao@yngzmiao-virtual-machine:~/test/build$ rm -r *;cmake .. -- The C compiler identification is GNU 5.4.0 -- The CXX compiler identification is GNU 5.4.0 -- Check for working C compiler: /usr/bin/cc -- Check for working C compiler: /usr/bin/cc -- works -- Detecting C compiler ABI info -- Detecting C compiler ABI info - done -- Detecting C compile features -- Detecting C compile features - done -- Check for working CXX compiler: /usr/bin/c++ -- Check for working CXX compiler: /usr/bin/c++ -- works -- Detecting CXX compiler ABI info -- Detecting CXX compiler ABI info - done -- Detecting CXX compile features -- Detecting CXX compile features - done -- Configuring done -- Generating done -- Build files have been written to: /home/yngzmiao/test/build yngzmiao@yngzmiao-virtual-machine:~/test/build$ make CopyTask Scanning dependencies of target CopyTask Built target CopyTask命令行的打印信息看不出什么東西,但是如果根目錄下有config文件夾,或者有log.txt文件,那么文件夾內的文件和log.txt會被拷貝到etc文件夾下。
初始目錄結構,如下:
|---build |---config|---log.log |---CMakeLists.txt |---log.txt運行后目錄結構,如下:
|---build |---config|---log.log |---etc|---log.log|---log.txt |---CMakeLists.txt |---log.txt其實可以看出,這段代碼的目的就是將config文件夾的內容和log.txt文件復制到新的etc文件夾內。
add_custom_target生成一個目標CopyTask,該目標是用來復制文件夾或者復制文件的!也就是COMMAND中定義的操作。
其中:${CMAKE_COMMAND}是CMake的路徑,-E使CMake運行命令而不是構建,copy_directory和copy是cmake_command_line,再后面兩個就是command_line的參數。
當然,生成文件不僅僅只能是復制,還可以是其他的操作。而這些COMMAND操作,都在command_line中規定了。
至于cmake_command_line的內容,可參考cmake的官方資料:Run a Command-Line Tool。
該命令的其他一些參數的含義:
- ALL:表明該目標會被添加到默認的構建目標,使得它每次都被運行;
 - COMMAND:指定要在構建時執行的命令行;
 - DEPENDS:指定命令所依賴的文件;
 - COMMENT:在構建時執行命令之前顯示給定消息;
 - WORKING_DIRECTORY:使用給定的當前工作目錄執行命令。如果它是相對路徑,它將相對于對應于當前源目錄的構建樹目錄;
 - BYPRODUCTS:指定命令預期產生的文件。
 
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][VERBATIM] [APPEND] [USES_TERMINAL][COMMAND_EXPAND_LISTS])例如:
cmake_minimum_required(VERSION 3.0) project(test)add_custom_command(OUTPUT COPY_RESCOMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_CURRENT_SOURCE_DIR}/config ${CMAKE_CURRENT_SOURCE_DIR}/etcCOMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/log.txt ${CMAKE_CURRENT_SOURCE_DIR}/etc)add_custom_target(CopyTask ALL DEPENDS COPY_RES)add_custom_target生成一個目標CopyTask,該目標依賴于COPY_RES。而對于COPY_RES而言,它實際上是用來復制文件夾或者復制文件的!也就是COMMAND中定義的操作。
該命令的其他一些參數的含義:
- OUTPUT:指定命令預期產生的輸出文件。如果輸出文件的名稱是相對路徑,即相對于當前的構建的源目錄路徑;
 - COMMAND:指定要在構建時執行的命令行;
 - DEPENDS:指定命令所依賴的文件;
 - COMMENT:在構建時執行命令之前顯示給定消息;
 - WORKING_DIRECTORY:使用給定的當前工作目錄執行命令。如果它是相對路徑,它將相對于對應于當前源目錄的構建樹目錄;
 - DEPFILE:為生成器指定一個.d depfile .d文件保存通常由自定義命令本身發出的依賴關系;
 - MAIN_DEPENDENCY:指定命令的主要輸入源文件;
 - BYPRODUCTS:指定命令預期產生的文件。
 
構建事件
這種場景是:為某個目標(如庫或可執行程序)添加一個定制命令。
這種定制命令可以設置在,構建這個目標過程中的某些時機。也就是就,這種場景可以在目標構建的過程中,添加一些額外執行的命令。這些命令本身將會成為該目標的一部分。注意,僅在目標本身被構建過程才會執行。如果該目標已經構建,命令將不會執行。
那么這些時機是什么呢?如下表所示:
| PRE_BUILD | 在目標中執行任何其他規則之前運行 | 
| PRE_LINK | 在編譯源代碼之后,鏈接二進制文件或庫文件之前運行 | 
| POST_BUILD | 在目標內所有其他規則均已執行后運行 | 
其中,PRE_BUILD只被Visual Studio 7及之后的版本支持,其他情況下PRE_BUILD都被視為PRE_LINK。
此時的命令為:
add_custom_command(TARGET <target>PRE_BUILD | PRE_LINK | POST_BUILDCOMMAND command1 [ARGS] [args1...][COMMAND command2 [ARGS] [args2...] ...][BYPRODUCTS [files...]][WORKING_DIRECTORY dir][COMMENT comment][VERBATIM] [USES_TERMINAL])使用方式和第一種場景類似:
cmake_minimum_required(VERSION 3.0) project(test)add_custom_target(CopyTask)add_custom_command(TARGET CopyTaskPOST_BUILDCOMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_CURRENT_SOURCE_DIR}/config ${CMAKE_CURRENT_SOURCE_DIR}/etcCOMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/log.txt ${CMAKE_CURRENT_SOURCE_DIR}/etc)這段代碼的功能和上一段是一樣的,將config文件夾的內容和log.txt文件復制到新的etc文件夾內。
需要注意的是,此時add_custom_command需要寫在add_custom_target之后,否則將cmake不通過。
該命令的其他一些參數的含義:
- TARGET:指定命令運行的目標;
 - COMMAND:指定要在構建時執行的命令行;
 - COMMENT:在構建時執行命令之前顯示給定消息;
 - WORKING_DIRECTORY:使用給定的當前工作目錄執行命令。如果它是相對路徑,它將相對于對應于當前源目錄的構建樹目錄;
 - BYPRODUCTS:指定命令預期產生的文件。
 
add_custom_command總結
其實,可以看出盡管官方給了兩種的使用情景,但是本質上沒有什么區別,區別在于:
- 如果使用OUTPUT參數,需要在目標的構建中指定依賴于該OUTPUT;
 - 如果使用TARGET參數,直接指定目標就可以了。
 
add_custom總結
其實,可以發現,add_custom_command有時候略顯雞肋,因為我們可以將所有的COMMAND都寫到add_custom_target中,不需要add_custom_command來進行補充。
相關閱讀
cmake整理:在編譯時拷貝文件之add_custom_comand 和 add_custom_target
總結
以上是生活随笔為你收集整理的【CMake】cmake的add_custom_command和add_custom_target指令的全部內容,希望文章能夠幫你解決所遇到的問題。
                            
                        - 上一篇: CMake中执行shell命令之exec
 - 下一篇: Veristand制作Custom De