YOUR FEEDBACK
udaykiran wrote: Really Excellent Information. But i have some doubts. initially i have some aver...

SYS-CON.TV
TOP MICROSOFT .NET LINKS


Refactoring Your MSBuild Scripts
How to make maintainable processes

Some things change how you fundamentally program. Automation is one of those things. It is what will save you from wasting your weekend stepping through tedious and error-prone processes like regression testing (unit, integration, performance, functional, etc.), builds, deployment, or even documentation. Automation is one of those buzzwords we all know our projects should have (like "performance," "security," "maintainability," etc...), but the question is how?

Microsoft gave us a huge answer with .NET 2.0's MSBuild - its new build platform with a process-oriented scripting language. It can revolutionize not just how you build, but also how you test, deploy, and automate many of your development processes. The problem with these scripts, like the problem with anything else, is that they must be maintained. Perhaps the best way to maintain them is to keep them refactored - something that MSBuild makes very easy.

MSBuild Background
Refactoring is improving the code (usually by eliminating redundancy) while keeping the same functionality. To eliminate redundancy, you have to be able to split out code into separate, reusable chunks, and then pass data between those chunks. A simple MSBuild script is just a series of tasks. Therefore refactoring requires these steps:

  1. Pull out reusable properties.
  2. Group multiple tasks into a single target.
  3. Split out these targets into physically separate files
  4. Call these targets as needed.
  5. Pass data to and from these targets as we call them.
The first two steps are trivial. For example, this snippet shows two tasks (Message and Copy) grouped into a single target with variables named Var1 and Var2. Note that you can use one variable in defining another.

<PropertyGroup>
    <Var1>abc</Var1>
    <Var2>$(abc)def</Var2>
    <root>C:\myProj</root>
</PropertyGroup>

<Target Name="EndPoint">
    <Message Text="This is a task, print $(Var2)" />
    <Copy SourceFiles="$(root)\abc.txt"
       DestinationFolder="$(root)\myFolder" />
</Target>

The rest of this article will focus on the remaining three steps.

Splitting Out Scripts
Each MSBuild script is called a "project file." The extensions doesn't really matter, but will often be *.msbuild, *.task, or *.proj. Each project file is enclosed in the <Project> node (to save space, we'll omit the project node in the code snippets). MSBuild provides two ways to reach across physically separate projects files: (1) the Import Element and (2) the MSBuild task (not to be confused with MSBuild the engine itself). (See Table 1)

The Import element lets you insert one project file into another. For example, suppose you had a bunch of system-wide variables like application install paths. Getting a new version of an application may require updating its path, so you want to store all paths in a single file so it can be updated just once. You could do this by putting those paths in their own project (like "CommonProperties.proj"), and then importing that project into any script that needed it. This lets you update variables without touching each script.

CommonProperties.proj
   <PropertyGroup>
      <NameA>Value1</NameA>
      <NameB>Value2</NameB>
   </PropertyGroup>

Some other script:
   <Import Project="CommonProperties.proj" />
   <PropertyGroup>
      <NameB>Overrided</NameB>
      <NameC>Value3</NameC>
   </PropertyGroup>

   <Target Name="EndPoint">
      <Message Text="value from Include: $(NameA)" />
      <Message Text="value from Include: $(NameB)" />
   </Target>

Note that the properties in the imported script get overridden by any properties of the same name in the parent script.

Besides importing an entire project file, you can split your targets into separate project files and call them with the MSBuild task. The purpose of the MSBuild task is to call other targets, so we'll explain it more in our next section.

Ways to Call Targets
Once we have separate files, we have to be able to call targets in those files. MSBuild provides at least three ways to do this: (1) The MSBuild task that we just talked about, (2) The CallTarget task, and (3) the DependsOnTargets attribute of a target. The MSBuild task is a powerful way to call targets. (See Table 2) Because Visual Studio 2005 csproj projects are actually just MSBuild scripts, most developers are already using the MSBuild task. For example, these lines would build the MyApp project:

   <MSBuild Projects="$(rootdir)\MyApp.csproj"
      Targets="rebuild" Properties="Configuration=release" />

This task has three main attributes: the physical Project(s) file, the Target(s) to call within that project, and finally any Property(or Properties) to pass to that target. The power of the MSBuild task is that you can call any MSBuild project file and pass in your own properties (we'll discuss this more in the next section). This essentially lets you abstract out your targets to separate files as if they were class libraries.

When you don't need the full power of the MSBuild task, you can use the CallTarget task. Unlike the MSBuild task, it requires that the target be in the current project file (including all imported files), and it doesn't let you pass in your own property values. For example, you may have a build script that calls certain targets in a specific order:

<CallTarget Targets="GetSource" />
<CallTarget Targets="Compile" />
<CallTarget Targets="UnitTest" />

Yet another way to call targets is by using the "DependsOnTargets" attribute to specify which other targets the current target depends on. MSBuild is smart enough to automatically order the targets by their dependencies.

<Target Name="GetSource">
</Target>
<Target Name="Compile" DependsOnTargets="GetSource">
</Target>
<Target Name="UnitTest" DependsOnTargets="Compile">
</Target>

MSBuild is also smart enough to call each dependency only once. So if we added the GetSource target to the last line, so that it appears twice, it would still be called just once:

<Target Name="UnitTest" DependsOnTargets="Compile;GetSource">

Note that using CallTarget is an explicit approach - you start at the first target and march forward, explicitly calling each target in the order you want. On the contrary, DependsOnTargets is an implicit approach - MSBuild starts at the end of your script and steps backwards to infer the calling order.


About Timothy Stall
Tim Stall is a software developer at Paylocity, an independent provider of payroll and human resource solutions. He can be contacted at tims@paylocity.com.

MICROSOFT .NET LATEST STORIES
VMware’s ESX hypervisor has become the first third-party hypervisor accredited under Microsoft’s months-old Server Virtualization Validation Program (SVVP). The validation applies to VMware ESX 3.5 update 2 (ESX 3.5u2) and means VMware customers who run Windows Server and Microsoft...
We are seeing more being written about Cloud computing and cloud platforms today, and there is strong validation that the future of computing will include significant innovation and value in web/cloud platforms. Microsoft’s Cloud strategy is materializing, and as part of our overall ...
Nth Penguin has released WW.DataServices to the public and is available for immediate download at: www.nthpenguin.com. WW.DataServices, the first system of the WebWidgetry engine, removes all the work from accessing your data. You simply point it to a database location, push a button,...
Gizmox announced the release of a fully functional beta version of its Visual WebGui (VWG) with support for Microsoft Silverlight. For the first time, VWG enables Silverlight for enterprise applications by providing a RAD like Windows Forms development experience with drag & drop desig...
Google will come out from behind the Firefox browser that it’s been pumping money into – and profiting royally from – and take direct aim at Microsoft with a browser of its very own. The widgetry is called Google Chrome and Google Chrome, like all of Google’s non-search widgetr...
SUBSCRIBE TO THE WORLD'S MOST POWERFUL NEWSLETTERS
SUBSCRIBE TO OUR RSS FEEDS & GET YOUR SYS-CON NEWS LIVE!
Click to Add our RSS Feeds to the Service of Your Choice:
Google Reader or Homepage Add to My Yahoo! Subscribe with Bloglines Subscribe in NewsGator Online
myFeedster Add to My AOL Subscribe in Rojo Add 'Hugg' to Newsburst from CNET News.com Kinja Digest View Additional SYS-CON Feeds
Publish Your Article! Please send it to editorial(at)sys-con.com!

Advertise on this site! Contact advertising(at)sys-con.com! 201 802-3021


SYS-CON FEATURED WHITEPAPERS

ADS BY GOOGLE
BREAKING NEWS FROM THE WIRES
Neverfail, a leading global software company providing affordable continuous availability and disast...