Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Automatic Build Versioning in Visual Studio

0.00/5 (No votes)
7 May 2005 1  
Automatic build version awareness, incrementing, and archiving.

Sample Image - build_versioning.jpg

Introduction

Many of your Windows executable files include version information. For example, in the Properties page for my C:\Windows\notepad.exe, the Version tab gives "File version: 5.1.2600.2180" along with other information. In a Visual Studio project, most or all of this information is stored in a resource file (default extension is .rc). I wanted an easy way to add automatic build versioning to my Visual Studio projects that would accomplish the following tasks:

  1. Increment the build number, so that each time the project is compiled, the executable's version information is updated.
  2. Archive a copy of each build executable in a separate location and name the files based on their respective versions.
  3. Allow the application itself to easily retrieve its own version information, such as through preprocessor constants in C++.

During my initial research I first determined that apparently none of these is natively supported in any version of Visual Studio. I then came across an existing Code Project article about a utility called RCStamp, which parses resource files and modifies the version information within, based on a given format string. This article does not go into the details of RCStamp, so I recommend you read its separate article first.

RCStamp solves task #1 on the list. This article explains the steps I took to solve my other requirements. First I outline the utility applications I created, after which I explain how it all comes together within Visual Studio.

Build Archiving (VerCopy)

The way I chose to solve the problem of archiving each build was to write a tiny utility application that simply takes a file as input, and copies it to a new file, which is named based on the version information. For example, running VerCopy on my notepad.exe would produce a new file called notepad-5-1-2600.exe. The code only uses the first three numbers of the file version because this is what I wanted. However the source code is extremely simple and is easily modified to suit anybody's needs. Here is the meat of the C# source code:

FileVersionInfo verInfo = FileVersionInfo.GetVersionInfo(PathFile);
string destFile = fileInfo.Name.Substring(0, 
    fileInfo.Name.Length-fileInfo.Extension.Length) + "-" 
    + verInfo.FileMajorPart + "-" + verInfo.FileMinorPart + "-" 
    + verInfo.FileBuildPart + fileInfo.Extension;

File.Copy(PathFile, destFile, true);

As you can see, C# makes it a simple matter to access the version information in a given file.

Version Awareness (VerHeader)

To solve the task of making my projects easily aware of their own current version information, I decided to write another small utility application that parses a resource file and produces a C++ header file with preprocessor constant definitions (#defines): one for major version number, one for minor version number, and a third for build number. Once again, the source code is simple and can quickly be modified to output the version data in any desired format, such as an inclusion file for a different language. Here's what the source looks like:

string line, major, minor, build;
while ((line = RCFile.ReadLine()) != null)
{
   int pos;
   if ((pos = line.IndexOf("FILEVERSION")) < 0)
      continue;
   pos += "FILEVERSION".Length + 1;
   string[] tempInfo = line.Substring(pos).Split(" .,".ToCharArray());
   ArrayList verInfo = new ArrayList(4);
   foreach (string s in tempInfo)
      if (s.Length > 0)
         verInfo.Add(s);
   major = verInfo[0].ToString();
   minor = verInfo[1].ToString();
   build = verInfo[2].ToString();
}

outFile.WriteLine("#define MAJORVERSION {0}", major);
outFile.WriteLine("#define MINORVERSION {0}", minor);
outFile.WriteLine("#define BUILDNUMBER {0}", build);

Integration into Visual Studio

Here I describe the method I use to add my three build versioning requirements to a Visual Studio project. It is quick and painless and once again the process is easily customizable to suit your needs. The steps I personally use are as follows:

  1. Copy the three utility executables into the solution folder. These are RCStamp.exe, VerCopy.exe, and VerHeader.exe.
  2. Add a version resource to the desired project and set the initial version information.
  3. Add a call to VerHeader in the pre-build event for all configurations.
  4. Add calls to VerCopy and RCStamp in the post-build event for the desired configurations.
  5. Include the VerHeader output file in the application.

Adding the Version Resource

To do this, simply right-click on the project name in Solution Explorer, and select Add->Add Resource... Choose "Version" from the list and click "New". The file will be added to the Resource Files folder for the project and given the same name as the project and the extension ".rc". Double-clicking it will open Resource View. Expanding the Version folder and double-clicking "VS_VERSION_INFO" will show you the contents of the file. Modify it whichever way you like. The "FILEVERSION" field is the one that will be modified by RCStamp and accessed by VerCopy and VerHeader. Be sure to save your changes.

Pre-Build Event

Before we build the application, we want VerHeader to create our header file for us, so we can include it in the application. To do this we add a call to VerHeader in the pre-build event for the project. This is a set of user-defined batch commands that are executed before the build process begins. To access the settings, right-click the project name in Solution Explorer and select Properties... Select "All Configurations" in the Configuration drop-down list and then expand the Build Events folder. In the Command Line field under Pre-Build Event, add:

..\VerHeader "$(ProjectName).rc" version.info

The working directory of the batch commands is the project folder. Usually this is a sub-folder within the solution folder, so VerHeader.exe is contained one step up from the working directory. Visual Studio provides some macros for us to use within these batch commands. $(ProjectName) is self-explanatory. We use it because the resource file's default name is the same as the project name. VerHeader will write to a file called "version.info". You can add a description such as "Updating Version Header..." which will be displayed in Visual Studio's build output window.

Post-Build Event

Once the application has been built, we want to store a copy of it using VerCopy. In addition, we want to increment the build number in our resource file. So we add calls to VerCopy and RCStamp in the post-build event for the project. This works exactly the same as the pre-build event except that it is called directly after a build succeeds. For the desired configurations, add the following to the post-build command line:

..\VerCopy "$(TargetPath)" "..\Builds\$(ConfigurationName)"
..\RCStamp "$(ProjectName).rc" *.*.+.*

Once again, we use the $(ProjectName) macro to access the resource file. $(TargetPath) is the full path of the output file for the project. $(ConfigurationName) is the name of the configuration that was just built. Therefore VerCopy will copy the output file to a Builds folder within the solution folder, and put it under a sub-folder according to the configuration. Next, RCStamp will increment the third value of the "FILEVERSION" field in the resource file, which I use as the build number. You can add something like "Archiving and Incrementing Build..." in the post-build Description field, which Visual Studio will display in its build output window.

Including the Header File

The last step is to include the outputted header file in your application. In C++, simply add a #include "version.info" directive and now you can use the preprocessor constants MAJORVERSION, MINORVERSION, and BUILDNUMBER within the code. This is useful, for example in a console application, for displaying version information to the user, as well as stamping logs with version information.

You will find that these steps are easy to remember, and once you've gone through them, they can be done in a matter of minutes.

Notes and Considerations

  • I have given the extension ".info" to the file outputted by VerHeader. This is because I use source control, and Visual Studio automatically adds all .h files to the solution's source control. I don't need every revision of the version header file to be stored in my source control depot, therefore I gave it a different extension.
  • The post-build steps are only executed when a build succeeds. This is why the call to RCStamp is in the post-build event. It could be in the pre-build event, with similar behaviour; however, in that case the build number would be incremented even on failed builds, which I do not prefer.
  • The pre-build steps are executed on every build attempt. Therefore the version header file is re-built even on failed builds. In this case the build number has not changed and so the call to VerHeader is useless. However, the first time we build the application the version header file does not exist, and thus needs to be created before the first build. In addition, the resource file can be edited manually and it can cause the version header file to become out-of-date between build attempts. So the inexpensive VerHeader call should be in the pre-build event.
  • In my setup, only the build number is automatically modified. I manually change the major and/or minor version numbers when I feel it is appropriate for the application. Of course you can easily customize anything to suit your needs.
  • The calls to the post-build event don't have to be performed for every build configuration. For example, you can choose to only increment the build number after release builds, or only archive release builds, etc.

Conclusion

I personally find this functionality to be greatly useful in projects with experimental code. I can run performance tests on any builds I wish and release the one with the best results, while working to improve any new changes. Coupled with source control, I finally feel like I have optimal control over not only my code revisions, but also the culmination of sets of revisions into new builds. Hopefully future versions of Visual Studio will provide a full-featured build versioning system, but until that time I feel that my solution is quite adequate. Many thanks to Peter Chen for creating RCStamp, which is really the backbone of this system.

Feedback

Please contact me with any and all feedback you have regarding this article and the source code. Anything from a spelling correction, to a simplification of the setup process, to a way to improve the source code would be much appreciated. The utilities I wrote are neither highly functional nor highly robust and I would be happy to make any modifications that are important or popularly requested. I would be particularly interested in learning about a scripting method to quickly perform the setup process for a given project within Visual Studio.

Revision History

  • May 7, 2005:
    • Original article.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here