先决条件更改后 Cmake 不重建依赖项

Cmake does not rebuild dependent after prerequisite changes

我有如下依赖图

a.txt <- prereq <- stamp <- dest

其中 prereqdest 是目标,a.txtstamp 是文件。我希望在 a.txt 更改时更新邮票。

为此,我有以下 CMakeLists.txt 文件:

 cmake_minimum_required(VERSION 3.6)
 project(sample)

 # variable holding location of stamp and a.txt file
 set(STAMP ${CMAKE_CURRENT_SOURCE_DIR}/stamp)
 set(ATXT ${CMAKE_CURRENT_SOURCE_DIR}/a.txt)

 add_custom_target(
         prereq
         DEPENDS ${ATXT}
 )


 add_custom_command(
         OUTPUT ${STAMP}
         COMMAND ${CMAKE_COMMAND} -E echo "Update stamp."
         COMMAND ${CMAKE_COMMAND} -E touch ${STAMP}
         DEPENDS prereq
 )

 add_custom_target(dest ALL DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/stamp)

最初,我有以下文件

$ ls
a.txt
CMakeLists.txt

在 运行第一次 cmake 和 make 之后,我们得到了预期的行为,

$ cmake .
$  make
[  0%] Built target prereq
[100%] Generating stamp
Update stamp.
[100%] Built target dest

然而,在触摸 a.txt 之后,我希望 stamp 得到更新,但它没有。

$ touch a.txt
$ make
[  0%] Built target prereq
[100%] Built target dest

这是 cmake 中的错误还是预期的行为?我们如何在每次 prereq 更改时强制 cmake 运行 触摸命令?

DEPENDSadd_custom_target()add_custom_command() 调用中的行为不同。

只需移动 ATXT 作为您的 add_custom_command(OUTPUT ${STAMP} ...) 调用的依赖项应该可以解决问题,因为在 add_custom_target() 中命名非输出文件将不起作用。

add_custom_command() documentation:

DEPENDS: Specify files on which the command depends. If any dependency is an OUTPUT of another custom command in the same directory (CMakeLists.txt file) CMake automatically brings the other custom command into the target in which this command is built. If DEPENDS is not specified the command will run whenever the OUTPUT is missing.

add_custom_target() documentation:

DEPENDS: Reference files and outputs of custom commands created with add_custom_command() command calls in the same directory (CMakeLists.txt file).

add_custom_target()中的DEPENDS参数仅用于确定target/custom调用依赖。

编辑:"Late Dependency Injection"

的备选方案
  1. 如果您在同一个 CMakeLists.txt 文件中,您可以 APPEND 依赖于先前的自定义命令 OUTPUT:

    add_custom_command(
        OUTPUT ${STAMP}
        COMMAND ${CMAKE_COMMAND} -E echo "Update stamp."
        COMMAND ${CMAKE_COMMAND} -E touch ${STAMP}
    )
    
    add_custom_target(dest ALL DEPENDS ${STAMP})
    
    add_custom_command(
        OUTPUT ${STAMP}
        DEPENDS ${ATXT}
        APPEND
    )
    
  2. 您可以添加一些虚拟输出来为您的 prereq 目标提供自定义命令,但要重新触发 dest 的构建,您需要触摸一些输入或删除 dest 的输出(add_dependencies() 本身不会重新触发自定义目标,它只是确保一个在另一个之前被调用):

    add_custom_command(
        OUTPUT ATxtCheck
        COMMAND ${CMAKE_COMMAND} -E remove ${STAMP}
        COMMAND ${CMAKE_COMMAND} -E touch ATxtCheck
        DEPENDS ${ATXT}
    )
    
    add_custom_target(prereq DEPENDS ATxtCheck)
    
    add_custom_command(
        OUTPUT ${STAMP}
        COMMAND ${CMAKE_COMMAND} -E echo "Update stamp."
        COMMAND ${CMAKE_COMMAND} -E touch ${STAMP}
        DEPENDS prereq
    )
    
    add_custom_target(dest ALL DEPENDS ${STAMP})
    

参考资料

  • Why does CMake make a distinction between a "target" and a "command"?
  • cmake: struggling with add_custom_command dependencies