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.

  • How to handle dependencies in cross platform C++ projects?
  • CMake External Project for Git Project
  • How to get git branch/tag names in CMake, from external project?
  • What is the Difference between Installation OpenCV by Using the Pre-built Libraries & by Making Own Libraries from the Source Files?
  • Jenkins + Cmake + JIRA = CI of multiple interdependent projects?
  • CMake error: The source directory does not exist
  • 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

  • Changing branches in git mistakenly results in modified files
  • Changing remote tracking branches in git(-svn) after clone with restricted branches
  • Git: The Curious Case of the Missing Commits
  • How to load separately submodules included in a project?
  • Git, SVN & Mercurial Whats is Ideally the best SCM?
  • Clone a private repo of github with username and password
  • One Solution collect form web for “why does cmake compiles everything after git commit”

    CMake doesn’t track, which source file can be affected by particular compile definition. When compile definitions changes, CMake assumes that all sources should be rebuilt.

    Better approach is to use configured header file. So, when 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 resulted file’s timestamp if its content wouldn’t be changed. So, if you rerun cmake without git commit, nothing will be recompiled on next build. Only rerunning cmake after git commit will force main.cpp file(and only it) to be recompiled on next build.


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

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

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

    Unfortunately, this approach doesn’t work as expected in case of makefile generators: even if compile definitions are changed for specific source, all sources (for same target) will be rebuilt. This is known limitation.

    Git Baby is a git and github fan, let's start git clone.