Archive for February, 2009

Automagically add version numbers in your builds

Sunday, February 1st, 2009

It is often very useful to be able to identify builds with version numbers automatically – for example, when diagnosing bugs reported by users. For a while I struggled with this, but I think I have a robust solution now.

I use subversion for source control, so it seems natural to use subversion version numbers to automatically add a version string. This turns out to have a couple of subtle issues:

  • I need one version number for the whole program, not individual version numbers for each file
  • I want to see if the code built has been modified since the last commit

Now I did a bit of internet searching, and came across svnversion! This seems to solve both of my problems quite nicely – it will output a version number for a directory, and it can append ‘M’ to the end of the version string if the working copy was modified. This even seems to be cross platform! The only thing left to do is to make a script to embed this information into a source file, and then add this script to out build system.

However, I’ve neglected a couple of missing things that could be useful:

  • what if I want the revision number as an integer?
  • what if I want the modified flag as a boolean?
  • what if I want the date the application was built?

These are all minor issues – nothing some perl-fu can’t solve. It would still be nice if I didn’t have to write all of this myself (as laziness is the foundation of efficiency).

Lucky for me, I don’t. There is a nice program called svnrev that will embed all of this information into a C++ or Java source file. It’s cross-platform and even comes with a Linux and Windows binary. Now I just needed to embed all of this into my build scripts.

I was only able to solve this problem satisfactorally when I started using CMake for builds. Before, I had been building on Linux and Windows, and had to maintain both an autotools configuration and Visual Studio solution. Switching to CMake gave me an easy way to generate native builds for each platform (as well as solve my versioning problems!) I now have a custom target in my CMakeLists.txt that my main target depends on. This looks something like this:

IF(UNIX)
  ADD_CUSTOM_TARGET(svnversion ALL ./svn_update.sh WORKING_DIRECTORY ${SOURCE_DIR}/tools/)
ENDIF(UNIX)
IF(WIN32)
  ADD_CUSTOM_TARGET(svnversion ALL ./svn_update.bat WORKING_DIRECTORY ${SOURCE_DIR}/tools/)
ENDIF(WIN32)

svn_update.{bat,sh} is a simple shell script that calls svnrev on all of my source files. I then add the svn_update script and svnrev to a tools/ directory in subversion, as well as a CMakeLists.txt like the one above. In my main CMake target, I just call

ADD_DEPENDENCIES(target svnversion)