【问题标题】:How to always run command when building regardless of any dependency?无论任何依赖关系,如何在构建时始终运行命令?
【发布时间】:2012-12-17 18:38:59
【问题描述】:

我想运行一个解析整个源代码树的 cmake 命令,所以我无法在 cmake 的 add_custom_command/add_custom_target 命令中列出所有可能的依赖项。

是否可以告诉 cmake 只是在没有任何条件的情况下运行命令?我尝试了在网上找到的所有解决方案(包括 SO),但他们都认为该命令依赖于少数已知文件是最新的。

我找到了一个解决方案,但它不能可靠地工作:

cmake_minimum_required(VERSION 2.6)

project(main)

add_custom_command(
   OUTPUT file1
   COMMAND echo touching file1
   COMMAND touch file1
   DEPENDS file2)
add_custom_target(dep ALL DEPENDS file1 file2)

# this command re-touches file2 after dep target is "built"
# and thus forces its rebuild
ADD_CUSTOM_COMMAND(TARGET dep
          POST_BUILD
          COMMAND echo touching file2
          COMMAND touch file2
)

这是输出:

queen3@queen3-home:~/testlib$ make
[100%] Generating file1
touching file1
touching file2
[100%] Built target dep
queen3@queen3-home:~/testlib$ make
[100%] Generating file1
touching file1
touching file2
[100%] Built target dep
queen3@queen3-home:~/testlib$ make
touching file2
[100%] Built target dep
queen3@queen3-home:~/testlib$ 

如您所见,在第三次运行时它没有生成 file1,即使之前已触及 file2。有时每 2 次运行一次,有时每 3 次,有时每 4 次。这是一个错误吗?是否有另一种方法可以在 cmake 中运行没有任何依赖关系的命令?

奇怪,但如果我添加 TWO 命令来重新触摸 file2,即只需复制粘贴构建后的命令,它就可以可靠地工作。或者它可能每运行 1000 次就会失败,我还不确定 ;-)

【问题讨论】:

    标签: cmake


    【解决方案1】:

    虽然我对这个解决方案一点也不满意,但由于我偶然发现这个页面并且没有看到它被提及,所以发布了。

    您可以添加引用丢失文件的自定义目标,

    例如:

    add_custom_target(
        my_custom_target_that_always_runs ALL
        DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/__header.h
    )
    
    add_custom_command(
        OUTPUT
            ${CMAKE_CURRENT_BINARY_DIR}/__header.h  # fake! ensure we run!
            ${CMAKE_CURRENT_BINARY_DIR}/header.h    # real header, we write.
        # this command must generate: ${CMAKE_CURRENT_BINARY_DIR}/header.h
        COMMAND some_command
    )
    

    这将继续运行自定义命令,因为找不到 __header.h

    查看使用此功能的working example

    【讨论】:

    • create_ad 指的是什么?互联网似乎不知道这一点
    • @sehe 名称并不重要,也可以链接到使用它的工作示例。
    • 酷。我只是感到困惑 :) 这个名字似乎很神奇,就像 CMake 语法中的很多东西一样。我必须承认我开始越来越喜欢 CMake,但是做一些 /just/ 与众不同的简单事情很难。
    • 我发现的一个问题是,出于某种上帝抛弃的原因,cmake 会更新生成文件上的 LM 时间戳(如果生成了一些文件)。如果您不想在某些情况下修改它,这会导致构建失败。
    • 具体取决于您在做什么 - 解决此问题的方法是在临时位置生成一个文件,并且仅在它们不同时将其复制。 (不好,但比缓慢的构建时间要好!)
    【解决方案2】:

    ideaman42 的答案的一个转折是使用空的 echo 语句创建一个虚拟输出。好处是你可以有几个自定义命令取决于这个虚拟输出。

    此外,cmake 构建系统将知道您的自定义命令的输出文件是什么,以便可以正确解决对该输出的任何依赖关系。

    # Custom target will always cause its dependencies to be evaluated and is
    # run by default
    add_custom_target(dummy_target ALL
        DEPENDS
            custom_output
        )
    
    # custom_output will always be rebuilt because it depends on always_rebuild
    add_custom_command(
        OUTPUT custom_output
        COMMAND command_that_produces_custom_output
        DEPENDS
            always_rebuild
        )
    
    # Dummy output which is never actually produced. Anything that depends on
    # this will always be rebuilt.
    add_custom_command(
        OUTPUT always_rebuild
        COMMAND cmake -E echo
        )
    

    cmake -E echo 与 cmake 一样接近无操作。

    【讨论】:

    • 如果我需要生成一个特定文件(自动生成),该解决方案将不起作用,该文件将在项目中使用。
    • @TarmoPikaro 为什么不呢?此解决方案的目的是允许生成项目的其他部分可以依赖的特定文件。我的解决方案中特定文件的名称是“custom_output”。我可能没有说清楚,还是您遇到了其他问题?
    【解决方案3】:

    我搜索了完全一样的,我终于找到了一个“notSoWorkaround”的解决方案。

    ADD_CUSTOM_TARGET(do_always ALL COMMAND yourCommandRegardlessOfAnyDependency)
    

    这将添加一个将在 ALL 之后运行的目标。由于自定义目标总是被认为是过时的,它会一直运行。

    您可能需要DEPENDS yourA.out 在构建后运行

    我的来源:

    【讨论】:

    • 不幸的是,这仅在您实际构建 ALL 目标时才有效(即您没有明确设置目标)。如果您执行make my_other_target 之类的操作,它将无法运行。虽然,公平地说,据我所知,所有其他答案都是如此,所以这绝对是最简单的。
    • 在 catkin build(它构建了 CMake ALL 目标)方面非常出色地帮助了我。其他一切都失败了。
    • 你也可以:"add_dependencies(mytarget do_always)" 到所有目标,以避免@Timmmm 这里提到的问题它仍然是所有答案中最干净的解决方案
    【解决方案4】:

    所以这是我的解决方案。我添加了一个假库:

    add_subdirectory(fake)
    add_dependencies(${PROJECT_NAME} fake)
    

    然后我就这样做了:

    cmake_minimum_required (VERSION 2.6)
    project(fake CXX)
    add_library(${PROJECT_NAME} SHARED fake.cpp)
    add_custom_command(TARGET fake
        POST_BUILD
        COMMAND ./mycommand.sh
        COMMAND rm ${ROOT_BIN_DIR}/libfake.so
        WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
    

    如您所见,我只是在构建后删除了 .so 文件,这会导致每次重建假库,执行 POST_BUILD,并且所有这些都在主 PROJECT_NAME 之前,因为它依赖于假。

    【讨论】:

    • 此解决方案仅适用于 unix 平台。您可以使用 cmake -E 使其与平台无关,但这涉及创建一个不必要的假库。有关不涉及创建任何文件的解决方案,请参阅 ideaman42 的答案。
    猜你喜欢
    • 2020-05-04
    • 1970-01-01
    • 2016-04-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-05-30
    • 2017-04-20
    相关资源
    最近更新 更多