也许这是不可能的,我误读cmake 3.2 documentation,但我创建一个自定义命令会在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
。
答案 0 :(得分:12)
add_custom_command
不会创建新目标。您必须由add_executable
,add_library
或add_custom_target
明确定义目标,以使其可见。
如果您需要解决部署问题,可以
1。使用install
命令(在您的CMakeLists.txt中的某个位置),如下所示:
install(SCRIPT <dir>/post_install.cmake)
存储仅在单独的 .cmake 文件中运行make install
时执行的命令。或者,如果安装目标已经被保留用于其他事情,或者您正在进行更复杂的事情:
2。手动定义部署目标。完成后,您可以创建自定义的构建后命令,该命令仅在您在 deploy 目标上显式运行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,因为它只是更清洁。
希望这有帮助!
答案 1 :(得分:7)
CMake的文档在这里不清楚。 CMake的Makefile生成器会在子Makefile中创建源文件make规则,这些规则在主Makefile中不可见。在主Makefile中,您只能找到CMake目标的PHONY规则。我所知道的唯一例外是Ninja
Makefile应用程序将所有构建规则放入单个文件中。
根据我的经验 - 如果post_process
是一个脚本 - 你应该考虑用/在CMake脚本中重写你的后处理步骤,因为CMake应该知道用于post的所有文件依赖性和变量处理(然后它将为您处理所有必要的重建或清理步骤)。
以下是我所做的简化/修改版本:
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文件。我raised an issue对此有所了解,希望通过扩展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)
您无法在OUTPUT
本身声明add_custom_target()
,但在这种情况下您不想(因为您不希望有任何命名混淆)。但是如果你没有宣布任何产出:
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的bug追踪器上发布了这个问题:
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)
答案 2 :(得分:1)
转换依赖关系,并使用second signature of 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
会导致(例如)ninja说
多个规则生成foo_out。涉及此目标的构建将不正确;无论如何继续