CMake POST_BUILD自定义命令忽略文件依赖关系

huangapple go评论59阅读模式
英文:

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&#39;t work :(
	DEPENDS build-iso.sh limine.cfg
	BYPRODUCTS ${CMAKE_BINARY_DIR}/kernel.iso
	COMMAND ./build-iso.sh $&lt;TARGET_FILE:kernel&gt; ${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&lt;/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 &quot;${CMAKE_CURRENT_BINARY_DIR}/kernel.iso&quot;)
set(iso_root &quot;${CMAKE_CURRENT_BINARY_DIR}/iso_root&quot;)
set(build_script &quot;${CMAKE_CURRENT_SOURCE_DIR}/build-iso.sh&quot;)

add_custom_command(
    OUTPUT &quot;${kernel_iso}&quot;
    COMMAND &quot;${build_script}&quot; &quot;$&lt;TARGET_FILE:kernel&gt;&quot; &quot;${kernel_iso}&quot; &quot;${iso_root}&quot;
    DEPENDS
      &quot;${build_script}&quot;
      limine.cfg
      kernel  # File-level dependency on `kernel`.
    WORKING_DIRECTORY &quot;${CMAKE_CURRENT_SOURCE_DIR}&quot;
    VERBATIM
)

add_custom_target(kernel_iso ALL DEPENDS &quot;${kernel_iso}&quot;)

Note that the $&lt;TARGET_FILE:kernel&gt; 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.

huangapple
  • 本文由 发表于 2023年7月17日 10:04:12
  • 转载请务必保留本文链接:https://go.coder-hub.com/76701116.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定