[英]add_custom_command is not generating a target
也許這是不可能的,並且我誤讀了cmake 3.2文檔 ,但我雖然創建了一個自定義命令,但會在Makefile中創建一個自定義的“目標”,以便我可以通過調用輸出文件的名稱來構建目標。 CMake文檔說:
用makefile術語,它以以下形式創建一個新目標:
OUTPUT: MAIN_DEPENDENCY DEPENDS COMMAND
所以我想我可以再運行make OUTPUT
。 也許文檔使CMake目標與Makefile目標混淆了?
例如,
add_custom_command(OUTPUT foo_out
COMMAND post_process foo_in > foo_out
DEPENDS foo_in
)
我想要做
make foo_out
它將成為foo_out
。 但是,如果我這樣做,我得到
make: **** No rule to make target `foo_out`. Stop.
並且可以肯定的是,在cmake二進制輸出目錄中的任何文件中的任何地方都不存在單詞“ foo_out”。 如果我改成這個
add_custom_target(bar DEPENDS foo_out)
add_custom_command(OUTPUT foo_out COMMAND post_process foo_in > foo_out)
那我就可以
make bar
我可以做
make foo_in
但我還是做不到
make foo_out
make bar
的問題在於它不直觀,因為實際文件輸出是foo_out
而不是bar
。
我該怎么做呢?
就我而言,我需要對標准可執行目標執行一個特殊的處理步驟,該步驟將可選資源插入到ELF文件中。 我希望能夠將兩個可執行文件都作為Makefile目標,因此我可以構建裸露的ELF可執行文件以及資源注入的ELF可執行文件。
如果我正在編寫自定義的Makefile,這很簡單!
foo_in: foo.c
$(CC) $< -o $@
foo_out: foo_in
post_process $< > $@
我可以做make foo_in
和make foo_out
。
add_custom_command
不會創建一個新的目標。 您必須通過add_executable
, add_library
或add_custom_target
顯式定義目標,以使其可見。
如果您必須為部署進行修復,則可以
1.使用install
命令(在CMakeLists.txt中的某個位置),如下所示:
install(SCRIPT <dir>/post_install.cmake)
將僅當您運行make install
時執行的命令存儲在單獨的.cmake文件中。 或者,如果安裝目標已經預留給其他用途,或者您正在執行更復雜的操作:
2.手動定義部署目標。 一旦了解了這一點,就可以創建一個自定義的生成后命令,該命令僅在您在部署目標上顯式運行make時才執行。 這使您可以通過單獨的目標執行命令。
在您的CMakeLists.txt中,它可能類似於:
cmake_minimum_required(VERSION 3.0)
add_executable("App" <sources>)
# option 1: do deployment stuff only when installing
install(SCRIPT <dir>/post_install.cmake)
# option 2: define a deploy target and add post-build commands
add_custom_target("deploy")
add_custom_command(TARGET "deploy" POST_BUILD <some command>)
兩種方法都可以讓您將開發版本與昂貴的現成部署版本分開(如果我理解正確,那就是這里的目標)。 我建議選擇1,因為它更干凈。
希望這可以幫助!
CMake的文檔在這里不清楚。 CMake的Makefiles生成器會在子Makefile中創建源文件make規則,這些規則在主Makefile中不可見。 在主Makefile中,您只會找到CMake目標的PHONY規則。 我知道的唯一例外是Ninja
Makefiles生成器,它將所有構建規則放入單個文件中。
根據我的經驗-如果post_process
是腳本-您可能應該考慮使用CMake腳本/在其中編寫重寫后處理步驟,因為CMake應該知道用於后處理的所有文件依賴項和變量(然后它將處理所有必要的重建或清理步驟)。
這是我的工作的簡化/修改版本:
function(my_add_elf _target)
set(_source_list ${ARGN})
add_executable(${_target}_in ${_source_list})
set_target_properties(
${_target}_in
PROPERTIES
POSITION_INDEPENDENT_CODE 0
SUFFIX .elf
)
add_custom_command(
OUTPUT ${_target}_step1.elf
COMMAND some_conversion_cmd $<TARGET_FILE:${_target}_in> > ${_target}_step1.elf
DEPENDS ${_target}_in
)
add_custom_target(
${_target}_step1
DEPENDS
${_target}_step1.elf
)
add_custom_command(
OUTPUT ${_target}_out.elf
COMMAND final_post_process_cmd ${_target}_step1.elf > ${_target}_out.elf
DEPENDS ${_target}_step1
)
add_custom_target(
${_target}_out
DEPENDS
${_target}_out.elf
)
# alias / PHONY target
add_custom_target(${_target} DEPENDS ${_target}_out)
endfunction(my_add_elf)
然后打電話
my_add_elf(foo foo.c)
這只是一個示例,但我希望它能給出一個主意:您可以為最終的ELF輸出調用make foo
為其他步驟之一調用make foo_in
或make foo_step1
。 而且我認為所有步驟對於用戶和CMake都是透明的。
當您嘗試給自定義目標與其輸出之一相同的名稱時,例如:
add_executable(foo_in foo.c)
add_custom_command(
OUTPUT foo_out
COMMAND post_process foo_in > foo_out
DEPENDS foo_in
)
add_custom_target(foo_out DEPENDS foo_out)
您最終將獲得無效的make文件。 我提出了一個與此有關的問題 ,希望可以通過擴展CMake本身來解決問題,並得到以下答復:
CMake不能在Makefile中產生特定的內容。 由add_custom_target創建的頂級目標名稱始終是邏輯(即偽)名稱。 完全不允許具有相同名稱的文件。
因此,有一些解決方法,但是它們都有一個或另一個缺點。
1.最短版本:
macro(my_add_elf_we _target)
add_executable(${_target}_in ${ARGN})
add_custom_target(
${_target}_out
COMMAND post_process $<TARGET_FILE:${_target}_in> > ${_target}_out
DEPENDS ${_target}_in
)
set_property(DIRECTORY APPEND PROPERTY ADDITIONAL_MAKE_CLEAN_FILES ${_target}_out)
endmacro(my_add_elf_we)
您不能在add_custom_target()
本身中聲明OUTPUT
,但是在這種情況下,您不想這樣做(因為您不希望有任何命名混亂)。 但是,如果您不聲明任何輸出:
clean
構建規則 2.強制輸出名稱版本
這是上面的宏版本,可將目標名稱和輸出名稱強制為給定值:
macro(my_add_elf_in_out _target_in _target_out)
add_executable(${_target_in} ${ARGN})
set_target_properties(
${_target_in}
PROPERTIES
SUFFIX ""
OUTPUT_NAME "${_target_in}"
)
add_custom_target(
${_target_out}
COMMAND post_process ${_target_in} > ${_target_out}
DEPENDS ${_target_in}
)
set_property(DIRECTORY APPEND PROPERTY ADDITIONAL_MAKE_CLEAN_FILES ${_target_out})
endmacro(my_add_elf_in_out)
您用以下方式調用它:
my_add_elf_in_out(foo_in.elf foo_out.elf foo.c)
3.對象庫版本
以下版本使用對象庫,但是系統不會重用foo_in
目標鏈接:
macro(my_add_elf_obj_in_out _target_in _target_out)
add_library(${_target_in}_obj OBJECT ${ARGN})
add_executable(${_target_in} $<TARGET_OBJECTS:${_target_in}_obj>)
set_target_properties(
${_target_in}
PROPERTIES
SUFFIX ""
OUTPUT_NAME "${_target_in}"
)
add_executable(${_target_out} $<TARGET_OBJECTS:${_target_in}_obj>)
set_target_properties(
${_target_out}
PROPERTIES
SUFFIX ""
OUTPUT_NAME "${_target_out}"
EXCLUDE_FROM_ALL 1
)
add_custom_command(
TARGET ${_target_out}
POST_BUILD
COMMAND post_process ${_target_in} > ${_target_out}
)
endmacro(my_add_elf_obj_in_out)
4.最終版本
最后一個絕對只適用於Makefile生成器的最終版本,讓我在CMake的錯誤跟蹤器中發布了該問題:
macro(my_add_elf_ext_in_out _target_in _target_out)
add_executable(${_target_in} ${ARGN})
set_target_properties(
${_target_in}
PROPERTIES
SUFFIX ""
OUTPUT_NAME "${_target_in}"
)
add_executable(${_target_out} NotExisting.c)
set_source_files_properties(
NotExisting.c
PROPERTIES
GENERATED 1
HEADER_FILE_ONLY 1
)
set_target_properties(
${_target_out}
PROPERTIES
SUFFIX ""
OUTPUT_NAME "${_target_out}"
RULE_LAUNCH_LINK "# "
)
add_custom_command(
TARGET ${_target_out}
POST_BUILD
COMMAND post_process ${_target_in} > ${_target_out}
)
add_dependencies(${_target_out} ${_target_in})
endmacro(my_add_elf_ext_in_out)
轉過來的依賴項,並使用add_custom_command
的第二個簽名 ,這應該工作:
add_custom_target(foo_out DEPENDS foo_in)
add_custom_command(TARGET foo_out POST_BUILD COMMAND post_process foo_in > foo_out)
注意:添加BYPRODUCTS foo_out
將導致(例如) 忍者說
多個規則生成foo_out。 涉及此目標的構建將是不正確的; 反正繼續
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.