How can the status of a git repository be determined at compile time?

I’m working on a simulation system written in C++ that is managed by git. I use GNU make as build tool. To make simulation results reproducible git is very useful as you can go back to the exact version of the simulation program the results have been created with.

Currently the status and SHA1 of the git repository are determined programmaticaly at run time and written to a file together with the results. However, if the sources have been changed since compilation of the program, the status in my log file will not reflect the actual version of the program. Thus I’m looking for a way to determine the git status at compile time. Is there any chance to accomplish this?

  • Generic method for reading config sections
  • How should I collaborate with developers who use Xcode?
  • Add github library(BamTools) to c++ using cmake ExternalProject_Add
  • Apparently nondeterministic behavior in this code calling out to an external process
  • One source needs to compile differently on multiple machines
  • AssemblyInfo.cs subversion and TortoiseSVN
  • How to create a commit from a diff or patch using GitHub's API?
  • Git squash commits in the middle of a branch
  • Keep settings in branch
  • How can I tell Emacs my git branch has changed?
  • What is the difference between git push.default=current and push.default=upstream?
  • How to add a file to the index in a git pre-commit hook
  • 2 Solutions collect form web for “How can the status of a git repository be determined at compile time?”

    One solution is to have your build system extract the value and have it generate some C++ header (or source file) with this value inside it.

    For example, if using CMake, you can use the FindGit module to do something like:

    project(...)
    
    # load module.
    find_package(Git)
    
    # create "${GIT_HEAD_HASH}" variable that contains
    # the SHA-1 of the current tree.  This assumes that the
    # root CMakeLists is in the root of the Git repository.
    git_tree_info(${CMAKE_SOURCE_DIR} GIT_HEAD)
    
    # generate a 'version.h' file based on the 'version.h.in'
    # file.  replace all @...@ strings with variables in the
    # current scope.
    configure_file(
        ${CMAKE_CURRENT_SOURCE_DIR}/version.h.in
        ${CMAKE_CURRENT_SOURCE_DIR}/version.h
        @ONLY
    )
    

    Then, add the following version.h.in file:

    #ifndef _version_h__
    #define _version_h__
    
    static const char VERSION[] = "@GIT_HEAD_HASH@";
    
    #endif
    

    CMake will replace the @GIT_HEAD_HASH@ string with the value it extracted using get_tree_info().

    Then, from your regular code:

    #include "version.h"
    #include <cstdlib>
    #include <cstring>
    #include <iostream>
    
    int main(int argc, char ** argv)
    {
        if ((argc == 2) && (std::strcmp(argv[1],"--version") == 0))
        {
            std::cerr
                << VERSION
                << std::endl;
            return (EXIT_FAILURE);
        }
    
        // ...
    }
    

    This is a simplified and absolutely untested example. If you take a look at the sources of the FindGit CMake module, you’ll see that it just runs an execute_process() command at build time to extract the information. You can modify it to extract anything based on invocation of the Git command-line interface.

    Since you are already using Makefile, you can check the status there.

    If you want to keep track of what commit was the HEAD at that time, you can use git rev-parse HEAD to get the sha1 of the commit. You may store it in a file if you need it at runtime.

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