Tonight I'm doing something completely different. I'm not working on WiX. In fact, I'm not even working on one of my own projects. Last week, I mentioned that I was considering switching the WiX versioning scheme to one based on git history. I found two projects that tackled versioning via git history. However, neither of them supported native code (think .vcxproj). That means it's time to roll up our sleeves and enhance one of these projects. Sound good? Yeah. Let's code!
Picking the project
As noted above, when doing my research, I found two solutions to versioning via git history. One of them is called GitVersion. This is the project I looked at first. It is a very nice looking project with lots of documentation and several interesting integrations. However, the more I dug into the documentation the more concerned I got.
I want every build to create a unique version number. At relatively rare times, I will update the major or minor version and the build number can start over again. That's it. Very simple requirements.
Maybe I can get that with GitVersion but after reading the documentation for a while I didn't immediately see what set of configuration was going to give that. I especially didn't want to be concerned about what the version would be based on the branch the code was committed to.
Fortunately, I came across NerdBank.GitVersioning (or NB.GV or as I often call it "GitVersioning"). The documentation for the project isn't laid out as cleanly but the stated goals of the project immediately caught my attention:
- Prioritize absolute build reproducibility. Every single commit can be built and produce a unique version.
- No dependency on tags. Tags can be added to existing commits at any time. Clones may not fetch tags. No dependency on tags means better build reproducibility.
- No dependency on branch names. Branches come and go, and a commit may belong to any number of branches. Regardless of the branch HEAD may be attached to, the build should be identical.
- The computed version information is based on an author-defined major.minor version and an optional unstable tag, plus a shortened git commit ID.
Sound familiar? Yep. That's exactly what I was looking for and articulated better than I do. So, does it support native code? Nope. But issue #94 says they wish it did. And since no one has made progress on the issue since December I guess I'll do it.
Normally, I'd be creating a branch in one of my existing repositories. But this is a new project for me. So, I click "Fork" in the GitHub UI and clone my copy of GitVersioning.
git clone https://github.com/robmen/Nerdbank.GitVersioning.git GitVersioning git checkout -b 94-nativebinaries
I'm primarily focused on MSBuild integration
so I start with the .targets file:
It's pretty simple.
GetBuildVersion target calculates all the version information
and the results are stored in a bunch of properties.
GenerateAssemblyVersionInfo target does the work
to write the assembly information into a file
and include that file in the compilation.
Either I teach the
called by the
to write out .rc files.
Or I create a new task and target.
After digging through the
I decide the
AssemblyVersionInfo code was complex enough dealing with C# and VB.
Adding something completely different would be too much.
I'll create the new target and task.
So, let's get to work.
I copy the
and name it
I'm so creative sometimes.
Then I moved the
VersionSourceFile property into
and create a copy of it
in my new
but change the extension from
I didn't know
$(DefaultLanguageSourceExtension) existed (kinda' cool).
Unfortunately, it won't work for our case because it is ".cpp"
and we're generating a .rc.
It doesn't technically matter
but it would be pretty confusing to see a .cpp file
being compiled by
Now to write the task that does the actual work.
Continuing along with my original creative streak
I copy the
AssemblyVersionInfo.cs file and name it
Then I gut all the code that processes .cs files
and start adding functionality to create a VERSIONINFO resource.
One of the nice things the
AssemblyVersionInfo tasks does
is inject a static class with the all version information
into your assembly.
This provided direct access to the version information so
your C# code could display the version information or what not.
In the native code I wanted to do the same
by putting all the version information in
Thus I added a standard
VERSIONINFO resource that looked
like the following:
VS_VERSION_INFO VERSIONINFO FILEVERSION NBGV_FILE_MAJOR_VERSION,NBGV_FILE_MINOR_VERSION,NBGV_FILE_BUILD_VERSION,NBGV_FILE_REVISION_VERSION PRODUCTVERSION NBGV_PRODUCT_MAJOR_VERSION,NBGV_PRODUCT_MINOR_VERSION,NBGV_PRODUCT_BUILD_VERSION,NBGV_PRODUCT_REVISION_VERSION FILEFLAGSMASK 0x3FL #ifdef _DEBUG FILEFLAGS 0x1L #else FILEFLAGS 0x0L #endif FILEOS 0x4L FILETYPE NBGV_FILE_TYPE FILESUBTYPE 0x0L BEGIN BLOCK ""StringFileInfo"" BEGIN BLOCK NBGV_VERSION_BLOCK BEGIN VALUE ""CompanyName"", NGBV_COMPANY VALUE ""FileDescription"", NGBV_TITLE VALUE ""FileVersion"", NBGV_FILE_VERSION VALUE ""InternalName"", NGBV_INTERNAL_NAME VALUE ""OriginalFilename"", NGBV_FILE_NAME VALUE ""ProductName"", NGBV_PRODUCT VALUE ""ProductVersion"", NBGV_INFORMATIONAL_VERSION VALUE ""LegalCopyright"", NBGV_COPYRIGHT END END BLOCK ""VarFileInfo"" BEGIN VALUE ""Translation"", NBGV_LCID, NBGV_CODEPAGE END END
NBGV_ values are
NativeVersionInfo task writes out the
and that standard
to the output .rc file.
I won't actually finish the scenario where the
are included in the final built binary.
I'm thinking in the future
if I add the
to the C++ compilers
INCLUDES then you could do:
And all the
#define variables would be available.
Or something like that.
It looks easy now that we're done
but I spent a lot of time wandering
through all the existing code
trying to understand what the best path through.
I also spent a lot of time futzing
until I finally got that to look good.
Anyway, this is enough for tonight.
git add src\Nerdbank.GitVersioning.NuGet\build\Nerdbank.GitVersioning.targets git add src\Nerdbank.GitVersioning.Tasks\NativeVersionInfo.cs git commit > Support GitVersioning in .vcxprojs > > Generate a .rc file and include it into the build pipeline for native > code in a fashion similar to the `GenerateAssemblyVersionInfo` task. > > Fixes #94 git push
Then back to my fork on GitHub and push the button to send a pull request.
Now we wait for someone to accept my PR.
Until next time! Keep coding. You know I am.