Include Git commit hash and/or branch name in C/C++ source

Viewed 11106

I would like to know how you can get a Git commit hash and/or other information into the contents of a C++ variable in the compiled binary without having it be part of the source that's tracked by Git.

I need to keep track of firmware release information in a compiled executable running on an embedded processor. Means to identify the particular release of the firmware binary such as meaningful filenames, MD5 checksums or even date/time stamps are not available in this closed environment (i.e., there is no filesystem).

One approach is to have the device's console output produce identifying text, such as 'Release 1.2.3', 'commit hash 1bc123...', or similar. The firmware release information is only of interest to maintenance personnel, so a trained operator could examine the console output. To implement this it could potentially involve manual editing of a version string, which is then compiled into the code and output to the console at program startup.

This is acceptable for major releases where a signoff workflow is used to double-check that the version information is correct. However, this being a manual process it is inherently unreliable. For example, what if the developer forgets to update the version information? - There is now a disconnect between the compiled code and its reported version string.

A workflow where the code is freshly compiled and downloaded each time the user wants to test the hardware is not practical in the situation in question, ie., it is quite onerous to update the firmware.

An automatic way of identifying the version of the code is thus required. In the situation in question, Git is used, and the developers regularly commit their work to feature branches. Displaying the Git commit hash, and perhaps also whether or not there are unstaged changes, would be a way of identifying the status of the source code used to compile the firmware.

The requirement is that I would like my application to have information available to it so that it is able to display: "Git commit:[01abcdef...etc], branch: experimentalStuffDoNotRelease"

Thus, I would like to automatically include Git information, such as commit hash and branch, in the compiled C and/or C++ code.

The development environment has developers using both Windows and Linux, and uses Eclipse CDT with a relatively unsophisticated workflow of: check out; compile; download to the hardware.

6 Answers

Here's simple solution if you need git hash and local modifications flag only:

$ cat update-version-info.sh

#!/bin/sh
version=$(git describe --always --dirty --tags)
echo "#define GIT_VERSION \"$version\"" > git-version.h

$ cat 1.c

#include <stdlib.h>
#include <stdio.h>

#include "git-version.h"

int main() {
#ifdef GIT_VERSION
    printf("%s\n", GIT_VERSION);
#endif
    return 0;
}

$ ./1

ee4f307-dirty

Based on @Richard's answer and my fixes for qmake/Qt, here is the solution I use: With Qt 5.14 the following lines in .pro file work for me:

GIT_HASH="\\\"$$system(git -C \""$$_PRO_FILE_PWD_"\" rev-parse --short HEAD)\\\""
GIT_BRANCH="\\\"$$system(git -C \""$$_PRO_FILE_PWD_"\" rev-parse --abbrev-ref HEAD)\\\""
BUILD_TIMESTAMP="\\\"$$system(date -u +\""%Y-%m-%dT%H:%M:%SUTC\"")\\\""
DEFINES += GIT_HASH=$$GIT_HASH GIT_BRANCH=$$GIT_BRANCH BUILD_TIMESTAMP=$$BUILD_TIMESTAMP

In your code you can check the revision like this:

int main(int argc, char *argv[])
{
    QStringList args;
    for (int i = 0; i < argc; i++)
        args << QString(argv[i]);

    if (args.contains("-v") || args.contains("--version")) {
        std::cout << QString("branch: %1, version: %2, built_at: %3").arg(GIT_BRANCH).arg(GIT_HASH).arg(BUILD_TIMESTAMP).toUtf8().constData() << std::endl;
        return 0;
    }
    // ...
}

A C file or a C++ file can be generated by some program (for example, some shell script on Linux, or some GNU awk script, or your C program running system or popen(3) running some git command).

You just configure your build automation tool (e.g. your Makefile if you use GNU make, or your build.ninja file if you use ninja) appropriately.

Both Bismon and RefPerSys are doing so and keep their git id inside the obtained executable (displaying it when invoked with --version). Note: both are projects I created.

PS a different question is how to configure your IDE to run a particular build automation tool. This is specific to your IDE. But Eclipse CDT FAQ offers an insight.

Related