Various software development topics.

Sunday, January 20, 2008

Getting subversion revision numbers into your code

Note! I test all the things I post here using Linux and the tools mentioned. Hopefully there are no mistakes.

It is very important during testing, debugging, and even when given an image/program whose provenance you are unsure of, to be able to say what precise revision of the code you are dealing with.

One of the most effective ways of dealing with this is to ensure that your build system passes in the current revision of the code that your system or programs was built with. You can easily find out what revision your current workspace or sandbox contains using a command like svnversion at the top of your workspace:

cd /the/top/of/my/workspace
svnversion -n
1104:1108M
As you can see, svnversion is telling us a number of things about the code in our workspace, since it can print out a lot of information, as the help message for svnversion shows:

4123:4168 mixed revision working copy
4168M modified working copy
4123S switched working copy
4123:4168MS mixed revision, modified, switched working copy
Indeed, it will even print out exported if the current point in your source tree is not under SVN control. (You can obtain more information about Subversion at Version Control with Subversion.)

If you have this information available as a C/C++ preprocessor symbol in your source code, then you can ensure that your system/programs print out the version number it was build from when they start up. This will make your life much easier during testing and while debugging the inevitable problems thrown up by QA as well as, heaven forbid, when bugs are found in the field.

So how do we get this information into our builds? Make comes to our rescue here again. The following piece of make code obtains the current revision number if it is not already defined.

# Grab the current SVN revision number
ifeq ($(svnVersion),)
svnVersion := $(shell svnversion -n .)
export svnVersion
endif
ADDED_CFLAGS += -D_svn_revision=$(svnVersion)
ADDED_C++FLAGS += -D_svn_revision=$(svnVersion)
Now, you might use this in the following way in your include files:

#define STRINGIFY(_str_) #_str_

#define RVN_STRING(_str_) STRINGIFY(_str_)

#define VMJR "1"
#define VMNR "1"
#if _PRODUCT_BUILD
#define BLD_STR ""
#elif _DAILY_BUILD
#define BLD_STR " (Daily Build)"
#else
#define BLD_STR " (Developer Build)"
#endif

#define VREST VMNR BLD_STR" SVN#"RVN_STRING(_svn_revision)
#define VERSION "V"VMJR"."VREST

and then in your system or applications do something like:

printf("%s\n", "MyBigApp " VERSION);
and your application strings will look like:

MyBigApp V1.1 (Developer Build) SVN#218:221M
Clearly, you do not have to use the abbreviated symbols like BLD_STR and VMNR as I did above. Since there are space restrictions with the Blog template I am using I have shortened the symbol names in an effort to prevent example lines from wrapping.

The STRINGIFY trick above is documented in the GCC documentation on Stringification.

As you can see the system was build in a workspace that contained mixed revisions and modified (ie, uncommitted files). If QA or a customer shows you such output from a test you could clearly identify that they do not have an official build, or at least one hopes so.

No comments: