在自定义目标运行后重建依赖目标
Posted
技术标签:
【中文标题】在自定义目标运行后重建依赖目标【英文标题】:Rebuild dependant target after a custom target runs 【发布时间】:2020-04-10 11:51:30 【问题描述】:我有一个 CMake 项目,它使用外部工具为某个平台构建特殊库。运行这个工具使用一个“配置文件”来生成几个文件,这些文件在最终程序构建时注入到编译器和链接器选项中:
对象库 链接器命令文件,链接多个预编译库和上述对象库 设置各种平台编译器选项的 makefile 选项文件每当这些文件中的任何一个发生更改时,都必须完全重建主程序,因为它们是程序的固有部分,并且涉及编译器标志和系统包含等内容。
到目前为止,我有这样的东西,appears 是推荐的方式:
# run the external build tool to generate platform libs
# and compiler/linker option files
add_custom_command(
OUTPUT $LINKER_CMD_FILE $COMPILER_OPTS_FILE $PLATFORM_OBJECT_LIB
COMMAND "$EXTERNAL_BUILD_TOOL"
ARGS --config $CFG_FILE
DEPENDS $CFG_FILE
COMMENT "Invoking external build tool for $CFG_FILE"
)
add_custom_target(platform_libs
DEPENDS $LINKER_CMD_FILE $COMPILER_OPTS_FILE $PLATFORM_OBJECT_LIB
)
....
add_executable(main_prog
main.c
)
# whenever any of these change, rebuild
add_dependencies(main_prog platform_libs)
# add the platform compiler opts from the generated file
target_compile_options(main_prog PRIVATE
@$COMPILER_OPTS_FILE
)
这也是in this question所做的。
当我更改配置文件时,platform_libs
目标运行并根据需要生成库和其他文件。然而,虽然运行make main_prog
确实会正确触发platform_libs
的构建,但它似乎没有“注意到”任何变化,因此得出结论它不需要实际重新构建主程序。
我总是可以运行make clean
,但让 CMake 完全忽视基本系统库的变化并不是很好。
如果platform_libs
已运行,我如何强制main_prog
重建?
【问题讨论】:
也许,您还没有显示所有代码,但add_dependencies()
调用不应该在main_prog
上,而不是main_app
?
@squareskittles 抱歉,这是一个错字。真正的目标有不同的名称。
尝试与set_target_property(main_prog LINK_DEPENDS $COMPILER_OPTS_FILE)
或platform_libs
一起做一些事情
@KamilCuk 确实总是强制重新链接,尽管它不强制重新构建源文件(即main.c
),现在可能有不同的编译器选项。
Och,因为当COMPILER_OPTS_FILE
发生变化时,main_prog
的所有源都需要重建。好的,对不起,我错过了。试试看:设置对源文件本身的依赖。遍历main_prog
get_target_property(main_prog SOURCES sources)
中的文件并对每个源执行set_source_files_properties($sources OBJECT_DEPENDS $COMPILER_OPTS_FILE)
。我认为应该这样做。
【参考方案1】:
[此答案的中心方法来自@KamilCuk在问题评论中的回答]。
诀窍是使用以下之一:
在下游目标上设置LINK_DEPENDS
属性(示例中为main_prog
) - 这意味着如果此属性中的文件发生更改,将执行重新链接。
在用于main_prog
的每个源上设置OBJECT_DEPENDS
。
就我而言,因为$COMPILER_OPTS_FILE
会影响每个文件的编译,所以我需要OBJECT_DEPENDS
方法。如果你这样做,你就不需要LINK_DEPENDS
,因为无论如何你都会重新编译你的源代码并重新链接,但为了清楚起见,我做了这两件事。从理论上讲,您可以设计一种情况,即链接器命令文件发生更改,但编译器没有选择,在这种情况下您可能会错过重新链接。
就我而言,我不仅需要为 main_prog
以及所有其他使用的库 main_prog
执行此操作,因此我将链接器命令文件和编译器 opts 文件作为目标属性存储在 platform_libs
目标上:
set_property(TARGET platform_libs
PROPERTY MY_LINKER_CMD_FILE $LINKER_CMD_FILE
)
set_property(TARGET platform_libs
PROPERTY MY_COMPILER_OPTS_FILE $COMPILER_OPTS_FILE
)
这意味着以后很容易将它们取出,而无需知道确切的文件名(甚至可以访问变量本身):
# Retrieve the previously-stored options
# To do this, we only need the target name and the (fixed) property name
get_target_property(MY_LINKER_CMD platform_libs MY_LINKER_CMD_FILE)
get_target_property(MY_COMPILER_OPTS platform_libs MY_COMPILER_OPTS_FILE)
set_target_properties(main_prog PROPERTIES
LINK_DEPENDS $MY_LINKER_CMD
)
# Also set as the linker cmd on the linker command line
# This depends on the linker, for GCC it's -Wl,T<file>
target_link_libraries(main_prog PRIVATE
-Wl,-T$MY_LINKER_CMD
)
# these are the sources that depend on the opts file
get_target_property(MAIN_SRCS main_prog SOURCES)
# set the dependency of source files on platform_libs
set_property(SOURCE $MAIN_SRCS
PROPERTY OBJECT_DEPENDS $MY_COMPILER_OPTS
)
# Set as a compiler opt file
# For GCC: @<opt_file>
target_compile_options($TARGET_TO_COMPILE PRIVATE
@$MY_COMPILER_OPTS
)
# make sure the platform_libs is a dep
# or the compiler opts and linker files won't be generated
add_dependencies(main_prog platform_libs)
值得注意的是,在这段 Cmake 代码中,项目名称 main_prog
和 platform_libs
可以是变量,然后您可以将整个事情变成一个只需要这两个项目名称的函数。这样可以轻松地重用代码来针对 platform_libs
库编译库。
【讨论】:
以上是关于在自定义目标运行后重建依赖目标的主要内容,如果未能解决你的问题,请参考以下文章
尽管没有更改任何来源,但 CMake 会重建自定义目标 [重复]