Skip to content

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

License

Notifications You must be signed in to change notification settings

wolframroesler/version

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

12 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

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 identifier. 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.

Resources


Wolfram Rösler • [email protected]https://gitlab.com/wolframroeslerhttps://twitter.com/wolframroeslerhttps://www.linkedin.com/in/wolframroesler/

About

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

Topics

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Contributors 3

  •  
  •  
  •