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:
- 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.
- Dependencies. When you have one project that references another, Visual Studio will always re-build the referencing project if referenced project has changed. </ol>
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
Build Output
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:
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:
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:
Build Results:
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.
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:
You can also enable this via the ReSharper options:
Choose Internals under Options:
Set options as below:
Have fun!
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.