alexbevi / version

How to automatically get version and build number into a C++ executable

Home Page:https://gitlab.com/wolframroesler/version

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Build Number Generation With git And cmake

This example program shows how to achieve the following:

  • Manage a project's version number in annotated git tags only (no manual editing in header files when bumping the version number, just create the tag)
  • Automatically generate a unique build number with every git commit, which can be used to retrieve the exact source code used in that build
  • Automatically create a "version identifier" that contains the version number, the build number, the build date and time, and platform details (host name, user name, OS version number, etc.)
  • Make this version identifier available to the program (e. g. print it when invoked with --version)
  • Make it possible to extract the version identifier from an executable without having to execute it

Running The Example Program

$ mkdir build
$ cd build
$ cmake ..
$ make

This creates the example program which, when invoked, simply displays the version identifer. For example:

$ ./version
Version 1.0-3-g5c4af1f (built 2018-01-08 19:32:17 by wolfram on MacBook-Air with Darwin 16.7.0)

Use strings and grep to extract the version number from the executable, in which it is marked with the magic string @(#). (Or use the ancient what program if your system is old enough to have it.)

$ strings version | grep '@(#)'
@(#)1.0-3-g5c4af1f (built 2018-01-08 19:32:17 by wolfram on MacBook-Air with Darwin 16.7.0)

How To Make The Build Number

For release versions (that have a git tag with the version number on them), there is no build number beside the version number. For example:

$ git tag
0.0
1.0
$ git checkout 1.0
$ make
$ ./version
Version 1.0 (built 2018-01-08 19:50:23 by wolfram on MacBook-Air with Darwin 16.7.0)

When new commits are added, the build number indicates the number of commits since the version tag, plus -g followed by the commit ID.

$ git checkout develop
$ make
$ ./version
Version 1.0-3-g5c4af1f (built 2018-01-08 19:57:34 by wolfram on MacBook-Air with Darwin 16.7.0)

You can later return to the source code this version was created from with git checkout 5c4af1f.

If there are uncommitted changes, the build number contains the string -dirty. This indicates that it may not be possible to retrieve this version's source code from the repository.

$ vi main.cpp
$ make
$ ./version
Version 1.0-3-g5c4af1f-dirty (built 2018-01-08 20:03:06 by wolfram on MacBook-Air with Darwin 16.7.0)

All this is accomplished with the git describe command, which is what we use to construct the version number and build number. That means we don't have to keep the version number anywhere in the source code, it's enough to have it in the git tags.

$ git describe --dirty
1.0-3-g5c4af1f-dirty

$ ./version
Version 1.0-3-g5c4af1f-dirty (built 2018-01-08 19:32:17 by wolfram on MacBook-Air with Darwin 16.7.0)

How To Add The Build Details

... like time stamp, machine/computer name, etc.

This is accomplished by a shell script, makeversion.sh, which uses simple shell tools like date, uname, etc. (and, of course, git describe) to construct the version identifier. The script outputs its result as a C function that returns the version string.

$ bash makeversion.sh
char const *Version() {
    return "@(#)1.0-3-g5c4af1f (built 2018-01-08 20:23:33 by wolfram on MacBook-Air with Darwin 16.7.0)" + 4;
}

To access the version identifier in the program, simply invoke this function.

std::cout << "Version " << Version() << std::endl;

The C string that contains the version identifier begins with the "magic string" @(#) which we can use to retrieve the version number from the executable as described above. The Version() function, however, skips the magic string and returns only what comes after it.

How To Put It All Together

This is where the actual magic happens.

When invoked with the -o parameter, makeversion.sh compiles its C output into an object file. The cmake file uses add_custom_command to invoke makeversion.sh -o during each build, and contains the resulting object file in its target_link_libraries.

This is done as a "pre link" step, i. e. only when there's actual work to do. Simply typing make again (without any source change, make clean, etc.) won't trigger a new link and thus won't create a new version number.

Ressources


Wolfram Rösler • wolfram@roesler-ac.dehttps://gitlab.com/wolframroeslerhttps://twitter.com/wolframroeslerhttps://www.linkedin.com/in/wolframroesler/

About

How to automatically get version and build number into a C++ executable

https://gitlab.com/wolframroesler/version

License:MIT License


Languages

Language:Shell 54.9%Language:CMake 27.5%Language:C++ 10.5%Language:C 7.2%