CMake 中 A 的 POST_BUILD 命令会先于依赖目标 B 吗?
结论
不能保证在所有生成器下,A 的 POST_BUILD 命令都会在目标 B 开始执行前完成。add_dependencies(B A) 建立了目标级依赖,但 CMake 明确指出,Ninja 生成器的顺序保证较弱:它只保证依赖目标的自定义命令在 B 的源文件开始编译前完成。由于 B 是没有源文件的自定义目标,这项说明无法证明 B 的其他构建操作会等到 A 的 POST_BUILD 完成。
题目中的 add_custom_command(TARGET A POST_BUILD) 缺少必需的 COMMAND,因此不是完整有效的写法。以下分析假设实际代码中补有命令。
文档原文
CMake 的 add_dependencies() 文档 对 Ninja 生成器的说明是:
“The Ninja Generators use weaker ordering than other generators in order to improve available concurrency. They only guarantee that the dependencies’ custom commands are finished before sources in
<target>start compiling; this ensures generated sources are available.”
也就是说,Ninja 为了提高并行度,采用了较弱的依赖排序。它只保证依赖目标的自定义命令在目标源文件开始编译前完成,以确保生成的源文件可用。
add_custom_command() 文档 对 POST_BUILD 的定义是:
“Run after all other rules within the target have been executed.”
因此,A 的 POST_BUILD 会在 A 的其他构建规则执行后运行。这一定义没有说明它会先于依赖目标 B 的所有操作完成。
如何让顺序更明确
如果 B 必须等某项操作完成后再运行,可以将该操作建模为带有明确输出的自定义命令,并让 B 依赖这个输出:
set(post_build_stamp "${CMAKE_CURRENT_BINARY_DIR}/a_post.stamp")
add_custom_command(
OUTPUT "${post_build_stamp}"
COMMAND some_command
COMMAND "${CMAKE_COMMAND}" -E touch "${post_build_stamp}"
DEPENDS A
VERBATIM
)
add_custom_target(B DEPENDS "${post_build_stamp}")
将 some_command 替换为实际操作。这样,B 依赖该命令生成的文件,构建系统可以根据文件级依赖安排执行顺序。如果这项操作还必须作为 A 的 POST_BUILD 事件执行,应结合目标所用的生成器验证事件与输出依赖的具体行为。仅凭题目中的 add_dependencies(B A),无法证明所有生成器都能严格保证先后顺序。
注意事项
POST_BUILD 只会在目标本身被构建时执行。如果 A 已是最新状态且没有触发构建,单独请求构建 B 并不保证 POST_BUILD 会重新运行。题目没有提供 CMake 版本、生成器或 A 的具体类型,因此这里仅说明文档所支持的保证范围。
备注:内容仅供参考。
