CMake中执行shell命令之execute_process、add_custom_target和add_custom_command
背景
以下情況可能需要在CMake中執(zhí)行shell腳本:
- cmake未提供的功能而實(shí)際構(gòu)建中又需要時(shí),如獲取Linux發(fā)行版本
- 項(xiàng)目構(gòu)建時(shí)需要執(zhí)行腳本才能完成,如boost構(gòu)建過程
有的需要shell腳本的返回值,而有的不需要,這個(gè)關(guān)系不大。本文主要關(guān)注的是在cmake中執(zhí)行shell腳本的方法。
主要涉及三個(gè)命令:execute_process、add_custom_target和add_custom_command。
execute_process
通過execute_process方法可以執(zhí)行多個(gè)子進(jìn)程。
原型如下:
execute_process(COMMAND <cmd1> [<arguments>][COMMAND <cmd2> [<arguments>]]...[WORKING_DIRECTORY <directory>][TIMEOUT <seconds>][RESULT_VARIABLE <variable>][RESULTS_VARIABLE <variable>][OUTPUT_VARIABLE <variable>][ERROR_VARIABLE <variable>][INPUT_FILE <file>][OUTPUT_FILE <file>][ERROR_FILE <file>][OUTPUT_QUIET][ERROR_QUIET][COMMAND_ECHO <where>][OUTPUT_STRIP_TRAILING_WHITESPACE][ERROR_STRIP_TRAILING_WHITESPACE][ENCODING <name>][ECHO_OUTPUT_VARIABLE][ECHO_ERROR_VARIABLE][COMMAND_ERROR_IS_FATAL <ANY|LAST>])命令COMMAND會并行執(zhí)行,每個(gè)子進(jìn)程的標(biāo)準(zhǔn)輸出映射到下一個(gè)進(jìn)程的標(biāo)準(zhǔn)輸入上,所有進(jìn)程共用standard error管道。
各選項(xiàng)說明如下:
- COMMAND: 子進(jìn)程的命令行,直接使用操作系統(tǒng)api執(zhí)行。可以提供多個(gè)command,它們會并行執(zhí)行。如果需要多個(gè)命令順序執(zhí)行,可以調(diào)用execute_process多次
- WORKING_DIRECTORY:在該目錄下執(zhí)行COMMAND命令
- TIMEOUT:超時(shí)時(shí)間,過了這個(gè)時(shí)間,所有子進(jìn)程會被終止,RESULT_VARIABLE會被設(shè)置為“timeout”
- RESULT_VARIABLE:最后一個(gè)子進(jìn)程的返回值(正常是0,異常是其他整數(shù)),或者描述發(fā)生錯(cuò)誤的字符串
- RESULTS_VARIABLE:對應(yīng)于每個(gè)子進(jìn)程的返回值,使用分號分割的列表
- OUTPUT_VARIABLE:對應(yīng)于standard output的內(nèi)容
- ERROR_VARIABLE:對應(yīng)于standard error的內(nèi)容
- INPUT_FILE:第一個(gè)子進(jìn)程的standard input
- OUTPUT_FILE:最后一個(gè)子進(jìn)程的standard output
- ERROR_FILE:所有子進(jìn)程的standard error
- OUTPUT_QUIET/ERROR_QUIET:忽略standard output 和 standard error
- COMMAND_ECHO:重顯命令到指定的標(biāo)準(zhǔn)設(shè)備,如STDERR、STDOUT、NONE。使用CMAKE_EXECUTE_PROCESS_COMMAND_ECHO變量來修改它的行為
- OUTPUT_STRIP_TRAILING_WHITESPACE/ERROR_STRIP_TRAILING_WHITESPACE:刪除空白字符
- ENCODING:在windows系統(tǒng)上指定進(jìn)程輸出時(shí)的解碼方式,默認(rèn)是utf-8,其他平臺會忽略該參數(shù)
- ECHO_OUTPUT_VARIABLE/ECHO_ERROR_VARIABLE:輸出將被復(fù)制,它將被發(fā)送到配置的變量中,也會在標(biāo)準(zhǔn)輸出或標(biāo)準(zhǔn)錯(cuò)誤中,3.18版本支持
- COMMAND_ERROR_IS_FATAL:觸發(fā)致命錯(cuò)誤并終止進(jìn)程執(zhí)行,方式取決于參數(shù)。ANY表示任意命令執(zhí)行失敗都觸發(fā),LAST表示最后一個(gè)進(jìn)程執(zhí)行失敗才觸發(fā),3.19版本支持
示例如下:
cmake_minimum_required(VERSION 3.2)project(cmake_test)execute_process(COMMAND echo "hello world"WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}TIMEOUT 3RESULT_VARIABLE result_varOUTPUT_VARIABLE output_varERROR_VARIABLE error_varOUTPUT_STRIP_TRAILING_WHITESPACEERROR_STRIP_TRAILING_WHITESPACE)message(STATUS "result: ${result_var}") message(STATUS "output: ${output_var}") message(STATUS "error: ${error_var}")輸出如下:
-- result: 0 -- output: hello world -- error:如果要執(zhí)行一個(gè)shell腳本,只需要把echo命令替換為如:bash a.sh 即可。
add_custom_target
添加自定義的沒有輸出的目標(biāo),它總會被構(gòu)建。
原型如下:
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...]])目標(biāo)沒有輸出文件,總是被認(rèn)為是過時(shí)的,可以使用 add_custom_command() 命令生成依賴的文件供 DEPENDS 參數(shù)使用。
常用參數(shù)說明如下:
- Name:目標(biāo)名稱
- ALL:說明該目標(biāo)需要添加到默認(rèn)目標(biāo)的構(gòu)建中,所以命令每次都會被執(zhí)行。注意Name不能是ALL
- COMMAND:構(gòu)建時(shí)執(zhí)行的命令,如果指定了多個(gè)COMMAND,它們將按順序執(zhí)行,但不一定組成有狀態(tài)shell或批處理腳本。(要運(yùn)行完整的腳本,可以使用configure_file命令或GENERATE命令來創(chuàng)建它,然后指定一個(gè)command來啟動它。)
- COMMENT:注釋信息,會在命令執(zhí)行前打印出來
- DEPENDS:通常以同一CMakeLists.txt文件中的add_custom_command()命令生成的文件作為依賴,目標(biāo)構(gòu)建后依賴會被更為最新
- SOURCES:生成目標(biāo)所需要的額外的源文件,它們會被添加到IDE項(xiàng)目文件中
- WORKING_DIRECTORY:執(zhí)行命令的目標(biāo),如果是相對目錄,則以當(dāng)前源文件目錄為基準(zhǔn)
從以上說明可以看出,可以直接使用add_custom_target執(zhí)行shell命令,并且使用DEPENDS可以讓各個(gè)目標(biāo)之間產(chǎn)生關(guān)聯(lián)。
通常和add_custom_command命令配合使用來產(chǎn)生DEPENDS。
比如我們在編譯boost庫時(shí),需要執(zhí)行shell命令,示例如下:
add_custom_target(build_boost_libsCOMMAND ./bootstrap.sh --prefix=/usr/local/boostCOMMAND ./b2 link=static runtime-link=static threading=multi --with-system --with-thread --with-filesystemWORKING_DIRECTORY "${PROJECT_SOURCE_DIR}/boost/" COMMENT "begin build boost libs...")這樣,我們自定義了目標(biāo)build_boost_libs,它是通過兩行命令來構(gòu)建完成的。
關(guān)于add_custom_command,下面介紹。
add_custom_command
為構(gòu)建系統(tǒng)添加自定義的構(gòu)建規(guī)則。
它有兩種形式的原型,下面分別介紹。
生成文件
簽名如下:
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])使用命令生成指定的輸出文件。具體參數(shù)不再說明,詳情可參考后文資料。
使用示例:
add_custom_command(OUTPUT out.cCOMMAND someTool -i ${CMAKE_CURRENT_SOURCE_DIR}/in.txt-o out.cDEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/in.txtVERBATIM)add_library(myLib out.c)這樣,在生成myLib庫時(shí)依賴out.c,而out.c由add_custom_command生成,每次in.txt的變動都會導(dǎo)致add_custom_command中命令的執(zhí)行。
add_custom_command指定的DEPENDS可以是某個(gè)target(通過add_library/add_executable/add_custom_target創(chuàng)建),或者直接是某個(gè)文件。
如果add_custom_command命令不指定DEPENDS的話,那么只要沒有這個(gè)OUTPUT的文件,都會生成自己并執(zhí)行command。
構(gòu)建事件
為庫、可執(zhí)行文件等目標(biāo)添加自定義命令,可以在構(gòu)建目標(biāo)前或者構(gòu)建目標(biāo)后執(zhí)行一些命令。
要執(zhí)行的命令會成為目標(biāo)的一部分,并且只在目標(biāo)構(gòu)建時(shí)執(zhí)行,如果目標(biāo)已經(jīng)構(gòu)建完成,這些命令也不會執(zhí)行。
原型:
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][COMMAND_EXPAND_LISTS])這樣就為指定的target關(guān)聯(lián)了要執(zhí)行的命令,target必須在當(dāng)前目錄里定義。
命令執(zhí)行的時(shí)機(jī):
- PRE_BUILD:在所有規(guī)則執(zhí)行前執(zhí)行
- PRE_LINK:在源文件編譯后且鏈接前執(zhí)行
- POST_BUILD:在所有規(guī)則執(zhí)行后執(zhí)行命令
其他參數(shù)不再說明。
示例:
# 在目標(biāo)構(gòu)建完成后執(zhí)行一些操作 add_executable(myExe myExe.c) add_custom_command(TARGET myExe POST_BUILDCOMMAND someHasher -i "$<TARGET_FILE:myExe>"-o "$<TARGET_FILE:myExe>.hash"VERBATIM)add_custom_target vs add_custom_command
add_custom_target有依賴文件時(shí),經(jīng)常和add_custom_command的生成文件模式搭配使用。
它們之間的關(guān)系比較曖昧,這里說明一下。
當(dāng)add_custom_target所要生成的target依賴add_custom_command所生成的文件時(shí),這個(gè)文件就是一個(gè)紐帶。
add_custom_command命令輸出的OUTPUT文件和命令里的command之間的關(guān)系是:每當(dāng)這個(gè)文件需要被重新生成時(shí),都會執(zhí)行這段command。
這個(gè)文件會不會被生成,取決于構(gòu)建的target是否depends這個(gè)output文件。
這個(gè)文件會不會被重新生成,取決于這個(gè)output文件depends的東西變了沒。
上面也有點(diǎn)繞,舉例說明一下:
add_custom_command(OUTPUT config_bootstrapCOMMAND ./bootstrap.sh --prefix=/usr/localWORKING_DIRECTORY "${PROJECT_SOURCE_DIR}/boost/" COMMENT "begin config_bootstrap")add_custom_target(build_boost_libsCOMMAND ./b2 link=static runtime-link=static threading=multi --with-system --with-thread --with-filesystemWORKING_DIRECTORY "${PROJECT_SOURCE_DIR}/boost/" DEPENDS config_bootstrapCOMMENT "begin build_boost_libs")執(zhí)行流程為:
這個(gè)流程與MakeFile決定是否重新編譯目標(biāo)是一個(gè)道理,它會自動識別模塊間的依賴關(guān)系,并自己構(gòu)建需要構(gòu)建的模塊。
寫cmake的過程,也是告訴cmake模塊間依賴關(guān)系的過程。
小結(jié)
cmake提供了對執(zhí)行自定義命令的支持,可以很方便地使用它們執(zhí)行shell命令。
但它們使用上有一些區(qū)別,比如有的會無條件每次執(zhí)行,有的則依賴于依賴文件是否被更新。
具體使用哪種模式,就看需求了。
參考資料
execute_process
add_custom_target
add_custom_command
總結(jié)
以上是生活随笔為你收集整理的CMake中执行shell命令之execute_process、add_custom_target和add_custom_command的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: echart实现custom自定义色块功
- 下一篇: 【CMake】cmake的add_cus