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.
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.
Here is a solution that works in Visual Studio, and the obvious similar technique should also work in makefiles.
We store the
svnversion output in a one-liner header file (I use
svnversion.h for it):
#define SVNVERSION "123M"
We do not place this file under revison contol, and we do
not commit the file into the repository. We add the name to
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.)
This tiny header files is placed in source tree of the working copy
where it can be included when needed, for example with a
"svnversion.h" directive in the resource script (
We re-generate the
svnversion.h header file immediately prior to
each build, and we also re-compile the resource script defining
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!):
In the first line:
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"
^"” is correct, and
"” in front of the apostroph
It should be obvious how these actions could be invoked in a makefile to achieve the same effect.
VERSION resource in the generated binary (
will always reflect the project revision at the time of build.
If the target binary is up-to date, no unneeded re-build of the target will occur, since the “Pre-Build Event” will not occur, and the resource compiler will not be invoked on the resource script.
The project settings for this recipe are independent of the build configuration of the file and project names - they could be configured in a project template once and used in any new project afterwards.
The build will not fail if the source tree is not a working copy
(if it is from a
svn export, for example), but the
command will output
Unversioned directory, and this will become
the revision indication.
The build will fail if the SVN client (namely the
command) is not available. In this case, one could facilitate the
build process by placing a trivial
svnversion.bat file like this
somewhere on the
echo Unversioned directory
Archived source distributions could include such a placeholder
svnversion.bat which outputs the revision number of the sources in
the archive (and somehow place this
*.bat on the search path!)
(There should be better remedies in the last two cases …)