The .NET 2 platform is delivered with a new tool named msbuild.exe. This tool is used to build .NET applications. It accepts XML files which describe the sequence of tasks for the build process, in the same spirit as makefile files. Actually, in the beginning of this project, Microsoft had code named the tool XMake. The msbuild.exe executable is located in the .NET installation folder [Windows install folder]\Microsoft.NET\Framework\v2.0.50727\. It is planned that MSBuild will be part of the Windows Vista operating system. Its range of action will then be increased and may be used to construct all type of applications.

Until now, to construct your .NET applications, you needed to:

rither use the Build command in Visual Studio,

or use the Visual Studio devenv.exe executable as a command line,

or use a third party tool such as the open source tool named NAnt, or even use batch files which called the csc.exe C# compiler.

MSBuild aims to unify all these techniques. Those who know NAnt will not be in unknown territory as MSBuild borrows many concepts from this tool. The main advantage of MSBuild over NAnt is that it is used by Visual Studio 2005. MSBuild has no dependency on Visual Studio 2005 as it is an integral part of the .NET 2 platform. However, the .proj, .csproj, .vbproj etc. generated by Visual Studio 2005 to build projects are authored in the MSBuild XML format. During compilation, Visual Studio 2005 uses the services of MSBuild. In addition, the XML format used by MSBuild is fully supported and documented. The support of MSBuild is a significant progress for Visual Studio since until now, it used undocumented build scripts.

Since we wish to construct an assembly with more than one module, we have no choice other than to use the csc.exe command line compiler as the Visual Studio environment cannot handle multi-module assemblies.

Create the files Foo2.netmodule and Foo1.exe by typing, in order, the following command (the csc.exe compiler can be found in the folder <WINDOWS-INSTALL-FOLDER>\Microsoft.NET\Framework\v2.0.50727):

The root element of the MSBuild XML documents is <Project>. This element contains <Target> elements. These <Target> elements are the build units named targets. An MSBuild project can contain multiple targets and msbuild.exe is capable of chaining the execution of multiple targets. When you launch msbuild.exe through the command line, it takes as input a single .proj from the current folder. If multiple .proj files are present, you must specify to msbuild.exe which one to use. A single file must be specified.

An MSBuild target is a set of MSBuild tasks. Each child element to <Target> constitutes the definition of a task. The tasks of a target are executed in the order of their declaration. About forty types of tasks are provided by MSBuild, for example:

Task type

Description

Copy

Copies a file from a source folder to a destination folder.

MakeDir

Creates a folder.

Csc

Calls the csc.exe C# compiler.

Exec

Executes a system command.

AL

Calls the al.exe tool (Assembly Linker).

ResGen

Calls the resgen.exe tool (Resources Generator).

The complete list of possible tasks is available in the article named MSBuild Task Reference, on MSDN. An interesting aspect of MSBuild is that each type of task is materialized by a .NET class. It is then possible to extend MSBuild with new types of tasks by supplying your own classes. We will discuss this a little later.

Let us revisit our multi-module assembly example introduced in the previous section. Let me remind you that to build this assembly constructed from three modules Foo1.exe, Foo2.netmodule, and Image.jpg, we had to execute the following two commands:

In addition, we wanted that at the end of the construction of the assembly, the three modules be located in the \bin sub-folder from the current folder. Here is the MSBuild project Example1.proj which accomplishes the same work:

To execute this build project, you need to create a folder containing the following files:

.\Foo.proj
.\Foo1.cs
.\Foo2.cs
.\Image.jpg

Go in this folder with the command window (Start Menu --> Microsoft .NET Framework SDK v2.0 --> SDK Command Prompt) and then launch the msbuild.exe command. Each target must be named. By default, msbuild.exe only executes the first target. You can specify a list of targets separated by semi-colons using the /target (shortcut /t). You can also specify such a list using the DefaultTarget attribute of the <Project> tag. If multiple targets are specified, the order of execution is undefined.

The default behavior of MSBuild is to stop execution as soon as one of the tasks emits an error. You may wish to have a build script tolerate errors. Also, each element containing a task can contain a ContinueOnError attribute which is set to false by default but may be set to true.

To allow you to add parameters to control your scripts, MSBuild presents the notion of a property. A property is a key/value couple defined in the <PropertyGroup> element. MSBuild properties work as an alias system. Each occurrence of $(key) in the script is replaced by the associated value. Typically, the name of the /bin folder is used in five places in our project. It constitutes a good candidate for a property:

During the edition of properties with Visual Studio 2005, you will notice that a certain number of keys are proposed by intellisense. OutputPath, for example, is such a key. You can use these keys, but nothing prevents you from defining your own keys.

The base behind building a project by a script is the manipulation of folders, files (source, resource, executable…), and references (to assemblies, to COM classes, to resource files…). We use the term item to designate these entries which constitute the entries and outputs for most of the tasks. In our example, the Image.jpg file is an item consumed both by the Copy task and the second Csc task. The file Foo2.netmodule is an item produced by the first Csc task and is consumed by the second Csc task. Let us rewrite our project using the notion of item:

We notice the use of the @(item name) to reference an item. Moreover, an item can define a set of files through the use of the wildcard syntax. For example, the following item references all the C# files in the current folder except for Foo1.cs:

We may wish that the same MSBuild project build multiple different versions. For example, it would be a shame to have to create and maintain two projects to handle the build of a Debug and a Release version of the same application. Also, MSBuild introduces the notion of a condition. A Condition attribute can be added to any element of a MSBuild project (properties, item, target, task, property group, item group…). If during the execution, the condition of an element is not satisfied, the MSBuild engine will ignore it. The MSDN article named MSBuild Conditions describes the complete list of expression which can be used in a Condition attribute.

In the following example, we use the condition of type string equality compare to make sure that our script supports both a Debug and Release mode. We also use a condition of type test for the presence of a file or folder to execute the MakeDir task only when needed. This condition is there purely for learning reasons as the MakeDir only executes if the folder does not already exist:

In a real environment, the execution of an MSBuild project can take several minutes (even hours) to execute. As a side fact, did you know that since its beginning, the Windows operating system takes about 12 hours to build? This means the ever growing volume of code to be compiled compensates the performance increase of machines.

It is not necessarily a good thing to completely restart the build process for a minor change made on a source file for which no other components depend. Also, you can use the notion of incremental construction. For this, you must specify the list of input items and the output items for a target using the Inputs and Outputs attributes. If MSBuild detects that at least one of the input items is older than one of the output items, it will execute the target.

This incremental build technique forces you to partition your tasks into several targets. We have seen that if we specify multiple targets to build by MSBuild, for example with the DefaultTargets attribute, you can not assume any execution order. You can however specify a set of dependencies between targets using the DependsOnTargets attribute. MSBuild executes a target only when the totality of the targets on which it depends is executed. Naturally, the MSBuild engine will detect and emit an error when circular dependencies between targets exist:

You have the possibility of establishing an objective correspondence between the input items and the output items of a target. For this, you need to use MSBuild transformations detailed in the article named MSBuild Transforms, on MSDN. The advantage of using transformations is that MSBuild decides to execute the target if at least one of the input items is older than the output item which corresponds to it. Logically, such a target is going to be executed less often, hence a performance gain.

We have seen that the msbuild.exe tool can only process a single project file for each execution. However, an MSBuild project file can import another MSBuild project file by using the <Import> element. In this case, all the children of the <Project> in the imported file are copied in place of the <Import> element. Our example script can then be broken into two files Example7.proj and Example8.target.proj as follows:

I have already mentioned that the files of extension .proj, .csproj, .vbproj etc. generated by Visual Studio 2005 to build projects are authored in the MSBuild XML format. If you analyze such a file, you will notice that no targets are explicitly specified. In fact, the project files generated by Visual Studio 2005 import some .targets files which contain generic targets. For example, a file with a .csproj extension contains the following element:

<ImportProject="$(MSBuildBinPath)\Microsoft.CSharp.targets"/>

This Microsoft.CSharp.targets file contains two generic targets:

A target named CreateManifestResourceNames which takes care of the organization of resource files (transformation of .resx files into .resources).

A target named CoreCompile which contains a task named Csc which takes care of building C# files.

We recommend that you take a look at the .targets files located in the folder defined by $(MSBuildBinPath) which is the .NET 2.0 installation folder (i.e. [Windows folder]\Microsoft.NET\Framework\v2.0.50727).

In addition to importing such a .targets file, the files generated by Visual Studio 2005 contain essentially the definition of properties and items which will be used by the generic targets.

Another interesting aspect of MSBuild is that each type of task materializes itself in a .NET class. This means that it is possible to extend MSBuild with new task types by supplying your own classes. Such a class must support the following constraints:

It must implement the ITask interface defined in Microsoft.Build.Framework.dll, or derive from the helper class Task defined in Microsoft.Build.Utilities.dll.

It must implement the bool Execute() of the ITask interface. This method contains the body of the task and must return true if the execution succeeded.

It can offer properties which will be set by MSBuild from the attribute values in the task, before the call to Execute(). Only the properties marked with Required must necessarily be initialized.

Here is an example of a task named MyTouch which updates the timestamp of the files specified with the Files attribute (let us mention that such a task named Touch is offered by the MSBuild framework):

Note the use of the TaskLoggingHelper Task.Log{get;} which allows displaying information relating to the execution of the task. Our MyTouch task must be registered to all the MSBuild projects which may use it. This is done by using an element <UsingTask>. Here is such a script which updates the timestamps of the C# files in the current folder (the MyTask.dll assembly must be located in the C:\CustomTasks\ folder):

It is interesting to note that all standard tasks are declared by <UsingTask> elements located in the Microsoft.Common.Tasks file. This file is automatically and implicitly imported by msbuild.exe at each execution. By analyzing this file, we can see that the classes corresponding to the standard tasks are defined in the Microsoft.Build.Tasks.dll assembly. You can then access the code of these tasks using a tool such as Reflector.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

Share

About the Author

Patrick Smacchia is a .NET MVP involved in software development for over 15 years. He is the author of Practical .NET2 and C#2, a .NET book conceived from real world experience with 647 compilable code listings. After graduating in mathematics and computer science, he has worked on software in a variety of fields including stock exchange at Société Générale, airline ticket reservation system at Amadeus as well as a satellite base station at Alcatel. He's currently a software consultant and trainer on .NET technologies as well as the author of the freeware NDepend which provides numerous metrics and caveats on any compiled .NET application.

Very informative article. Thanks (appreciated). Quick question though. I have a Visual Studio add-in that needs to determine the name of the ".resources" file that's created for any arbitrary ".resx" file (in any arbitrary VS project). This is the name of the ".resources" file that's embedded in the satellite assembly. Presumably it has something to do with "CreateManifestResourceNames" (not sure). Do you have any idea how to pull this off? Have spent many hours searching for the answer with no luck. Thanks.

I'm new to using MSBuild and for the life of me I cannot figure out how to build a single project that is in a solution that has many projects. To give you an idea I have a solution with 30 separate projects, there is a class library project for every web service project so when I build I need to build the dll project that goes along with it's associated web service project. I want to create a script that I can run to build/deploy each web service individually but can not see to get this to work. Any thoughts on how to do this?

This is the most terse but clear article out there.
I believe the statement "If MSBuild detects that at least one of the input items is older than one of the output items, it will execute the target." (i.e., s/older/newer/)

I am starting off with modifying .proj files and using MSBuild. This article helped me a lot in getting the basics, but I was wondering if it is possible to run both the Debug and Release builds through the same .proj file, in case the configuration option is blank. One of the project solutions (.sln file) I am building is in Debug mode which is set from the VS, but I want to have the Release build along side the default Debug one?

Let's assume that we have a solution with only and only one project within. This project has a bunch of c sharp files and each c sharp file contains one class only. For i.e. class1.cs, class2.cs, class3.cs and class4.cs. In this schema class2.cs needs class4.cs and class3.cs needs class1.cs.

If we want to use CSC class1.cs and class4.cs must be compiled first. My question is that, is there any way to find out the sequence of building of each module (c sharp files) within a project? I know that if we supply all files names together to CSC, it's gonna be taken care of automatically. But I want a solid mechanism to be able to figure out the module dependencies within a C# project pro grammatically. thanks.