SVN Revision Numbers in Application VERSION Resources

Martin Hofmann

Missing or cumbersome and unreliable ways of getting a SVN revision number into the VERSION resource of a Windows application (or into a printable string literal in a Standard C program) have frustrated me for quite some time. I think I now have a viable solution recipe for this.

The Problem

Having SVN substitute keywords in sources file (eg $Rev: 123$) is nice and useful, but these substitutions are file-based and do not reflect the project revision number.

The SVN client installation has the svnversion command for this reason, and it indeed outputs the project-wide revision number, including an indication if the working copy has any local modifications (123M), has a mixed revision range (123:129), or if the working copy is switched (123S), or a combination of these indicators (see the description of the svnversion command in “the SVN Book” Version Control with Subversion).

This is the revison number (rsp indicator) which we want to have in the VERSION resource, so that it will be displayed in the Windows Shell if one opens the property sheet for the executable file (select the file and press key Alt-Enter, or use the context menu).

Unfortunately, this revision indicator is only available as the standard output of the cited command, and we need a way to get it from there into the source code at the right times. This way should not require any developer intervention from build to build and from commit to commit, it should not trigger needless compilation due to changed file modification times, and of course it should not trigger a SVN revision itself.

A Solution

Here is a solution that works in Visual Studio, and the obvious similar technique should also work in makefiles.

  1. We store the svnversion output in a one-liner header file (I use the name svnversion.h for it):

    #define SVNVERSION "123M"
  2. We do not place this file under revison contol, and we do not commit the file into the repository. We add the name to the svn:ignore list of file patterns instead. (Naming the file svnversion.tmp and ingnoring files matching *.tmp by default would be a more general approach.)

  3. This tiny header files is placed in source tree of the working copy where it can be included when needed, for example with a #include "svnversion.h" directive in the resource script (*.rc) that defines the VERSION resource.

  4. We re-generate the svnversion.h header file immediately prior to each build, and we also re-compile the resource script defining the VERSION resource right away.

    In Visual Studio, this can be done in a “Pre-Build Event” action for all configurations, available in the property sheet of the Project nodes in the Solution Explorer pane.

    This is content of the Description field (it will be printed in the build log):

    Getting SVN version number into "svnversion.h"...

    This is the content of the Command Line field (join the indented lines in the Visual Studio project property sheets rsp makefile!):

    for /f %%i in ('svnversion -n ^"$(ProjectDir)..') do
      ( echo #define SVNVERSION "%%i" > "..\resource\svnversion.h" )
    echo ~~~
    type "..\resource\svnversion.h"
    echo ~~~
    echo Compiling resource file "$(ProjectName).rc"...
    echo rc /d "_UNICODE" /d "UNICODE" /I "..\src"
      /fo"$(IntDir)SwAddinSimple.res" "..\resource\$(ProjectName).rc"
    rc /d "_UNICODE" /d "UNICODE" /I "..\src"
      /fo"$(IntDir)SwAddinSimple.res" "..\resource\$(ProjectName).rc"
    In the first line:

It should be obvious how these actions could be invoked in a makefile to achieve the same effect.

Properties of this Solution

(There should be better remedies in the last two cases …)