【CMake】cmake的add_custom_command和add_custom_target指令

在很多時候,需要在cmake中創建一些目標,如cleancopy等等,這就需要通過add_custom_target來指定。同時,add_custom_command可以用來完成對add_custom_target生成的target的補充。

本文實例源碼github地址https://github.com/yngzMiao/yngzmiao-blogs/tree/master/2019Q4/20191029


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(CopyTask
  COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_CURRENT_SOURCE_DIR}/config ${CMAKE_CURRENT_SOURCE_DIR}/etc
  COMMAND ${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_RES
  COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_CURRENT_SOURCE_DIR}/config ${CMAKE_CURRENT_SOURCE_DIR}/etc
  COMMAND ${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_BUILD
                   COMMAND 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 CopyTask
  POST_BUILD
  COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_CURRENT_SOURCE_DIR}/config ${CMAKE_CURRENT_SOURCE_DIR}/etc
  COMMAND ${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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章