Sunday, May 1, 2011

How to synchronize SVN revision and version ressources of EXE/DLL files?

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?

From stackoverflow
  • 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.

    Stefan : SubWCRev is also available separately for those who don't (want) to use TortoiseSVN: http://sourceforge.net/project/showfiles.php?group_id=138498&package_id=281312
    Lasse V. Karlsen : Cool, I didn't know that!
    Jim T : well thats my fact for the day :)
  • 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.

  • 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.

0 comments:

Post a Comment