12

I have following command in my CMakeLists.txt file

configure_file([...]/Version.h.in [...]/Version.h @ONLY)

How do I make it run on every build, but not only when Version.h.in changes? I need that because Version.h has __DATE__ macro in it and actually should be treated as new for every build, even while it remains the same.

The Version.h.in looks like

static const char VERSION[] = "Bla-bla-bla " @FOOBAR@ " built on " __DATE__;
uranix
  • 657
  • 1
  • 5
  • 23
  • Hello @uranix !!! Could I ask you something about the calculation of the error of the method we used? http://chat.stackexchange.com/rooms/31813/calculation-of-error – Mary Star Nov 19 '15 at 16:18
  • I guess, the issue ticket that could be created for CMake team is about comparing not only the .in-file content but macroses that it uses too. – Sergei Krivonos Mar 29 '22 at 13:30

2 Answers2

10

I transfered my version string generation into its own CMake script that I call with ${CMAKE_COMMAND} -P ... in a add_custom_command()/add_custom_target() and make my target using it depend on it.

In your case let's say you have a DateToVersionH.cmake script like this:

string(TIMESTAMP _date "%d %m %Y %H:%M")
file(WRITE ${VERSION_FILE_NAME} "#define MY_VERSION \"Bla-bla-bla ${FOOBAR} built on ${_date}\"\n")

you can do something like:

add_custom_command(
    TARGET MyExe
    PRE_BUILD
    COMMAND ${CMAKE_COMMAND} -DVERSION_FILE_NAME=Version.h -DFOOBAR="${FOOBAR}" -P "${CMAKE_CURRENT_LIST_DIR}/DateToVersionH.cmake"
)

See also use CMake to get build-time svn revision

That may not be enough if your make environment checks all the "needs to be rebuild" prior of calling the necessary steps (e.g. in Ninja only the outputs of custom commands are re-scanned; for more details see the Ninja documentation for the restat rule variable and this discussion which led to the introduction of the BYPRODUCTS option in add_custom_command()).

So you could simply add to your build shell script - prior to calling the actual make - removing the object file containing the version information.

Or you are forcing the re-compilation of the object before linking. This would - assuming you have a Version.c which includes Version.h - look like this:

include_directories(${CMAKE_CURRENT_BINARY_DIR})
execute_process(COMMAND "${CMAKE_COMMAND}" -DVERSION_FILE_NAME=Version.h -DFOOBAR="${FOOBAR}" -P "${CMAKE_CURRENT_LIST_DIR}/DateToVersionH.cmake")
add_library(MyVersionObj OBJECT Version.c)

add_executable(MyExe ... $<TARGET_OBJECTS:MyVersionObj>)

add_custom_command(
    TARGET MyExe
    PRE_LINK 
    COMMAND "${CMAKE_COMMAND}" -DVERSION_FILE_NAME=Version.h -DFOOBAR="${FOOBAR}" -P "${CMAKE_CURRENT_LIST_DIR}/DateToVersionH.cmake"
    COMMAND "${CMAKE_COMMAND}" --build "${CMAKE_BINARY_DIR}" --config $<CONFIG> --target "MyVersionObj"
)

Thinking about it, just deleting the object file and utilizing your current __DATE__ solution is the simplest solution.

For another "git version solution" see CMake: Automatically use git tags as version strings and How can I pass git SHA1 to compiler as definition using cmake?

the_storyteller
  • 2,335
  • 1
  • 26
  • 37
Florian
  • 39,996
  • 9
  • 133
  • 149
  • 1
    Thank you for the updated answer, solves my problem completely! I've just replaced `__DATE__` macro with `@_date@` in my `Version.h.in` – uranix Jun 25 '15 at 21:17
  • @uranix Glad to hear it helped. Just for completeness I added some comments about Ninja and how to force the compilation of something as a pre-linker step. – Florian Jun 26 '15 at 08:16
1

Just to submit an alternative answer that seems simpler to me and does the trick if you are under any *nix OS :

Running touch Version.h.in as a pre-build command, either implemented in your IDE, manually executed before running your cmake commands in your shell, or in your CI (where it might be useless), allows to systematically generate the Version.h file, even if it has not been modified.

aTom
  • 406
  • 6
  • 17