英文:
CMake POST_BUILD custom command ignores file dependencies
问题
我想在每次构建我的项目后运行一个脚本,但也要在任何依赖文件更改时运行。现在我有:
add_custom_command(
TARGET kernel POST_BUILD
# doesn't work :(
DEPENDS build-iso.sh limine.cfg
BYPRODUCTS ${CMAKE_BINARY_DIR}/kernel.iso
COMMAND ./build-iso.sh $<TARGET_FILE:kernel> ${CMAKE_BINARY_DIR}/kernel.iso ${CMAKE_BINARY_DIR}/iso_root
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
VERBATIM
)
如果我编辑源代码中的任何内容,它可以正常工作,但如果我只更改了limine.cfg
上的某些内容,该命令不会在cmake --build build
上运行。
英文:
I want to run a script every time my project has been built, but also if any of the dependency files have changed. Right now I have:
add_custom_command(
TARGET kernel POST_BUILD
# doesn't work :(
DEPENDS build-iso.sh limine.cfg
BYPRODUCTS ${CMAKE_BINARY_DIR}/kernel.iso
COMMAND ./build-iso.sh $<TARGET_FILE:kernel> ${CMAKE_BINARY_DIR}/kernel.iso ${CMAKE_BINARY_DIR}/iso_root
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
VERBATIM
)
It works fine if I edit any of the source code, but if I only change something on limine.cfg
, the command isn't ran on cmake --build build
答案1
得分: 1
根据文档所述,
该命令成为目标的一部分,仅在目标自身构建时才执行。如果目标已经构建,命令将不会执行。
参见:https://cmake.org/cmake/help/latest/command/add_custom_command.html#build-events
因此,limine.cfg
被修改并不重要,因为 kernel
还没有构建。
POST_BUILD
加上 BYPRODUCTS
通常表示您希望使用目标的 OUTPUT
,并具有对该目标的依赖性,再加上一个自定义目标以驱动 OUTPUT
命令。类似于这样:
set(kernel_iso "${CMAKE_CURRENT_BINARY_DIR}/kernel.iso")
set(iso_root "${CMAKE_CURRENT_BINARY_DIR}/iso_root")
set(build_script "${CMAKE_CURRENT_SOURCE_DIR}/build-iso.sh")
add_custom_command(
OUTPUT "${kernel_iso}"
COMMAND "${build_script}" "<TARGET_FILE:kernel>" "${kernel_iso}" "${iso_root}"
DEPENDS
"${build_script}"
limine.cfg
kernel # 文件级别依赖于 `kernel`。
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
VERBATIM
)
add_custom_target(kernel_iso ALL DEPENDS "${kernel_iso}")
请注意,<TARGET_FILE:kernel>
生成表达式隐含地添加了对 kernel
的目标级别依赖性,但没有文件级别的依赖性。这意味着构建 kernel_iso
不会使 kernel
更新。通过在 DEPENDS
中命名 kernel
,我们建立了必要的文件级别依赖性。
英文:
As the documentation says,
> The command becomes part of the target and will only execute when the target itself is built. If the target is already built, the command will not execute.
<sup>See: https://cmake.org/cmake/help/latest/command/add_custom_command.html#build-events</sup>
So it does not matter that limine.cfg
was modified because kernel
wasn't built.
POST_BUILD
plus BYPRODUCTS
is usually a sign that you want OUTPUT
with a dependency on that target, plus a custom target to drive the OUTPUT
command. Something like this:
set(kernel_iso "${CMAKE_CURRENT_BINARY_DIR}/kernel.iso")
set(iso_root "${CMAKE_CURRENT_BINARY_DIR}/iso_root")
set(build_script "${CMAKE_CURRENT_SOURCE_DIR}/build-iso.sh")
add_custom_command(
OUTPUT "${kernel_iso}"
COMMAND "${build_script}" "$<TARGET_FILE:kernel>" "${kernel_iso}" "${iso_root}"
DEPENDS
"${build_script}"
limine.cfg
kernel # File-level dependency on `kernel`.
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
VERBATIM
)
add_custom_target(kernel_iso ALL DEPENDS "${kernel_iso}")
Note that the $<TARGET_FILE:kernel>
generator expression implicitly adds a target-level dependency on kernel
, but not a file-level dependency. This would mean that building kernel_iso
would not bring kernel
up to date. By naming kernel
in DEPENDS
, we establish the necessary file-level dependency.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论