MSBuild
All about MSBuild
ReSharper's Hidden Gem

During NDC, Eugene, from JetBrains, Technical Lead for ReSharper, showed me some of the cool things that are coming out in the next version, 5.0. But guess what? I'm not going to talk about those now :).

What I am going to talk about is an interesting problem he said they were having and something many of us also experience: building solutions.

Visual Studio takes some time to build solutions when something changes. The reasons for this are two-fold:

 

  1. Sequential Builds. When Visual Studio builds projects, it does them in a sequential order, even if these are completely independent. So let's say you have 20 projects, 15 of which are completely unrelated, Visual Studio will still build these sequentially.
  2. Dependencies. When you have one project that references another, Visual Studio will always re-build the referencing project if referenced project has changed.

 

And being ReSharper quite a large solution, it was taking them approximately five minutes to build, and they needed a fix for this.

One of the not-so-well-known features of MSBuild is the possibility of building projects in parallel. This is a feature that ships with the MSBuild 3.5 Tool set. The following code shows a simple MSBuild project that takes advantage of this feature:

 

   1: <?xml version="1.0" encoding="utf-8"?>
   2: <Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="3.5">
   3:   <ItemGroup>
   4:     <ProjectReference Include="**\*.csproj"/>
   5:   </ItemGroup>
   6:   <Target Name="BuildProjectSet1">
   7:     <MSBuild Projects="@(ProjectReference)" BuildInParallel="true"/>
   8:   </Target>
   9: </Project>

Combining this with the maxcpucount command line argument, you can specify the number of parallel builds.

Now this solves the first issue, of having independent projects build in parallel as opposed to sequentially, but what about the second problem? Every time you make a change in a project that is referenced in another project, Visual Studio will build the latter, even if none of the public interfaces have changed. Just so we make sure we're on the same page, let's go thru an example:

 

Building NHibernate using Visual Studio

If you've never built NHibernate before, the first time you need to run the NANT script for it to generate the missing AssemblyInfo.cs files, etc. Once you've done that, you can build it inside Visual Studio.

We first do a BUILD ALL and notice how seven projects get built:

 

Solution Window

image

 

Build Output

image

 

Now let's make a change to NHibernate.csproj, which is referenced by the majority of the other projects. We'll add a new public class to it:

image

 

If we now Build the entire solution, all projects that reference NHibernate will get re-built. This is expected behaviour since we've made a change to the public interface of the referenced assembly. However, what would happen if we just added a few lines of comments:

 

image

 

Despite the public interface not changing, all assemblies that reference NHibernate will be re-built (You can verify this by looking at the timestamps of the assemblies).

 

Verifying what has changed on referenced assemblies

Thinking about it though, why would we want to have Visual Studio rebuild all referenced assemblies even if there hadn't been a public interface change? Wouldn't it be great if that wouldn't happen? 

Here's where ReSharper comes into play. What the guys at JetBrains have done is use the assembly metadata to see if there has been a change in the public interface and ONLY if there has been, build!

This has allowed them to reduce their build time drastically, in some instances dropping down to 30-40 seconds (obviously based on the changes).

What they've done is create their own Solution Builder that examines if the metadata for a referenced assembly has changed. If and only if it has changed, then they build it.

Here's some screenshots of it in action:

 

Projects building concurrently when possible:

image

image

image

 

Build Results:

image

 

If we run the same changes steps against NHibernate as we've done above, using ReSharper's solution builder, we'll see that if there is no interface change on the referenced assemblies, those assemblies that use them don't get re-built. When in a large solution, this saves substantial amount of time as you can imagine. Combined with parallel builds of independent projects and we're on to a winner!

 

So when can I play with this?

The bad news is that as it stands right now, there is no guarantee that this feature will make it in 5.0. The good news is that you already have this feature in ReSharper :). However, before we go on, I have to put in a few words (I promised Eugene I would).

 

DISCLAIMER

WHAT I'M ABOUT TO SHOW YOU IS NOT OFFICIALLY, UNOFFICIALLY OR EVEN REMOTELY SUPPORTED BY JETBRAINS. THEY WILL NOT BE RESPONSIBLE IF YOUR PROJECT GETS CORRUPTED, DELETED, BUILDS SOMEONE ELSE'S PROJECT REMOTELY OVER THE INTERNET OR EVEN BLOWS UP BY ENABLING THE FOLLOWING FEATURES OF RESHARPER. USE PURELY AT YOUR OWN RISK. YOU, YOURSELF, AND POSSIBLY YOUR MOTHER WILL BE RESPONSIBLE FOR ANYTHING THAT HAPPENS FROM NOW ON. YOU CAN'T HOLD ME RESPONSIBLE EITHER, IN CASE THAT IS NOT BLATANTLY OBVIOUS. OH, BTW, THIS MIGHT NOT ALWAYS WORK.

 

 

To enable these features, close down Visual Studio and then start it up with the following command line option: /ReSharper.Internal. If all goes well, you'll have some new options enabled in the ReSharper menu (see image below). If you've got something named wrong, you'll get an error. Shut down and try again.

 

image

 

Obviously, apart from the Solution Builder, you'll see a whole slew of new features pop up under the ReSharper menu. I've not played with a lot of them yet, but plan to when I get a chance. 

 

Building using the Solution Builder

When you first open a project after launching Visual Studio with these features enabled, and try and Build, you'll get a screen asking you if you want to use Visual Studio solution builder or ReSharper's Solution Builder. You need to click MSBuild for the latter:

 

image

 

You can also enable this via the ReSharper options:

 

Choose Internals under Options:

image

 

Set options as below:

image

 

 

This works for Jetbrains and it works for me, but you use it at your own risk. It might not give you the desired results, but then again, that's why it's not released.

Have fun!

and there's no opting out...

Just noticed this under one of the Build failure notification e-mails received from the TFS daemon:

 

- You are receiving this notification because of a subscription created by xxxx\Hadi Hariri Provided by Microsoft Visual Studio® Team System 2008 <http://msdn.microsoft.com/vstudio/teamsystem/>

 

Notice there's no "If you do not wish to receive future notifications please....."

 

Nope, you're screwed. Your best bet is to not break the build...or break me!

ALM Session, Workshop and Planning Poker

Last week I did a session at Microsoft's first ALM Event in Spain (Microsoft ALM' 08). Was a very good event. As sponsors, iMeta also had a booth there were we were giving out among other things, Planning Poker cards. And they went like hot cakes!

I'm following up the presentation (Continuous Integration with VSTS) with a workshop to be held in Madrid on the 6th of November (in Spanish). The agenda will include not only how to set up CI with VSTS but more about the whole CI process including unit testing, integration tests, build automation, etc.

Download my session from here (they've recorded the session. Once I have the link I'll post it)

Workshop @ Microsoft Offices - Madrid, 6th November 2008

Introducción
Pruebas unitarias y suplantación de dependencias
Pruebas de integración
Integración continua como proceso
Automatización de procesos con MSBuild
Integración continua con TFS 2008
Extensibilidad de TFS 20083

Register here

 

image

P.S.: Due to the high demand, we are considering shipping Planning Poker cards at cost price to anyone interested. The process is not set up yet but we're hoping to have something in place pretty soon. If you're interested, send me an email and I'll make sure you're put on the list.

Targeting multiple frameworks with MSBuild

Visual Studio 2008 allows you to build your projects and target multiple frameworks. You can do so by choosing the Target Framework in the project’s properties.

 VS 2008 Properties

However, this functionality isn’t exclusive to Visual Studio. MSBuild as of version 3.5 has this feature built in. This allows us to have one build machine that targets multiple frameworks, without the need to even have VS installed.

The first thing you need to do is make sure you’re referencing the correct MSBuild executable. The best way is to add the install directory to your system path (normally %windir%\microsoft.net\framework\v3.5).

To be able to target different frameworks, we need to override a predefined property in the MSBuild common target files, called TargetFramework. As with any property in MSBuild, this can be done via the command line as so:

msbuild ConsoleApplication1.csproj /p:TargetFramework=v2.0 /ToolsVersion:3.5

The ToolsVersion parameter is to indicate to MSBuild which toolset to use. A toolset is a series of files (Target files, compilers) installed with each version of MSBuild. Since only the 3.5 version of the target files have the TargetFramework defined, we need to specify this on the command line. TargetFramework can be v2.0, v3.0 and v3.5

 

One Comment Filed Under [ MSBuild ]