VERSION
ResourcesMartin Hofmann
tin-pot@gmx.net
2014-03-10
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
the name 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
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.)
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.
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:
^"
” 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.
The VERSION
resource in the generated binary (.dll
or .exe
)
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 svnversion
command will output Unversioned directory
, and this will become
the revision indication.
The build will fail if the SVN client (namely the svnversion
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 PATH
:
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 …)