【问题标题】:How to trigger a CMake reconfigure when the output of a command changes当命令的输出发生变化时如何触发 CMake 重新配置
【发布时间】:2016-07-06 09:14:15
【问题描述】:

我希望在命令输出更改时触发 CMake 配置;具体来说,我正在考虑在 git describe --always --dirty 的输出与上次配置 CMake 时发生变化时尝试配置 CMake。

大部分问题都可以通过查看HEAD 文件并将内部的symref 解析为refs/heads/[branch] 并将它们与configure_file(...) 链接来解决,但是当树处于脏状态时,这不会出现( IE 当有未提交的修改时)。在这种情况下,git describe --always --dirty 会将-dirty 后缀附加到输出。

发生这种情况时,git 文件没有任何更改,只有 git 注意到与存储状态的差异,因此我无法在此处的任何文件上 configure_file(...) 让 cmake 注意到更改并重新配置。

所以我正在寻找是否有办法让 cmake 运行 git 命令注意输出的差异并触发重新配置,几乎需要类似于预重新配置检查阶段的东西。

不确定这是否可能,是否有人知道如何实现这种行为?

【问题讨论】:

  • 不要在 CMake 本身中做这种事情,因为这会给你一种“鸡和蛋”的问题(当没有文件更改时检查更改的文件)。只需将其移动到调用您的 git、配置和构建步骤的一些 shell 脚本包装器中。
  • 所以我希望这样做的原因是我可以将git describe 字符串编译到版本信息中,以确保我确切知道它是从哪个 git commit 构建的,并且 critical,如果该提交有修改。如果我可以避免它并且我不明白为什么它应该以先有鸡还是先有蛋的情况结束,我不想在它之上建立一个元构建系统来获得一小部分功能?
  • 我不知道如何强制 CMake 在构建期间重新运行配置。但是,如果您只想更改 version.h 并重建依赖它的所有内容,则可以在 build 阶段使用 add_custom_target(BuildVersion COMMAND ${CMAKE_EXECUTABLE} -P <script_file>) 之类的内容生成该文件。这将在脚本模式下运行 CMake,您可以在其中使用通常的 configure_file 命令。进一步add_dependencies(<exec-target> BuildVersion) 命令将保证,如果脚本更改 version.h 文件,则该可执行文件将被重建。
  • This related question 可能会有所帮助(另请阅读该答案的 cmets)。
  • 有一些解决方案的相关讨论:stackoverflow.com/questions/1435953/…

标签: git cmake


【解决方案1】:

问题

这里的问题是“预重新配置检查阶段”由您的构建环境处理。 CMake 仅在其某些输入文件发生更改时调用(因为 CMake 已为您的构建环境生成规则以跟踪这些文件是否被更改)。

对于本次讨论,我们假设您有以下内容:

execute_process(
    COMMAND ${GIT_EXECUTABLE} describe --always --dirty
    OUTPUT_VARIABLE _git_file_list
    OUTPUT_STRIP_TRAILING_WHITESPACE
)

configure_file(version.h.in version.h)

外部命令输出更改时无需重新配置内建

如果没有您在构建过程中制作的附加脚本,我认为“检查外部命令的输出作为预重新配置步骤”之类的事情是不可能的。

您可以强制 CMake 每次都重新配置,例如通过在实际构建之前调用make rebuild_cache 或添加例如add_custom_command(TARGET MyExe POST_BUILD ${CMAKE_COMMAND} -E remove ${CMAKE_CURRENT_BINARY_DIR}/version.h),但是每次调用配置过程都是非常耗时的事情。

解决方案

在我的项目中,我将上面代码之类的内容移到了它自己的 WriteVersionInfo.cmake 脚本中:

set(_version_cpp_full_path "${CMAKE_CURRENT_BINARY_DIR}/version.cpp")
set(_version_obj_full_path "${_version_cpp_full_path}${CMAKE_CXX_OUTPUT_EXTENSION}")

string(REPLACE " " ";" _compiler_flags_list ${CMAKE_CXX_FLAGS})

# Create a dummy output to satisfy dependency check
if (NOT EXISTS ${_version_obj_full_path})
    file(WRITE ${_version_obj_full_path} "")
endif()

add_custom_command(
    TARGET MyExe
    PRE_LINK 
    COMMAND ${CMAKE_COMMAND} -D GIT_EXECUTABLE=${GIT_EXECUTABLE} 
                             -D _version_cpp_name=${_version_cpp_full_path} 
                             -P ${CMAKE_CURRENT_SOURCE_DIR}/WriteVersionInfo.cmake
    COMMAND ${CMAKE_CXX_COMPILER} ${_compiler_flags_list} 
                                  -o ${_version_obj_full_path} 
                                  -c ${_version_cpp_full_path}
    VERBATIM
)

target_link_libraries(
    MyExe
    ${_version_obj_full_path}
)

这里我直接写入.cpp 文件并直接将其作为PRE_LINK 步骤传递给编译器。请注意,上述方法不适用于库目标(因为没有预链接步骤)。

参考文献

【讨论】:

  • 据我所知the manualPRE_LINK 只有add_custom_target() 不存在;它适用于库和可执行文件。
猜你喜欢
  • 1970-01-01
  • 2017-07-24
  • 1970-01-01
  • 2015-09-24
  • 2017-02-03
  • 1970-01-01
  • 1970-01-01
  • 2017-06-18
  • 1970-01-01
相关资源
最近更新 更多