John Robbins' Blog

MSBuild 3.5 Tips and a Small MSBuild 4.0 Wish List

Earlier this week, I spent some quality time porting a moderately complicated build over to MSBUILD 3.5, the version that comes with Visual Studio 2008. There are numerous new features in MSBUILD 3.5 that are quite interesting, especially the wonderful AdditionalProperties and Properties child elements on ItemGroup elements for MSBuild tasks. Now you can create your ItemGroup elements with custom settings

In the following example section of a bigger build file, I've got a debugger project that has to be built platform specific since the CLR debugger cannot handle debugging across bitness levels. By adding the AdditionalProperties child element to the DebuggerProjects property group, sets the platform. The BuildDebuggers task, as shown below, is now much easier to understand because you don't need six different MSBuild tasks calls to build all the combinations. While you will not need this new feature every day, it can simplify your build scripts when you do need it.

<ItemGroup>
  <
DebuggerProjects Include="..\Dbg\Dbg-x64.csproj">
    <
AdditionalProperties>Platform=x64</AdditionalProperties>
  </
DebuggerProjects>
  <
DebuggerProjects Include="..\Dbg\Dbg-IA64.csproj">
    <
AdditionalProperties>Platform=Itanium</AdditionalProperties>
  </
DebuggerProjects>
  <
DebuggerProjects Include="..\Dbg\Dbg-x86.csproj">
    <
AdditionalProperties>Platform=x86</AdditionalProperties>
  </
DebuggerProjects>
</
ItemGroup>
. . .

<Target Name="BuildDebuggers">

    <
MSBuild Projects="@(DebuggerProjects)"
             StopOnFirstFailure="true"
             Properties="Configuration=Release"
             Targets="build"
            
BuildInParallel="true"/>
    <
MSBuild Projects="@(DebuggerProjects)"
             StopOnFirstFailure="true"
             Properties="Configuration=Debug"
             Targets="build"
            
BuildInParallel="true"/>
  </
Target>
. . .

What I was most interested in taking advantage of building projects in parallel. The project I was porting over really didn't need the parallel builds, but it will be growing much larger so anything I could do to speed up the overall build time down the road would be great. The good news is that it's quite easy to get your projects set up to use. The big thing I found is that the MSBuild engine can run the actual individual builds in differing orders between runs. That's not a bad problem, but you need to be aware of it.

Just flipping the /maxcpucount switch on the MSBuild command line enables multiple build support. However, you'll probably find that your build doesn't work like I did. The single process version of MSBuild we've all been using executes the tasks in top to bottom order. If you have a project or step that others depend on, we all know to use the DependsOnTarget attribute on the subsequent Target elements. That becomes even more important with parallel builds. That attribute is how you ensure the exact order of the Targets gets built. You'll also want to be explicit about using the BuildInParallel attribute on the MSBuild task itself. In my case, I have a custom MSBuild task that's part of my build that's also used later by the build script itself:

<Target Name="BuildTasksTarget">
  <
MSBuild Projects="@(BuildTaskProjects)"
           Properties="Configuration=Debug"
           StopOnFirstFailure="true"
           Targets="build"
           BuildInParallel="false"
           UnloadProjectsOnCompletion="true"/>
</
Target>

In the MSBuild task for my custom MSBuild task, I specifically set BuildInParallel to false so this Target would be built and the task would wait on the task to complete before continuing.

  <Target Name="BuildAllCode" DependsOnTargets="BuildTasksTarget">
    <
MSBuild Projects="@(CommonProjects);
                       @(SomeMoreProjects);
                       @(EvenMoreProjects);
                       @(WayMoreProjects);
"
             StopOnFirstFailure="true"
             Properties="Configuration=Release"
             Targets="build"
            
BuildInParallel="true"/>
    <
MSBuild Projects="@(CommonProjects);
                       @(SomeMoreProjects);
                       @(EvenMoreProjects);
                       @(WayMoreProjects);
""
             StopOnFirstFailure="true"
             Properties="Configuration=Debug"
             Targets="build"
            
BuildInParallel="true"/>
  </
Target>

The BuildAllCode Target tells MSBuild to let fly with the magic of parallel builds for both the debug and release builds by setting BuildInParallel to true. In all the other Target elements, I carefully use the DependsOnTargets attribute to ensure I had the various Targets truly spaced in the proper order. Note that to use the BuildInParallel attribute, you'll have to set the ToolsVersion attribute on the top level Project element to "3.5."

As an avid MSBuild user, I'm hoping that version 4.0 will finally offer two key features that I think are missing. The first is a simple switch that will evaluate the project file, but not actually build anything. Being forced to execute all the build actions in a project ever time to test it gets very old, very fast. NMAKE has had the /D and /P switches for approximately six eons in Internet time. While you can throw in MessageTasks to do some tracing, MSBuild is still going to require you build everything. I almost shudder to turn on the /verbosity:diagnostic switch to see what my MSBuild scripts are doing. It's a classic case of way too much tracing with almost zero benefit. We desperately need this "what does MSBuild think it's going to do" option to make it easier to see exactly what our scripts will execute so we can quickly debug our scripts. There's nothing more frustrating than waiting for a twenty minute build script to execute over and over and over.

Since I'm on the subject of wishes, what would be even better would be an MSBuild debugger! I really can't see why we can't "step" through an MSBuild script like we can with dynamically generated .NET code or batch files (with my beloved 4NT command shell). The Visual Studio/.NET Teams are finished with Visual Studio 2008 so they have to be thinking about features for the next version. Of course, I have no idea how complicated the code is in MSBuild so it's easy for me to request. However, all we really need to do is to step through the targets themselves. The "variables" window would show the ItemGroups and Properties valid at that target. If those ItemGroups/Properties contains files, the values for each file would be their file time so we could see what MSBuild was determining was the valid reason for invoking that target. By providing us a debugger for MSBuild files, those of us using Team Foundation System and TeamBuild would have a hugely easier time of getting those correct as well. Maybe if we all start requesting an MSBuild debugger over and over we can get it on the feature list!

On Nov 11 2007 6:11 PMBy jrobbins MSBuildWith 6 Comments

Comments (6)

  1. Top of my wishlist is the equivalent of a 'finally', which would get run upon exit whether the build completed or not. We flush the TortoiseSVN auth cache at the end of each build (we use a read-only user to check everything out) and if the build fails or gets cancelled that won't run.

    And yes, 'dry run' functionality would be very nice indeed!

  2. Here is a debugger for MSBuild Projects http://blogs.msdn.com/parthopdas/archive/2007/12/01/visual-debugger-for-msbuild-projects.aspx

    John - could you give it a try and let me know?

  3. John,

    Thank you for very interesting post. It appears that most MSBuild users have similar desires.

    We at my company have been trying to address some of those issues, starting with project editing experience. Now, in v2 of our application we also tried to address the features you mention in your post, viz. visualization of targets & tasks (without building the project) and providing detailed log that will supply enough information to diagnose the problem and at the same time will not be overly detailed.

    I would be very interested in your opinion on whatever the approach we implemented is a hit or miss (see link for more info http://blogs.microsoft.co.il/blogs/tfsidekicks/archive/2007/11/29/msbuild-v2.aspx).

    Regards,
    Eugene

Leave a Comment

Archives

Tags