Search code examples
gitcompilationcmake

why does cmake compiles everything after git commit


Lets say I have a code compiling at some time with cmake 2.8 on linux.

I change a file "my_changed_file", run cmake, and only this one file is built. So far so good.

Now i want to commit this:

git add my_changed_file
git commit

If I run cmake again, i'd expect nothing happens. But all my files are recompiled, despite I didn't touched anything! The timestamp appears to be untouched when I do ls -l.

I do have these lines:

execute_process(
  COMMAND git describe --abbrev=8 --dirty --always --tags
  WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
  OUTPUT_VARIABLE GIT_CODE_VERSION
  OUTPUT_STRIP_TRAILING_WHITESPACE
)
add_definitions("-DCODE_VERSION=${GIT_CODE_VERSION}")

But it only affect the file main.cpp

What is happening ?

thanks


Solution

  • CMake doesn't track what source files will be affected by a particular compile definition. When compile definitions change, CMake assumes that all sources should be rebuilt.

    A better approach is to use a configured header file, so when the content of this file is changed, only those sources will be recompiled which includes this file (directly or indirectly):

    version.h.in:

    #define CODE_VERSION @GIT_CODE_VERSION@
    

    main.cpp:

    #include "version.h"
    ...
    

    CMakeLists.txt:

    # Calculate value of variable GIT_CODE_VERSION
    ...
    configure_file("version.h.in" "version.h")
    

    Nice thing with configure_file is that it doesn't update the resulted file's timestamp if its content wouldn't be changed. So, if you re-run cmake without git commit, nothing will be recompiled on the next build. Only re-running cmake after git commit will force the main.cpp file (and only it) to be recompiled on the next build.


    Another way is to use COMPILE_DEFINITIONS property on specific source files instead of a target-wide one (which is affected by the add_definition() call):

    set_property(SOURCE main.cpp APPEND
        PROPERTY COMPILE_DEFINITIONS "-DCODE_VERSION=${GIT_CODE_VERSION}")
    

    Changing this property via a cmake call will be detected by the build system, so the next build will recompile main.cpp and only it.

    Unfortunately, this approach doesn't work as expected for Makefile generators: even if compile definitions are changed for a specific source, all sources (for the same target) will be rebuilt. This is a known limitation.