I have a header file version.h
containing version information. Before every build, I want CMake to ensure that the version information is up to date. As a test, I've set up CMake to touch the file before every build. That should cause all source files that include the file to be recompiled on every build. Here is how it works:
# CMakeLists.txt
add_library(MY_APP STATIC main.cpp version.h)
add_custom_target(UPDATE_VERSION
COMMAND ${CMAKE_COMMAND} -E touch ${CMAKE_CURRENT_SOURCE_DIR}/version.h
)
add_dependencies(MY_APP UPDATE_VERSION)
// main.cpp
#include "version.h"
On every build, the first output I get is /usr/local/bin/cmake -E touch version.h
, and the timestamp of the file is changed. Great! However, main.cpp
is only compiled on every other build! It seems that whether main.cpp
should be compiled is determined before version.h
is updated. Probably something like this happens:
main.cpp
for compilation if version.h
is newer than main.obj
touch version.h
main.cpp
if it was listed for compilationWhenever main.cpp
is compiled, main.obj
will be newer than version.h
in step 1 during the next build, so then main.cpp
will not be compiled. In the next run again, version.h
will be newer than main.obj
in step 1, and main.cpp
is compiled again.
At least this is my assumption to why it does not work. How can I update build version.h
so that main.cpp
is compiled every time?
I'm using Visual Studio 2022 and Ninja.
If you want to keep using your current modification timestamp approach, you might want to mark the generated file as a byproduct of the custom target using the BYPRODUCTS
argument of add_custom_target
, which will give the source file the GENERATED
property. And/or add the ALL
argument.
Using file timestamps is depending on whether the generated buildsystem lacks the sophistication to look at whether the content of a file has changed. I think you'd do better to actually change the content of the file. Ex. putting ${CMAKE_COMMAND} -P /absolute/path/to/write_stamp_file.cmake
, where write_stamp_file.cmake
contains something like this:
string(TIMESTAMP timestamp "%s" UTC)
file(WRITE "${training_stamp_file}" "// UTC: ${timestamp}")
Of course, that's assuming a buildsystem that lacks the sophistication to detect whether the changes made in a dirty header actually necessitate re-compilation of a source file that #include
s it, but... that's another problem. There is the OBJECT_DEPENDS
source file property, but at the time of this writing, only the Makefile and Ninja generators support it.