Pre-Instrumentation Targets for MSBuild

Pre-Instrumentation Targets for MSBuild

pre_instrumentation_msbuildThe flexibility of NCover pre-instrumentation has been demonstrated in two previous articles describing both the NCover Pre-Instrumentation and the Pre-Instrumentation for Continuous Integration. Pre-instrumentation for coverage collection with NCover can also be integrated directly into MSBuild projects. MSBuild targets are the core of Visual Studio projects and solutions. MSBuild is leveraged by a multitude of build engines, so MSBuild targets to pre-instrument assemblies are very helpful.

Sample Targets

<PropertyGroup>
   <TargetAssembly>$(TargetDir)$(TargetFileName)
       </TargetAssembly>
   <NCOVEREXE>"d:\<install folder>\ncover.exe"</NCOVEREXE>
   <NCOVER_COVERAGE Condition=" '$(NCOVER_COVERAGE)' == '' ">false</NCOVER_COVERAGE>
</PropertyGroup>
<Target Name="TriggerNCoverPreinstrument"
     Condition="'$(NCOVER_COVERAGE)'=='true'"
     AfterTargets="AfterBuild" BeforeTargets="">
   <Message Text="******* SHOULD PRE-INSTRUMENT *********" Importance="High"/>
   <CallTarget Targets="NCoverPreinstrument"/>
</Target>
<Target Name="NCoverPreinstrument">
   <Message Text="NCover Pre-instrumentation for $(TargetAssembly)" Importance="High"/>
   <Exec Command="$(NCOVEREXE) instrument &quot;$(TargetAssembly)&quot;"
       ContinueOnError="true" />
</Target>

Adding these targets to a <project>.Common.targets is a simple way to enable every project in a solution to be assigned the NCoverPreinstrument target and to provide automatic instrumentation on any build command. By default, the NCOVER_COVERAGE property is set to “false” if the value is not otherwise provided before the build.

Most project files will have included projects. In the case below, there’s an include for Microsoft.CSharp.targets and then a second include for a custom project targets file. A custom targets file is a great way to add targets, items, and properties that are common to all project files in a solution.

<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<Import Project="..\<my_solution>.Custom.targets" />  
      <!-- may have to add one of these -->

Adding the Targets

In the case above, just edit the <my_solution>.Custom.targets file and add the sample targets above. Custom target files are not included in projects by default. If you don’t have one, you can create one and add an Import command to all your MSBuild project files. A typical custom targets file would look like the following:

<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
   <TargetAssembly>$(TargetDir)$(TargetFileName)</TargetAssembly>
   <NCOVEREXE>"d:\<install folder>\ncover.exe"</NCOVEREXE>
   <NCOVER_COVERAGE Condition=" '$(NCOVER_COVERAGE)' == '' ">false</NCOVER_COVERAGE>
</PropertyGroup>
<Target Name="TriggerNCoverPreinstrument"
   Condition="'$(NCOVER_COVERAGE)'=='true'"
   AfterTargets="AfterBuild" BeforeTargets="">
   <Message Text="******* SHOULD PRE-INSTRUMENT *********" Importance="High"/>
   <CallTarget Targets="NCoverPreinstrument"/>
</Target>
<Target Name="NCoverPreinstrument">
   <Message Text="NCover Pre-instrumentation for $(TargetAssembly)" Importance="High"/>
   <Exec Command="$(NCOVEREXE) instrument &quot;$(TargetAssembly)&quot;"
       ContinueOnError="true" />
</Target>
</Project>

Invoking Pre-instrumentation

These targets give us the flexibility to invoke pre-instrumentation in two separate ways. The first is to add -p:NCOVER_COVERAGE=true to any MSBuild command. This property will signal to MSBuild that pre-instrumentation should be performed on each assembly as it is built in the larger build process. That command would look like one of the following:

In a project folder:
> msbuild /p:NCOVER_COVERAGE=true

A specific project:
> msbuild some_project.csproj /p:NCOVER_COVERAGE=true

A solution build:
> msbuild my_solution.sln /p:NCOVER_COVERAGE=true

The second method to invoke pre-instrumentation is to directly call the NCoverPreinstrument target. This won’t trigger a rebuild of the project source targets, but it will instrument the target assembly from the last build.

In a project folder:
> msbuild /t:NCoverPreinstrument

A specific project:
> msbuild some_project.csproj /t:NCoverPreinstrument

A solution build:
> msbuild my_solution.sln /t:NCoverPreinstrument

Of course, it’s possible to simply add the targets to every project file, but this is one example of target integration with some simple elegance. Please post a reply with your own preferences and improvements.

Trackbacks

  1. […] Pre-Instrumentation Targets for MSBuild (Kerry Meade) […]