Blog‎ > ‎Good Samaritan‎ > ‎

The easy way to get subversion revision information into your autotools project

posted Sep 14, 2008, 2:04 PM by Brian Tanner   [ updated Jun 3, 2009, 7:25 AM ]

Introduction

I have been trying to figure how to get the build number automatically included into my autotools project so that when I do ./myprogram --version it will print out the build number. This is very handy because then if there is a problem with code someone is using, you can figure the EXACT version immediately.

I quickly came across this page:
http://www.mhoenicka.de/system-cgi/blog/index.php?itemid=999

This looks interesting, but I couldn't make it work right.  My makefile was giving me errors, and after hours of trying various ways to fix it, I gave up.

Then I thought of a much simpler (IMHO) way that used the same basic idea.   That is listed last on this page (the old/bad way), because since then I've thought of and been told about some even better ideas.

Cross-Platform Easy Way : Using Keywords

There is a much easier way than what I describe below, and I find it more robust.

You need to use svn keywords.  Look them up. They are cool.  Basically, you have a file called: myfile.c, and you do:
svn propedit svn:keywords

Then when you favorite editor comes up you can set some keywords that you want to be replaced.  For example, if you use Revision, then anywhere in myfile.c that you put:
$Revision$, subversion will replace it with something like $Revision: 882 $ AUTOMATICALLY, every time you commit.  Score.  

You can also edit your subversion config file (on *nix/Mac it's in ~.subversion/config) so that it always replaces keywords.  Then you can put them in your comments section of each source file.

So now, just put this function in myfile.c and make sure its prototype is known to the code you want to call it from:
char svnVersionString[1024];
char* __get_svn_version(){
int howMuchToCopy=0;
char *theVersion="$Revision: 882 $";
howMuchToCopy=strlen(theVersion+11) - 2;
assert(howMuchToCopy>0);
memcpy(svnVersionString, theVersion+11, howMuchToCopy);
    svnVersionString[howMuchToCopy] = '\0';
return svnVersionString;
}
Now, if you write code like:
printf("The svn revision number is r%s\n",__get_svn_version() );

You will get code that automatically outputs the current global version of the project, without any mess with autotools, local copies of version numbes, etc, etc.

Cross Platform Windows Way -  Use SubWCRev

John Muczynski recently contacted me and suggested I look into SubWCRev.  If you're on Windows, this program comes with Tortoise SVN, and seems to make it even easier to get version information into your program:
http://tortoisesvn.net/docs/release/TortoiseSVN_en/tsvn-subwcrev.html

The First Cross Platform Attempt (the old/bad way)

The basic idea is to either use svnversion to get the current build number if possible, and if not, fall back to  a file that has been saved.  This way, if you build from code checked out of subversion, you have the info, and if you build from a download, you still have it.

The approach used in the link above comes from the subversion people originally, and they want you to use your Makefile to actually create a C source file with a function that gives you the build number.

Instead, you could just define a symbol, say called SVN_VERSION, and then do whatever you want with it in your code.

There just a few steps.

Update configure.ac

This is taken almost directly from the link above.  Basically, we're going to check if svnversion is installed and working, and if so get the build number from it.  IF not, we're going to get the build number from a file we stored one of the other times that we built.  We're then going to define a symbol called SVN_VERSION that has the string as its value.  This is like doing #define SVN_VERSION "383" or similar.

AC_PATH_PROG(svnversioncommand, svnversion)
if test "X$svnversioncommand" = "X" || test `$svnversioncommand -n '.'` = "exported"; then
AC_DEFINE_UNQUOTED(SVN_VERSION, ["`cat saved_svn_version.txt`"], [repository svn version])
else
AC_DEFINE_UNQUOTED(SVN_VERSION, ["`svnversion -n`"], [repository svn version])
`svnversion -n > saved_svn_version.txt`
fi

Update Makefile.am

You'll want to make sure that saved_svn_version.txt will be included when you do "make dist".  So, add it to your EXTRA_DIST, or make an EXTRA_DIST if you don't have one already

EXTRA_DIST = saved_svn_version.txt

Use the value in your source code

printf("SVN VERSION is %s\n",SVN_VERSION);

That's all there is too it.

Caveats/Limitations

The SVN_VERSION will only get updated when you run configure.  If you are like me and "make distclean" before committing your latest revisions, then this is fine, because next time you want to build your code you'll have to ./configure and the values will be updated.  I guess the downside is that if you test some changes, make distclean, then commit, it won't show that the version has changed.  You'll have to ./configure and then make distclean one more time before committing.  I can live with that.  Someone more savvy might point out that there probably a hook you could write somewhere to update saved_svn_version.txt at some point in the process.
Comments