【问题标题】:How to make CMake target executed whether specified file was changed?无论指定的文件是否已更改,如何使 CMake 目标执行?
【发布时间】:2011-12-13 07:42:18
【问题描述】:

我正在尝试在我的 C++ 项目中使用 ANTLR。我为指定语法创建了一个运行 ANTLR 生成器的目标,并使 main prjct 依赖于它。

ADD_CUSTOM_TARGET(GenerateParser
    COMMAND ${ANTLR_COMMAND} ${PROJECT_SOURCE_DIR}/src/MyGrammar.g 
                             -o ${PROJECT_SOURCE_DIR}/src/MyGrammar
)

ADD_LIBRARY(MainProject ${LIBRARY_TYPE} ${TARGET_SOURCES} ${TARGET_OPTIONS})
ADD_DEPENDENCIES(MainProject GenerateParser)

问题是每次我构建项目时都会运行 ANTLR 生成器并消耗足够的时间。仅在我的语法已更改的情况下,如何才能使其运行?或者有可能让 ANTLR 以某种方式只为过时的语法生成解析器。

【问题讨论】:

  • 我们遇到了这个问题——add_custom_target 总是在重建。不幸的是,目标是在我们无法控制的外部模块中定义的。因此,在这种情况下,使用 add_custom_command 的解决方案不适用。我正在寻找一种解决方案来控制何时调用目标。

标签: cmake antlr


【解决方案1】:

add_custom_command 做到这一点,如果你正确地构造了对它的调用。

这样的事情应该可以工作:

ADD_CUSTOM_COMMAND(OUTPUT ${PROJECT_SOURCE_DIR}/src/MyGrammar
  COMMAND ${ANTLR_COMMAND} ${PROJECT_SOURCE_DIR}/src/MyGrammar.g
    -o ${PROJECT_SOURCE_DIR}/src/MyGrammar
  DEPENDS ${PROJECT_SOURCE_DIR}/src/MyGrammar.g
)

ADD_CUSTOM_TARGET(GenerateParser ALL
   DEPENDS ${PROJECT_SOURCE_DIR}/src/MyGrammar
)

ADD_LIBRARY(MainProject ${LIBRARY_TYPE} ${TARGET_SOURCES} ${TARGET_OPTIONS})
ADD_DEPENDENCIES(MainProject GenerateParser)

在这里,自定义目标每次都会“构建”,但它唯一会做的就是构建它依赖于其输出的自定义命令,但当且仅当自定义命令的输出相对于其而言已过时到其 DEPENDS 文件。

【讨论】:

  • 我发现这对我不起作用。构建一个依赖于自定义命令输出的自定义目标的目标每次都会调用自定义命令,在我的情况下,这每次都会导致下游重建。节省运行命令的时间并不是什么大问题,但是过时输出的连锁反应是相当乏味的。我的解决方案是否遗漏了什么?
  • 它应该只在其输入(add_custom_command 的 DEPENDS)比其输出更新时调用自定义命令。你确定你传递给 OUTPUT 和 DEPENDS 子句的值是正确的吗?在您的 CMake 文件中使用“消息”仔细检查这些元素的值。
【解决方案2】:

除了带有自定义目标的建议解决方案外,如果您的目标依赖于某些生成的源,则常见的工作流程如下:

添加生成源文件的目标。我建议使用完整路径以避免错误。

add_custom_command(OUTPUT ${GENERATED_SOURCE_FILE}
    COMMAND ${GENERATION COMMAND}
    DEPENDS ${DEPENDENCIES}
)

设置生成的源文件的 GENERATED 属性。所以 cmake 不会抱怨缺少源文件。

set_source_files_properties(${GENERATED_SOURCE_FILE} PROPERTIES
    GENERATED TRUE
)

像往常一样将生成的源添加到您的目标。

add_executable(${YOUR_TARGET} SOURCES ${GENERATED_SOURCE_FILE})

因此,在建议的示例中,${GENERATION COMMAND} 只有在某些 ${DEPENDENCIES} 文件发生更改时才会启动。

【讨论】:

  • 根据docs,无需手动将文件标记为GENERATED,默认标记为GENERATED
【解决方案3】:

add_custom_command 能解决问题吗?在这里您可以指定 DEPENDS [depends...],这将使命令仅在依赖文件更改时执行。

http://www.cmake.org/cmake/help/cmake2.6docs.html#command:add_custom_command

add_custom_command(OUTPUT output1 [output2 ...]
                 COMMAND command1 [ARGS] [args1...]
                 [COMMAND command2 [ARGS] [args2...] ...]
                 [MAIN_DEPENDENCY depend]
                 [DEPENDS [depends...]]
                 [IMPLICIT_DEPENDS <lang1> depend1 ...]
                 [WORKING_DIRECTORY dir]
                 [COMMENT comment] [VERBATIM] [APPEND])

【讨论】:

  • 似乎不起作用。据我了解,DEPENDS 仅适用于目标,例如每当更改依赖目标(重建库等)时,都会执行命令。
【解决方案4】:

我也有同样的问题。在阅读了如何生成 makefile 之后(因为 cmake 文档还有很多不足之处),看起来最好的解决方案是使用 OUTPUT 表单的 add_custom_command 。这是我的例子

add_custom_command(OUTPUT
                   # In my cmake file I list every file generated
                   ${PROJECT_SOURCE_DIR}/src/MyGrammar/file1
                   ${PROJECT_SOURCE_DIR}/src/MyGrammar/file2
                   COMMAND ${ANTLR_COMMAND} ${PROJECT_SOURCE_DIR}/src/MyGrammar.g
                   -o {PROJECT_SOURCE_DIR}/src/MyGrammar

                   # In my case I used a script checked into source control, 
                   # so I want to know when it changes too
                   DEPENDS ${ANTLR_COMMAND} ${PROJECT_SOURCE_DIR}/src/MyGrammar.g)

# cmake caches are problematic, so list the files in a variable
set(generated_sources src/MyGrammar/file1 src/MyGrammar/file2)
add_library(yourlib ${list_of_source_files} ${generated_sources})

然后当你构建时,cmake 会在决定重新生成源之前检查命令和语法文件是否有变化。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-06-07
    • 2016-12-19
    • 1970-01-01
    • 2010-09-08
    • 2015-01-08
    相关资源
    最近更新 更多