views:

977

answers:

3

Say I have some C++ project which builds an exe or dll file. The project is checked into a SVN repository. I want to automatically synchronize the revision from SVN with the version resource embedded in my exe/dll file, i.e. the version should be something like $major.$minor.$svn_revision.
Any ideas on how to achieve this? Are there any out-of-the-box solutions available?

+6  A: 

If you have TortoiseSVN installed, then there is a program installed with it, SubWCRev.

If, in your file, you have this value:

$WCREV$

Then it'll be replaced with the highest committed revision number if you execute something like this:

SubWCRev .\ yourfile.txt.template yourfile.txt

This will copy from yourfile.txt.template, do the substitutions, and write to yourfile.txt.

Note that there's a lot of other macros you can use as well, if you execute SubWCRev without any arguments, it'll list them all on the console.

Lasse V. Karlsen
Stefan
Cool, I didn't know that!
Lasse V. Karlsen
well thats my fact for the day :)
Jim T
+2  A: 

You might want to look into Subversion Properties and Subversion Keywords. They don't solve the resource problem since they always include that damned $KeywordName: ...$ part. Custom properties do provide a nice method for making metadata available in batch files and what not.

Anyway, I looked for a solution to the resource problem a few years ago and didn't find one. So, we created our own home-grown solution. We changed our RC file to include a header file that was generated during the build process. The RC was dependent on the header and the header had a custom build rule that invoked a batch file to generate the header. The following snippet will extract the current revision from the output of svn info.

SET rootdir=%1
SET svnrev=0
PUSHD "%rootdir%"
FOR /F "tokens=1-4 delims=: " %%I IN ('svn info') DO (
    IF /I {%%I}=={rev} SET svnrev=%%L
)
(ECHO./*
 ECHO. * version-stamp.h - repository version information
 ECHO. */
 ECHO.#ifndef VERSION_STAMP_H
 ECHO.#define VERSION_STAMP_H
 ECHO.#define REPOSITORY_VERSION %svnrev%
 ECHO.#endif) > include\version-stamp.h
POPD

Then we created a component specific version stamping header named component-info.h that looked something like:

#ifndef component_info_h
#define component_info_h
#include "product-info.h"
#include "version-stamp.h"

#define VERS_MAJOR 1
#define VERS_MINOR 2
#define VERS_PATCH 3
#define VERS_BUILD REPOSITORY_VERSION

#define MY_COMPONENT_NAME "TPS Report Generator"    
#define MY_VERSION_NUMBER VERS_MAJOR,VERS_MINOR,VERS_PATCH,VERS_BUILD
#define MY_VERSION_STRING VERSION_STRING(VERS_MAJOR,VERS_MINOR,VERS_PATCH,VERS_BUILD)

#endif

Finally, we had a product-line version file that defined the product information named product-info.h:

#ifndef product_info_h
#define product_info_h

#define PROD_VERS_MAJOR 0
#define PROD_VERS_MINOR 1
#define PROD_VERS_PATCH 0
#define PROD_VERS_BUILD 0

#define VSTR1(s) #s
#define VSTR(s) VSTR1(s)
#define VERSION_STRING(a,b,c,d) VSTR(a) "." VSTR(b) "." VSTR(c) "." VSTR(d) "\0"

#define MY_COMPANY_NAME         "IniTech\0"
#define MY_COPYRIGHT            "Copyright ©2009 " MY_COMPANY_NAME
#define MY_PRODUCT_NAME         "\0"
#define MY_PRODUCT_VERSION_NUM  PROD_VERS_MAJOR,PROD_VERS_MINOR,PROD_VERS_PATCH,PROD_VERS_BUILD
#define MY_PRODUCT_VERSION_STR  VERSION_STRING(PROD_VERS_MAJOR,PROD_VERS_MINOR,PROD_VERS_PATCH,PROD_VERS_BUILD)
#endif

Then your resource file includes component-info.h and uses the various defines in the appropriate places (e.g., FILEVERSION MY_VERSION_NUMBER). This structure gave us a lot of flexibility and traceability in the whole version stamping process. It grew from a simple chunk in a batch file into this multi-leveled monstrosity but it has worked very well for us for the last few years.

I find it hard to believe that no one has found a better way to do this yet. Then again, I haven't investigated it for a number of years. I would assume that you could add a custom .rules file that defines a custom tool that handles this.

D.Shawley
+1  A: 

This is great help, thanks. I've refined this for Visual Studio 2008 if it's of any help to anyone.

1/ Created a /Build folder within each project

2/ Copied AssemblyInfo.cs to the Build folder as AssemblyInfo.cs.txt, set the Build Action to "None"

3/ Edited the AssemblyInfo.cs.txt to have version attributes as below:

[assembly: AssemblyVersion("2.0.0.$WCREV$")]
[assembly: AssemblyFileVersion("2.0.0.$WCREV$")]

4/ Added the following to the Prebuild events:

SubWCRev $(SolutionDir) $(ProjectDir)\Build\AssemblyInfo.cs.txt $(ProjectDir)\Properties\AssemblyInfo.cs

This works everytime you compile.

I am using VisualSVN/TortoiseSVN and VisualSVN Server with Visual Studio 2008.

UPDATE:

My colleague has just updated his working copy and AssemblyInfo.cs is conflicted. Seems obvious. I have excluded it from SVN using VisualSVN to resolve this.

Program.X