简体   繁体   English

CMake:如果重建目标,则重新生成源文件

[英]CMake: Regenerate source file if target gets rebuilt

I am trying to embed the build date into a source file, so that every time a specific target gets built, the embedded date is refreshed, without regenerating every time the overall project built.我正在尝试将构建日期嵌入到源文件中,以便每次构建特定目标时都会刷新嵌入日期,而不会在每次构建整个项目时重新生成。

Ie I have a header file builddate.h that is generated by a command that has a set of #define s.即我有一个 header 文件builddate.h由具有一组#define的命令生成。 This header file is then included from other source files.然后从其他源文件中包含此 header 文件。

My first attempt was this:我的第一次尝试是这样的:

add_custom_target(builddate COMMAND <command that generates header file>)
add_library(mylibrary ...)
add_dependencies(mylibrary builddate)

This correctly generates the header file, however the header file is generated every time, regardless of whether the mylibrary target needs to be rebuilt.这会正确生成 header 文件,但是无论是否需要重建mylibrary目标,每次都会生成 header 文件。

Trying with a custom command instead, ie尝试使用自定义命令,即

add_custom_command(OUTPUT builddate.h COMMAND <command that generates header file>)
add_library(mylibrary ... builddate.h)

correctly generates the header once, but if the mylibrary target is rebuilt, the header is not regenerated as builddate.h is already up to date.正确生成一次 header,但如果重建mylibrary目标,则不会重新生成 header,因为builddate.h已经是最新的。

This feels like something that should be reasonably common, but I cannot figure out what incantation of custom commands and targets will give me the desired effect.这感觉应该是相当普遍的事情,但我无法弄清楚自定义命令和目标的什么咒语会给我想要的效果。 What I want is to call the command every time the mylibrary target is built, without spurious rebuilds if nothing has changed or if unrelated targets (such as executables using mylibrary ) are built.我想要的是每次构建mylibrary目标时调用该命令,如果没有任何更改或构建不相关的目标(例如使用mylibrary的可执行文件),则不会进行虚假重建。

Using a PRE_BUILD custom command would sound like a good idea, but the docs state that this gets invoked just prior to PRE_LINK commands for generators other than Visual Studio, ie after sources are compiled.使用PRE_BUILD自定义命令听起来是个好主意,但文档 state 会在 Visual Studio 以外的生成器的PRE_LINK命令之前调用它,即编译源代码之后。 This seems like it would make this unsuitable for this purpose, as the header is needed while compiling the sources.这似乎使它不适合此目的,因为在编译源代码时需要 header。

Found an old thread at https://cmake.org/pipermail/cmake/2010-October/040247.html suggesting to call CMake's --build for a target as a PRE_LINK command:https://cmake.org/pipermail/cmake/2010-October/040247.html找到一个旧线程,建议将 CMake 的--build作为PRE_LINK命令调用为目标:

# This is the library that I want to build
add_library(mylibrary ...)

# Set up a library that contains the code depending on the build date
# Use an OBJECT library because we don't need it to be a full static lib
# we just want to build some source that would "normally" have been part of mylibrary
add_library(builddate OBJECT EXCLUDE_FROM_ALL codethatusesbuilddate.cpp)

# Add a PRE_LINK command for mylibrary so that prior to linking we
# 1. Generate the builddate.h header
# 2. Call CMake to build the builddate library we just set up
add_custom_command(
    TARGET mylibrary PRE_LINK
    COMMAND <command that generates builddate.h>
    COMMAND ${CMAKE_COMMAND} --build ${CMAKE_BINARY_DIR} --target builddate
)

# We also need to link with the library
# NOTE: uses the generator expression to link with the output files rather than the target
# to avoid CMake setting up a dependency from builddate to mylibrary which I think
# would cause builddate to be built prior to building mylibrary, but at that point we
# haven't generated the header yet. Which we could fix, but then we'd just build it twice
target_link_libraries(mylibrary PRIVATE $<TARGET_OBJECTS:builddate>)


This feels a little awkward, but it seems to work.这感觉有点尴尬,但它似乎工作。

Footnote: Generating the header is easily done using CMake, ie first configure_file or similar to create a CMake script that does the generation, then invoke ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/generated_cmake_file.cmake as the command to generate the header. Footnote: Generating the header is easily done using CMake, ie first configure_file or similar to create a CMake script that does the generation, then invoke ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/generated_cmake_file.cmake as the command to generate the header.

Some time ago, I wrote a cmake makro.前段时间写了一个cmake makro。 It adds custom command to generate version.cpp in current build directory by executing Cversion.cmake.它添加了自定义命令,通过执行 Cversion.cmake 在当前构建目录中生成 version.cpp。 The generation of file is executed only when dependencies have changed.只有在依赖关系发生变化时才会执行文件的生成。 With cmake-generator-expressions dependencies are set to dependencies of target minus its own (files).使用 cmake-generator-expressions 依赖项设置为目标的依赖项减去它自己的(文件)。

It could be improved by adding libs dependencies to also generate anew version file.可以通过添加库依赖项来生成新的版本文件来改进它。

macro(add_versioning T)
add_custom_command(OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/version.cpp"
        COMMAND ${CMAKE_COMMAND} "-DCMAKE_CURRENT_BINARY_DIR=${CMAKE_CURRENT_BINARY_DIR}"
        -P "${PROJECT_SOURCE_DIR}/Version/CVersion.cmake"
        MAIN_DEPENDENCY "${PROJECT_SOURCE_DIR}/Version/version.cpp.in"
        DEPENDS "$<FILTER:$<TARGET_OBJECTS:${T}>,EXCLUDE,version.cpp.+$>")

target_include_directories(${T} PUBLIC "${PROJECT_SOURCE_DIR}/Version")
target_sources(${T} PUBLIC "${PROJECT_SOURCE_DIR}/Version/version.h" PRIVATE "${CMAKE_CURRENT_BINARY_DIR}/version.cpp")

endmacro()

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM