How can I get my C code to automatically print out its Git version hash?

Viewed 57066

Is there an easy way to write C code that can access its Git version hash?

I wrote software in C to collect scientific data in a laboratory setting. My code records the data it collects in a .yaml file for later analysis. My experiments change from day-to-day and I often have to modify the code. To keep track of revisions, I use a git repository.

I would like to be able to include the Git revision hash as a comment in my .yaml data files. That way, I could look at the .yaml file and know exactly what code was used to generate the data shown in that file. Is there an easy way to do this automatically?

12 Answers

I also use git to track changes in my scientific code. i didn't want to use an external program because it limits portability of the code (if someone would want to make changes on MSVS for example).

my solution was to use only the main branch for the calculations and make it output the build time using preprocessor macros __DATE__ and __TIME__. that way i can check it with git log and see which version i'm using. ref: http://gcc.gnu.org/onlinedocs/cpp/Standard-Predefined-Macros.html

another elegant way to solve the problem is to include git log into the executable. make an object file out of git log and include it into the code. this time the only external program you use is objcopy but there is less coding. ref: http://www.linuxjournal.com/content/embedding-file-executable-aka-hello-world-version-5967 and Embed data in a C++ program

This is a solution for CMake projects that works for Windows and Linux, without the need for any other programs (e.g. script languages) to be installed.

The git hash is written to a .h file by a script, which is a bash script when compiling on Linux or a Windows batch script when compiling on Windows. An if-clause in CMakeLists.txt is used to execute the script corresponding to the platform the code is compiled on.

Save the following 2 scripts in the same directory as CMakeLists.txt:

get_git_hash.sh:

#!/bin/bash
hash=$(git describe --dirty --always --tags)
echo "#ifndef GITHASH_H" > include/my_project/githash.h
echo "#define GITHASH_H" >> include/my_project/githash.h
echo "const std::string kGitHash = \"$hash\";" >> include/my_project/githash.h
echo "#endif // GITHASH_H" >> include/my_project/githash.h

get_git_hash.cmd:

@echo off
FOR /F "tokens=* USEBACKQ" %%F IN (`git describe --dirty --always --tags`) DO (
SET var=%%F
)
ECHO #ifndef GITHASH_H > include/my_project/githash.h
ECHO #define GITHASH_H >> include/my_project/githash.h
ECHO const std::string kGitHash = "%var%"; >> include/my_project/githash.h
ECHO #endif // GITHASH_H >> include/my_project/githash.h

In CMakeLists.txt add the following lines at the beginning to define the custom target "write_git_hash"

if(WIN32)
  add_custom_target( write_git_hash
    get_git_hash.cmd
    COMMENT "Call batch script for writing git hash"
    WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
  )
else()
  add_custom_target( write_git_hash
    ./get_git_hash.sh
    COMMENT "Call shell script for writing git hash"
    WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
  )
endif()

Make sure to add the "include" folder to your project

project(my_project)
include_directories(include)

After you define the executable, add "write_git_hash" as a dependency

add_executable(my_project src/my_cpp_file.cpp)
add_dependencies(my_project write_git_hash)

This will trigger the generation of the githash.h when building the project.

Include the githash.h file in your C++ file with #include <my_project/githash.h>. You should now be able to print the git hash to the terminal with

std::cout << "Software version: " << kGitHash << std::endl;

or do with it whatever you like.

Related