【问题标题】:Cmake does not rebuild dependent after prerequisite changes在先决条件更改后,Cmake 不依赖重建
【发布时间】:2016-10-13 23:23:04
【问题描述】:

我有如下依赖图

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运行touch命令?

【问题讨论】:

    标签: cmake dependencies rules


    【解决方案1】:

    add_custom_target()add_custom_command() 调用中的DEPENDS 表现不同。

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

    add_custom_command() documentation:

    DEPENDS:指定命令依赖的文件。如果任何依赖项是同一目录(CMakeLists.txt 文件)中另一个自定义命令的OUTPUT,CMake 会自动将另一个自定义命令带入构建此命令的目标中。如果未指定DEPENDS,则只要缺少 OUTPUT,该命令就会运行。

    add_custom_target() documentation:

    DEPENDS:在同一目录(CMakeLists.txt 文件)中使用add_custom_command() 命令调用创建的自定义命令的参考文件和输出。

    add_custom_target() 中的DEPENDS 参数仅用于确定目标/自定义调用依赖关系。

    编辑:“后期依赖注入”的替代方案

    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})
      

    参考文献

    【讨论】:

    • 感谢您的建议。确实你的建议有效,但我首先以这种方式构建 cmake 的原因是因为我想通过使用 add_dependencies 命令动态添加依赖项,并且这只适用于 targets 而不是 output files。如果我在add_custom_command 中使用DEPENDS 命令,那么我将无法使用该命令并且必须明确指定依赖关系。
    • @dzhelil 不客气。您始终可以为分组或依赖注入添加自定义目标,您只需要在附加的自定义命令中移动源文件依赖项。明天我会相应地更新我的答案。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-03-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多