文档不清楚
CMake 的文档在这里不清楚。 CMake 的 Makefile 生成器确实在子 Makefile 中创建源文件 make 规则,这些规则在主 Makefile 中不可见。在主 Makefile 中,您只会找到 CMake 目标的 PHONY 规则。我知道的唯一例外是Ninja
将所有构建规则放入单个文件的 Makefiles 生成器。
将后处理步骤转换为 CMake
根据我的经验 - 如果 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)
这只是一个示例,但我希望它给出了一个想法:您可以调用 make foo 来获取最终的 ELF 输出,调用 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)
您不能在add_custom_target() 本身中声明OUTPUTs,但在这种情况下您不想这样做(因为您不想有任何命名混淆)。但是如果你不声明任何输出:
- 目标将始终被视为已过期
- 您需要在
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)
一些参考资料