he build process has always been one of the dark mysteries of Visual Studio. What exactly happened when you pressed F5 inside the IDE? Nobody really knew for sure.
This is one of the reasons why Microsoft decided to redesign the whole build process from scratch in Visual Studio 2005. In this upcoming release the whole build process is separated from the IDE and is bundled in a standalone tool called MSBuild. The advantage of this approach is that MSBuild is part of the .NET Framework 2.0 and in the Longhorn timeframe the .NET Framework will be part of the underlying operating system. So you don’t need anything in your build lab except a computer running the .NET Framework?there are no other deployment issues, like there are in Visual Studio 2005.
Why should you switch to MSBuild?
- All project files created in Visual Studio 2005 are MSBuild project files.
- MSBuild is designed for scalability, performance, and extensibility.
- You are able to customize the whole build process for your own requirements: as a example you can include functionality from Source Code Control Provider like Visual Source Safe into your build process (e.g. getting the latest version, labeling builds etc.)
You don’t need to install Visual Studio 2005 in your build lab. You only need the .NET Framework 2.0.
Project files in Visual Studio 2005 are XML files that describe the whole build process, splitting it up into several fine-grained tasks. The visible part of MSBuild is contained in the console application msbuild.exe, which drives the whole build process. It is a thin wrapper around the core build engine implemented in the assembly MSBuildEngine.dll. This application receives project files as input and processes them synchronously.
Overview of MSBuild
The execution engine of MSBuild is responsible for executing the project files and calling all defined Tasks synchronously. Tasks are part of a so-called Target. You can see a Target as a component that is created during the build process (like an assembly). Tasks can receive their inputs from Properties and Items and can produce so-called Output Items that other Tasks can use as their inputs. Table 1 gives the definitions for these important terms.
Table 1. You should be familiar with these important terms before using MSBuild.
Term |
Description |
Target |
A target is a component that is created during the build process?like an assembly. |
Task |
A Target can consist of several tasks that describe the workflow used to create the Target. A Task represents a work item that must be executed?think of the compilation of C# files with csc.exe. |
Properties |
Properties are defined as key/value pairs. Properties are used to configure the build process. An example is the output path of the created assemblies. |
Items |
Items are lists of objects that can be used for Tasks as inputs. For example, the Task used to call csc.exe retrieves C# files as input items for the compilation. |
Output Items |
Tasks can produce Output Items that can be consumed from other Tasks as Input Items. Because of the loosely-coupled architecture it is possible to link tasks together written by different vendors in different languages. |
Conditions |
Conditions are used to drive the build process. With Conditions you can define if Tasks or Targets should be executed during the build process. |
Building an App
Now that you have a basic understanding of MSBuild and its key terms, I’ll walk through a simple project file that describes how a traditional C# Hello World program can be built:
Application1
You can start the build process with the command msbuild.exe MyProjectFile.csproj typed from the command line. The project files consist of the element
Table 2. The project files consist of the element
Attribute |
Description |
MSBuildVersion |
Current version number of MSBuild; currently 2.0 is used. |
DefaultTargets |
Lists the Targets that must be created during the build process. Several Targets can be split using a semicolon (;). Each Target listed here must be defined in the project file with a |
Underneath the element
Each Item array can be referenced through it’s name. The name of an array is the name of the XML element used. For example, when you use the element
An Item group can be referenced with the syntax @(ItemName). All in all there are three different ways to add items to an Item Group. The first way requires you to specify each file that should be added to the specified Item Group:
The second way allows wildcards such as *:
Finally, you can explicitly list your files:
The files in an
Checking Conditions
Conditions can be applied to the elements
Application1 binDebug binRelease
With msbuild.exe MyProjectFile.csproj /p:Configuration=Release you can start the build process and specify the appropriate configuration.
I have already mentioned that it is possible that Tasks can communicate with each other through a loosely coupled-architecture. Tasks can create Output Items that can be consumed from other Tasks as Input Items. The code that follows illustrates this concept: The C# compiler creates an assembly used by the Task Copy to move it to another folder.
As you can see, the Output Items must be explicitly defined within the Task. Therefore the element exists. With the attribute ItemName you can define the name with which another Task can refer to that Output Item. Additionally you must set the Attribute TaskParameter, which defines which property from the Task is exposed as an Output Item.
Table 3 describes the new XML tags you’ll be using with this project.
Table 3. XML tags control the MSBuild process.
XML-Tag |
Description |
|
Defines the root element of the project file. |
|
All properties are defined within this element. |
|
Items that should be processed from Tasks are defined within this element. |
|
Defines a target that should be built like an assembly. |
|
Represents a Task that should be executed during the building of a target. |
Use this element to output Items from Tasks to other Tasks as Input Items. |
|
|
Use this element to register your own written Tasks within MSBuild. |
? |
? |
Extensibility Through User-defined Tasks
Up to this point, this article has described the inner workings of MSBuild and how you can write project files that can be consumed from
First, what exactly is a ‘user-defined Task’? Simply put, it’s a managed class implementing the interface Microsoft.Build.Framework.ITask defined in the assembly MSBuildFramework.dll. Let’s have a look at the definition of the interface:
public interface ITask{ public bool Execute(); public IBuildEngine BuildEngine { get; set; } public object HostObject { get; set; }}
![]() |
|
Figure 1. The Class Model: This image shows the class model that is located behind a Task. |
The most important method is Execute. Execute is called when the Task is started through MSBuild. Furthermore you can find in the namespace Microsoft.Build.Utilities (assembly MSBuildUtilities) the class Task that is already implementing the interface ITask. The only thing you must do when deriving from this class is override the method Execute and implement your own build process logic to execute. Figure 1 shows the class model that is located behind a Task.
Your own Tasks must be registered within MSBuild when you want to use them. For the registration you can use the XML element
After this registration the Task can be used as every other Task shipped with MSBuild. But you’ll also need to know how a concrete Task can be implemented. The following code implements a Task that shows a Hello World message box.
using System;using System.Windows.Forms;using Microsoft.Build.Framework;using Microsoft.Build.Utilities;namespace MyTasks{ public class HelloWorld : Task { public override bool Execute() { MessageBox.Show("Hello World from MSBuild!"); return true; } }}
Finally, here’s how to register and use a user-defined Task within a project file:
As you already know you have the possibility to connect several Tasks through the use of Input and Output Items. The next thing to learn is how to create a user-defined Task that produces Output Items that can be consumed from other Tasks as Input Items. Every public property within the implemented Task class can be accessed from the project file as an XML attribute. Properties that are marked with the attribute [Output] are Output Items.
The following example declares the property Files that accepts a list of files for which the last write time should be changed to the current time. Furthermore this property is marked with the attribute MSBuild is completely extensible and scalable for large-scale enterprise applications. MSBuild was used for several years internally at Microsoft for building its own software products. Even better, there are rumors that Microsoft may decide to migrate the whole build process for Longhorn to MSBuild. While that doesn’t change what MSBuild can do for you it does provide some welcome ‘eating their own dog food’-level comfort. If Longhorn can be built with MSBuild then this tool is a first-class citizen for our own enterprise applications.