c++ - 在自定义目标运行后重建依赖目标
问题描述
我有一个 CMake 项目,它使用外部工具为某个平台构建特殊库。运行此工具使用“配置文件”生成几个文件,这些文件在构建最终程序时注入编译器和链接器选项:
- 对象库
- 一个链接器命令文件,它链接了几个预编译的库和上述对象库
- 设置各种平台编译器选项的 makefile 选项文件
每当这些文件中的任何一个发生更改时,都必须完全重建主程序,因为它们是程序的固有部分,并且涉及编译器标志和系统包含等内容。
到目前为止,我有这样的东西,这似乎是一种推荐的方式:
# 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}
)
这也几乎是在这个问题中所做的。
当我更改配置文件时,platform_libs
目标运行并根据需要生成库和其他文件。然而,虽然运行make main_prog
确实触发了platform_libs
正确的构建,但它似乎没有“注意到”任何变化,因此得出结论它不需要实际重新构建主程序。
我总是可以运行make clean
,但是让 CMake 对基本系统库的变化完全视而不见并不是很好。
如果已经运行,我该如何强制main_prog
重建?platform_libs
解决方案
[这个答案的中心方法来自@KamilCuk 在问题评论中的回答]。
诀窍是使用以下之一:
LINK_DEPENDS
在下游目标上设置属性(main_prog
在示例中) - 这意味着如果此属性中的文件发生更改,将执行重新链接。OBJECT_DEPENDS
在用于 的每个源上设置main_prog
。
就我而言,因为它${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
库编译库变得很容易。
推荐阅读
- php - 如果输入值存在于回显中,如何从输入值中发布数据
- javascript - 如何映射两个数组来创建对象?
- operating-system - 如何在分段内存管理中生成逻辑地址
- reactjs - 使用 Formik 降档自动完成 onBlur 重置值
- javascript - TypeError:无法读取 null 的属性“createElement”
- autohotkey - AutoHotKey 可以拦截鼠标点击吗?
- javascript - 如何在另一个数组中找到数组的每个值?
- aws-lambda - 在 Lambda 函数中获取 API Gateway 的 IP 地址(通过 Python)
- perl - 迭代数组引用并在 perl 中转换为哈希
- java - 汤 | 获取部分 HTML