You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

CMake中add_custom_command无法并行执行的原因分析

为什么Makefile生成器会串行执行无依赖的自定义目标?

问题场景

我编写了如下CMake文件:

cmake_minimum_required(VERSION 3.20)

project(foo)

set(srcs "foo.txt")

add_custom_command(
    DEPENDS ${srcs}
    VERBATIM
    OUTPUT "${CMAKE_CURRENT_SOURCE_DIR}/foo1.txt"
    COMMENT "Copying to foo1.txt"
    WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
    COMMAND sleep 5
    COMMAND cp "foo.txt" "foo1.txt"
)

add_custom_target(gen_foo1 DEPENDS "foo1.txt")

add_custom_command(
    DEPENDS ${srcs}
    VERBATIM
    OUTPUT "${CMAKE_CURRENT_SOURCE_DIR}/foo2.txt"
    COMMENT "Copying to foo2.txt"
    WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
    COMMAND sleep 5
    COMMAND cp "foo.txt" "foo2.txt"
)

add_custom_target(gen_foo2 DEPENDS "foo2.txt")

执行构建步骤:

> mkdir build
> cmake ..
-- Configuring done (0.0s)
-- Generating done (0.0s)
-- Build files have been written to: ..../build
> time make -j2 gen_foo1 gen_foo2
[100%] Copying to foo1.txt
[100%] Built target gen_foo1
[100%] Copying to foo2.txt
[100%] Built target gen_foo2

real    0m10.088s
user    0m0.030s
sys     0m0.043s

两个自定义目标无依赖关系,但Makefile生成器下串行运行耗时约10秒,而Ninja构建仅需5秒,请问原因是什么?


核心原因:Make对源目录输出的隐含目录依赖

当自定义命令将输出文件生成到源代码目录(CMAKE_CURRENT_SOURCE_DIR)时,Makefile生成器会触发Make本身的隐含机制:

  • Make会跟踪目录的修改状态,任何修改目录内容的目标都会被标记为更新了目录的时间戳。
  • 其他需要修改同一目录的目标会被Make判定为依赖于该目录的最新状态,因此必须等待前一个目标执行完成后才能启动,最终导致串行执行。

而Ninja生成器的依赖跟踪逻辑更精准,它只会处理CMake明确声明的文件依赖,不会为目录添加这种跨目标的隐含依赖,因此可以并行执行两个独立任务。

解决办法

最直接且符合CMake最佳实践的方式是将输出文件放到构建目录,避免修改源代码目录:
修改两个add_custom_command的OUTPUT和cp命令路径:

# 第一个自定义命令
OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/foo1.txt"
# ...
COMMAND cp "foo.txt" "${CMAKE_CURRENT_BINARY_DIR}/foo1.txt"

# 第二个自定义命令
OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/foo2.txt"
# ...
COMMAND cp "foo.txt" "${CMAKE_CURRENT_BINARY_DIR}/foo2.txt"

如果确实需要在源代码目录生成文件,可以尝试为自定义命令添加BYPRODUCTS属性,或者手动规避Make的目录依赖跟踪,但这种方式不推荐,容易引入其他构建问题。


内容的提问来源于stack exchange,提问作者Timmmm

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 23:49:53