MSBuild
References
- Overview
- Reference
- Task Reference
- Open Source Build Tasks
- Reserved Properties
- Well-known Item Metadata
- Incremental Builds
- Transforms
Tools
- Visualization in MSBuild Sidekick v2
- Debugger
- WiX helper tool and WiX itself
- PackageThis would be useful if you wanted to build an offline version of the MSBuild MSDN documentation.
- MSBuild Extension Pack which includes 170 tasks!!
Overview
Running MSBuild Projects
Here’s how to run an MSBuild script :
MSBuild.exe filename.proj /property:PropertyName=Value
Of course, you can always use /p: instead of /property:.
Projects
The Project element is the root element in any MSBuild project file. InitialTargets are executed before the DefaultTargets or the specified target is executed.
<Project
DefaultTargets="Compile"
InitialTargets="Clean;Compile"
xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<!-- Import the contents of another project file -->
<Import Project="..." />
<!-- ProjectExtensions data is ignored by MSBuild -->
<ProjectExtensions>...</ProjectExtensions>
<PropertyGroup>
<PropertyName>PropertyValue</PropertyName>
</PropertyGroup>
<ItemGroup>
</ItemGroup>
<!-- PropertyGroup and ItemGroup elements can be nested
inside a Choose element to provide different sets
of data based on certain conditions. -->
<Choose>
<When Condition="..."></When>
<Otherwise></Otherwise>
</Choose>
<Target Name="..."
DependsOnTargets="...;...;..."
Inputs="..."
Outputs="..." >
<!-- Tasks must appear as a child of a Target -->
<aTaskName Parameter="...">
<!-- Retrieve the output of a Task using the
Output element. Specify either PropertyName
or ItemName -->
<Output TaskParameter="Name of the Task output parameter"
PropertyName="Name of property to store output in"
Condition="..." />
</aTaskName>
<!-- If ContinueOnError is false for a failed task, the OnError
tasks are executed. There can be zero or more OnError elements
and must be the last elements in the Target. -->
<OnError/>
</Target>
<!-- Maps the task referenced in a Task element to the assembly
containing the implementation. Can specify AssemblyFile instead
of AssemblyName -->
<UsingTask TaskName="..." AssemblyName="..." />
</Project>
Items and Collections
Define a user-named collection of items by placing them in an ItemGroup then reference the collection with @(ItemCollectionName). The @() syntax can also include a separator used to build a string so, for example, the Exec task below builds a command with parameters /c:first /c:second /c:third using the _@(Phrase, ‘ /c:’) _syntax.
<Exec Command="findstr /i /c:@(Phrase, ' /c:') phrases.txt"/>
Items can contain metadata and accessed using the %(ItemMetadata) syntax. Well-know Item Metadata contains a list of metadata items already defined for filenames. This allows for an expansion like :
<Exec Command="demo.exe /name:%(filename) @(filesToProcess)"/>
Wildcards can be used to specify more than one file and from sub-directories. For example Images***.jpg specifies all jpg files found beneath all sub-directories of the Images folder.
<ItemGroup>
<Compile Include = "file1.cs" />
<Compile Include = "file2.cs" />
<Compile Include = "file3.cs;file4.cs" Exclude = "file5.cs" />
<Compile Include = "file6.cs" >
<!-- Meta data can be added to an item by placing it
beneath the item element itself. -->
<Culture>En</Culture>
</ItemName>
</ItemGroup>
Transforms can be used to perform a one-to-one conversion of one item collection into another and appear in the format _$(
_@(RESXFile -> '%(filename).resources')_
Another example that creates new filenames under a different folder and having a comma separator:
_@(RESXFile -> 'Toolset\%(filename)%(extension)', ',')_
Properties
Properties are added to PropertyGroup then referenced with _$(PropertyName). _There are also a number of reserved properties and the contents of a property can be xml which itself can contain properties that must be defined beforehand.
<PropertyGroup>
<BuildDir>Build</BuildDir>
</PropertyGroup>
Environment variables can be referenced by simply using the name of a variable using the property syntax such as $(PATH). If there’s a possibility that the variable may not exist then a default can be set using a condition such as :
<ToolsPath Condition="'$(TOOLSPATH)' == ''">c:\tools</ToolsPath>
Registry entries can be read using the syntax $(HKEY_LOCAL_MACHINE\ \KeyName\KeyName\@Value) or remove @Value for the default value.
Targets
Targets group and order tasks and define entry points into the build process. See the Tasks section for an example.
Targets can also be used to perform incremental builds such that a target will only execute if a set of input files are older that a set of output files. This works best when there is a one-to-one mapping, but where there’s a many-to-one mapping, the single output file will depend on the newest date stamp in the input file collection. Here’s how to specify this :
<Target Name="Build" Inputs="@(InputFiles)" Outputs="app.exe">
<Csc Sources="@(InputFiles)" OutputAssembly="app.exe" />
</Target>
Of particular use are the transforms described in the Items and Collections section above. For example:
<Target Name="CopyOutputs"
Inputs="@(BuiltAssemblies)"
Outputs="@(BuiltAssemblies -> '$(OutputPath)%(Filename)%(Extension)')">
<Copy SourceFiles="@(BuiltAssemblies)" DestinationFolder="$(OutputPath)"/>
</Target>
Batching Targets
Batching can be used in conjunction with the Inputs and Outputs attributes of the Target element in order to skip up-to-date batches. For example, the following example shows that the %(Culture) metadata reference in the Outputs attribute batches the @(Res) item collection based on the Culture metadata. This means that only those satellite assemblies that are out-of-date will be re-built.
<Project
xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Res Include="Strings.fr.resources">
<Culture>fr</Culture>
</Res>
<Res Include="Strings.jp.resources">
<Culture>jp</Culture>
</Res>
<Res Include="Menus.fr.resources">
<Culture>fr</Culture>
</Res>
<Res Include="Dialogs.fr.resources">
<Culture>fr</Culture>
</Res>
<Res Include="Dialogs.jp.resources">
<Culture>jp</Culture>
</Res>
<Res Include="Menus.jp.resources">
<Culture>jp</Culture>
</Res>
</ItemGroup>
<Target Name="Build"
Inputs="@(Res)"
Outputs="%(Culture)\MyApp.resources.dll">
<AL Resources="@(Res)"
TargetType="library"
OutputAssembly="%(Culture)\MyApp.resources.dll"
</Target>
</Project>
Incremental Builds
If inputs to a build haven’t changed compared with the ouputs they generate then there’s no point in running that task. To cater for this those input and outputs can be specified on a Target which will automatically be skipped:
<Target Name="Build" Inputs="@(InputFiles)" Outputs="AnOutput.dll">
This technique can also be combined with Transforms to give a one-to-one dependency mapping which means the Target will only be run for just the change files:
<Target Name="CopyOutputs" Inputs="@(SourceFiles)" Outputs="@(SourceFiles -> '$(OutputPath)%(Filename)%(Extension)')">
However, all outputs are passed on to dependent tasks even if only a portion had changed. In the following example the GenerateContentFiles may only process a subset of the files but the Build target will still receive them all.
<Project DefaultTargets="Build"
xmlns="http://schemas.microsoft.com/developer/msbuild/2003" >
<ItemGroup>
<TXTFile Include="*.txt"/>
<XMLFiles Include="\metadata\*.xml"/>
</ItemGroup>
<Target Name = "Convert"
Inputs="@(TXTFile)"
Outputs="@(TXTFile->'%(Filename).content')">
<GenerateContentFiles
Sources = "@(TXTFile)">
<Output TaskParameter = "OutputContentFiles"
ItemName = "ContentFiles"/>
</GenerateContentFiles>
</Target>
<Target Name = "Build" DependsOnTargets = "Convert"
Inputs="@(ContentFiles);@(XMLFiles)"
Outputs="$(MSBuildProjectName).help">
<BuildHelp
ContentFiles = "@(ContentFiles)"
MetadataFiles = "@(XMLFiles)"
OutputFileName = "$(MSBuildProjectName).help"/>
</Target>
</Project>
Tasks
Tasks are written in managed code, that implements the ITask interface, then mapped to MSBuild with a UsingTask element.
<Target Name="aTargetName" DependOnTargets="TargetName;TargetName">
<TaskName Parameter="$(PropertyName)" />
</Target>
If you want to ignore any errors that a task may raise then call it with the ContinueOnError attribute set:
<Delete Files="@(Files)" ContinueOnError="true"/>
There’s a table at the end of this document that highlights the list of standard tasks available.
Batching Tasks
Batching divides an item collection based on item metadata and passes each batch to a task separately. The following example highlights how the presence of %(ExampColl.Number), a metadata reference, informs MSBuild to group by the Number metadata and execute the task for each batch. _For each execution of the task @(ExampColl) _will contain each group and not the entire collection.
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<ExampColl Include="Item1">
<Number>1</Number>
</ExampColl>
<ExampColl Include="Item2">
<Number>2</Number>
</ExampColl>
<ExampColl Include="Item3">
<Number>3</Number>
</ExampColl>
<ExampColl Include="Item4">
<Number>1</Number>
</ExampColl>
<ExampColl Include="Item5">
<Number>2</Number>
</ExampColl>
<ExampColl Include="Item6">
<Number>3</Number>
</ExampColl>
</ItemGroup>
<Target Name="ShowMessage">
<Message Text = "Number: %(ExampColl.Number) -- Items in ExampColl: @(ExampColl)"/>
</Target>
</Project>
This example can be further extended to have two _ItemGroup_s, ExampColl1 and ExampColl2, and a metadata reference of _%(Number). _This will batch each collection based on the same metadata item.
The %(Identity) metadata references a built-in item that, since it’s a unique value for each item in a collection, can be used to batch individually.
Writing a Task
A task can be written by either:
- Implementing the ITask interface.
- Deriving from the helper class Task defined in Microsoft.Build.Utilities.dll.
An Execute method must be implemented and properties can be created that MSBuild will set immediately before calling Execute. For example:
using System;
using Microsoft.Build.Framework;
using Microsoft.Build.Utilities;
namespace MyTasks
{
public class SimpleTask : Task
{
public override bool Execute()
{
return true;
}
private string myProperty;
public string MyProperty
{
get { return myProperty; }
set { myProperty = value; }
}
}
}
Logging
Logging, by default, is sent to the console and can be turned off with a /noconsolelogger command line switch. MSBuild also supports a file logger by specify the /l switch as shown below:
_/logger:FileLogger,Microsoft.Build.Engine;logfile=MyLog.log;append=true;verbosity=diagnostic;encoding=utf-8_
This example highlights the logger switch and the ability to write a custom logger by implementing the ILogger interface. There’s a ‘How to’ on MSDN.
Standard Tasks
Task Name | Description |
AL | Assembly Linker which creates an assembly with a manifest from one or more modules or resource files. |
AspNetCompiler | Wraps aspnet_compiler.exe. |
AssignCulture | If provided a list of filenames with a Culture identifier embedded in the name, then it will assign the metaData Culture to it. |
CallTarget | Invokes a specified target. |
Copy | Copies files to a destination folder, or copies and renames if a list of destination files is specified with a one-to-one relationship with the source files. |
CreateItem | Allows a new list to be created from another whilst also be filtered and new metadata being added. |
CreateProperty | Creates a new property using the passed value. Use an embedded Output task to create a named property. |
Csc | Compiles C#. |
Delete | Deletes a list of files. |
Error | Stops the build and logs an error based on an evaluated conditional statement. |
Exec | Runs a specified program with the specified arguments. |
FindUnderPath | Discovers whether a list of files exist beneath a specified path. |
GenerateApplicationManifest | Generates a ClickOnce application manifest or a native manifest. |
GenerateBootstrapper | Provides an automated way to detect, download, and install an application and its prerequisites. |
GenerateResource | Converts between .txt and .resx (XML-based resource format) files and common language runtime binary .resources files that can be embedded in a runtime binary executable or compiled into satellite assemblies. This task is typically used to convert .txt or .resx files to .resource files. The GenerateResource task is functionally similar to resgen.exe. |
GetAssemblyIdentity | Retrieves the assembly identities from the specified files and outputs the identity information. |
GetFrameworkPath | Retrieves the path to the .NET Framework assemblies. If several versions of the .NET Framework are installed, this task returns the version that MSBuild is designed to run on. |
GetFrameworkSdkPath | Retrieves the path to the Windows Software Development Kit (SDK). |
LC | Wraps LC.exe, which generates a .license file from a .licx file. For more information on LC.exe, see License Compiler (Lc.exe). |
MakeDir | Creates directories and, if necessary, any parent directories. |
Message | Logs a message during a build. |
MSBuild | Builds MSBuild projects from another MSBuild project. Unlike using the Exec Task to start MSBuild.exe, this task uses the same MSBuild process to build the child projects. |
ReadLinesFromFile | Reads a list of items from a text file. |
RegisterAssembly | Reads the metadata within the specified assembly and adds the necessary entries to the registry, which allows COM clients to create .NET Framework classes transparently. The behavior of this task is similar, but not identical, to that of the Assembly Registration Tool (Regasm.exe). |
RemoveDir | Removes the specified directories and all of its files and subdirectories. |
ResGen | Use the <a'http://msdn2.microsoft.com/en-us/library/ms164295.aspx'>GenerateResource Task</a> task to convert .txt and .resx files to and from common language runtime binary .resources files. |
ResolveAssemblyReference | Determines all assemblies that depend on the specified assemblies, including second and nth-order dependencies. |
ResolveComReference | Takes a list of one or more type library names or .tlb files and resolves those type libraries to locations on disk. |
ResolveKeySource | Determines the strong name key source. |
ResolveNativeReference | Resolves native references. |
SGen | Creates an XML serialization assembly for types in the specified assembly. This task wraps the XML Serializer Generator Tool (Sgen.exe). For more information, see XML Serializer Generator Tool (Sgen.exe. |
SignFile | Signs the specified file using the specified certificate. |
Touch | Sets the access and modification times of files. |
UnregisterAssembly | Unregisters the specified assemblies for COM interop purposes. Performs the reverse of the RegisterAssembly task. |
Vbc | Wraps vbc.exe, which produces executables (.exe), dynamic-link libraries (.dll), or code modules (.netmodule). For more information on vbc.exe, see Visual Basic Compiler. |
VCBuild | Wraps vcbuild.exe, which builds Visual C++ projects and solutions which contain Visual C++ projects. For more information, see VCBUILD Reference. |
Warning | Logs a warning during a build based on an evaluated conditional statement. |
WriteLinesToFile | Writes the paths of the specified items to the specified text file. |
Conditions
A table lifted straight from the MSDN docs…
Condition | Description |
'stringA' == 'stringB' | Evaluates to true if stringA equals stringB. For example: Condition="'$(CONFIG)'=='DEBUG'" Single quotes are not required for simple alphanumeric strings or boolean values. However, single quotes are required for empty values. |
'stringA' != 'stringB' | Evaluates to true if stringA is not equal to stringB. For example: Condition="'$(CONFIG)'!='DEBUG'" Single quotes are not required for simple alphanumeric strings or boolean values. However, single quotes are required for empty values. |
<,>, <=,>= | Evaluates the numeric values of the operands. Returns true if the relational evaluation is true. Operands must evaluate to a decimal or hexadecimal number. Hexadecimal numbers must begin with "0x". Note: In XML, the characters < and> must be escaped. The symbol < is represented as <. The symbol> is represented as >. |
Exists('stringA') | Evaluates to true if a file or folder with the name stringA exists. For example: Condition="!Exists('$(builtdir)')" Single quotes are not required for simple alphanumeric strings or boolean values. However, single quotes are required for empty values. |
HasTrailingSlash('stringA') | Evaluates to true if the specified string contains either a trailing backward slash (\) or forward slash (/) character. For example: Condition="!HasTrailingSlash('$(OutputPath)')" Single quotes are not required for simple alphanumeric strings or boolean values. However, single quotes are required for empty values. |
! | Evaluates to true if the operand evaluates to false. |
And | Evaluates to true if both operands evaluate to true. |
Or | Evaluates to true if at least one of the operands evaluates to true. |
() | Grouping mechanism that evaluates to true if expressions contained inside evaluate to true. |