3

I am trying to set up a proper way to do automatic versioning for my C# projects in .Net.

The requirements are:

  1. the assembly is to be built only when is is not up to date. (normal behaviour in Visual Studio and via MSBuild)
  2. When it is built the assembly is to get the proper version assigned.

I have found a solution to give me the version-strings I want. However, to make the assemblies reflect this version after build I need to change the assemblyInfo.cs file just before it is being built. I ended up enabling this functionality via adding a script to be run on the pre-build event. According to Microsoft documentation this should be fine:

Pre-build events do not run if the project is up to date and no build is triggered.

(ref: http://msdn.microsoft.com/en-us/library/42x5kfw4.aspx):

This is so not true! Pre-build event scripts always execute - even if the project is up to date! That is. The pre-build script is run, even when it doesn't recompile (since it is up-to-date). Since my script updates the assemblyInfo.cs file the project is no longer up-to-date so it recompiles (due to a bug/designflaw I had to add the directive to disable caching). This means that the project recompiles every time, which is of course not what I want - considering that I have 103 projects in my solution...

I have investigated this further by adding both BeforeBuild and BeforeCompile targets in the project-file. Guess what: They also run every time even if the project is up-to-date. I have tried running the build from both Visual Studio and from MSBuild with the same sad results.

Does anybody have a suggestion on how to have scripts run **only* when the project is not up to date?

BTW: Before it is suggested: I have reviewed most solutions available on the net, including automatic increments via the "1.*" specifier in assemblyInfo.cs. This is not what I want. My versioning needs are somewhat more complex.

Spiralis
  • 3,232
  • 2
  • 39
  • 53

1 Answers1

2

It doesn't seem anyone had a solution on this, but with extra investigation I was finally able to find a workaround.

After investigating the Microsoft.CSharp.targets file I found that there are no "hooks" in CoreCompile that call targets only when CoreCompile is run. CoreCompile itself depends on comparison of Inputs and Outputs to determine whether it should run or not. Armed with that information I copied the input and output specifications from CoreCompile and voila :)

My custom BeforeCompile task now like this:

<Target
  Name="BeforeCompile"
  Inputs="$(MSBuildAllProjects);
          @(Compile);                               
          @(_CoreCompileResourceInputs);
          $(ApplicationIcon);
          $(AssemblyOriginatorKeyFile);
          @(ReferencePath);
          @(CompiledLicenseFile);
          @(EmbeddedDocumentation); 
          $(Win32Resource);
          $(Win32Manifest);
          @(CustomAdditionalCompileInputs)"
  Outputs="@(DocFileItem);
           @(IntermediateAssembly);
           @(_DebugSymbolsIntermediatePath);                 
           $(NonExistentFile);
           @(CustomAdditionalCompileOutputs)">
  <Message Text="BeforeCompile (only when project is not up-to-date)"/>
</Target>

It looks a bit kludgy, but it works. The inputs and outputs are probably also fairly safe to copy. Can't see any good reason for Microsoft to change them often ...

Spiralis
  • 3,232
  • 2
  • 39
  • 53
  • I have a similar issue (unrelated to version numbers) where a pre-build event always runs and causes a good half-a-dozen projects that haven't changed to recompile on every build. Is there any chance you could expand on this answer? Can everything be self-contained in the project file? Using this workaround, where does one put the commands that used to be inside the `` tags in the project file? – Joel Mueller May 02 '11 at 23:21
  • Yes, I believe so. My sample above redefines the BeforeCompile build-target (which originally comes from the Microsoft.CSharp.targets file). You could also redefine the prebuild-targets, but I chose not to do so, because that would interfere with Visual Studio's "magic" (I recall VS doing some special processing for prebuild-events in the project file). Using the sample above you can just replace the -tag. I use , just replace the ... with your batchfile (or similar). You can freely embed the macros that Visual Studio exposes, like $(ProjectDir) and similar. – Spiralis May 05 '11 at 09:56
  • Thanks, that worked great! Once I remembered that the double-quotes inside my command string needed to be replaced with `"` that is. – Joel Mueller May 05 '11 at 20:45