Jul 16 2009

MSBuild crash course Part 1

Category: zvolkov @ 18:29

Much water has flown away since my first post on MsBuild and I picked up a book by MsPress called "Inside the MSBuild". In this post I will summarize what I see in this book, as I read it. The result should be a crash-course on MSBuild that you, dear reader, should hopefully find useful.

Empty MSBuild file:

<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
</Project>

to run it, launch msbuild ourbuildscript.proj from command line.

Properties:

<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
    <PropertyGroup>
        <NameOfProperty>ValueOfProperty</NameOfProperty>
        <AnotherProperty>Value1</AnotherProperty>
        <YetAnotherProperty>Value1</YetAnotherProperty>
    </PropertyGroup>
    <PropertyGroup>
        <YetAnotherProperty>Value2</YetAnotherProperty>
    </PropertyGroup>
</Project>

This defines 3 properties. Since YetAnotherProperty is specified twice, its second value will overwrite the first. This is because all properties are evaluated sequentially.

Targets:

<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" DefaultTargets="Foo">
    <Target Name="Blah" DependsOnTargets="Foo">
        <Message Text="String that will be printed to log file"/>
        <Copy SourceFiles="c:\test.txt" DestinationFolder="d:\" />
    </Target>
    <Target Name="Foo">
        <Message Text="Hello $(YetAnotherProperty) !!!"/>
    </Target>
    <PropertyGroup>
        <YetAnotherProperty>Value2</YetAnotherProperty>
    </PropertyGroup>
</Project>

The default target in our build script is Foo and that's what msbuild will execute unless you explicitely specify which target to run: msbuild ourbuildscript.proj /t:Blah.
In this case since Blah depends on Foo, msbuild will first execute Foo and then Blah. Foo will print "Hello Value2 !!!".

Conditions:

<PropertyGroup>
    <SomeProperty Condition="'$(AnotherProperty) == '1'">2</SomeProperty>
</PropertyGroup>

SomeProperty will get value of 2 only if AnotherProperty is 1. This is not the case unless something sets AnotherProperty. For example via command line parameter: msbuild ourbuildscript.proj /p:AnotherProperty=1.

Items are arrays of objects:

<ItemGroup>
    <SomeArray Include="FirstElementOfSomeArray" />
    <SomeArray Include="SecondElement" >
        <PropertyOne>X</PropertyOne>
        <PropertyTwo>Y</PropertyOne>
    </SomeArray>
</ItemGroup>

Just like Properties, items can be arguments to tasks (note how array references use @ instead of $):

<Target Name="Blah">
    <Message Text="@(SomeArray)"/>
</Target>

The above prints "FirstElementOfSomeArray;SecondElement" (this is how array is converted to String, which is what Message.Text takes)

Items have special support for files. This defines two arrays and fills them with actual file names from C: drive:

<ItemGroup>
    <ArrayOfFiles Include="C:\*.cs" />
    <ArrayOfFiles Include="C:\*.vb" />
    <AnotherArray Include="C:\Temp\**\*.*" />
</ItemGroup>

The list of files can now be used as argument for Copy task:

<Target Name="Blah">
    <Copy SourceFiles="@(ArrayOfFiles)" DestinationFolder="d:\" />
</Target>

Batching

To execute a task once for each item in the array use special batching syntaxis (the % and the .Identity):

<Target Name="Blah">
    <Message Text="%(SomeArray.Identity)"/>
</Target>

To execute entire target once for each item in the array use Outputs attribute like so:

<Target Name="Blah" Outputs="%(ArrayOfFiles.Identity)">
    <Message Text="File @(ArrayOfFiles) was created on @(ArrayOfFiles->'%(CreatedTime)' )"/>
</Target>

The above also shows how to access properties of items (ArrayOfFiles.CreatedTime).
The expression in %() does not have to be .Identity, it can be any other property of the Item, in this case msbuild will group all elements of the array by the property and process each group as a batch. You can even group by multiple properties if you specify multiple %() expressions as arguments to a task or a target.

Importing

<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
    <Import Project="anotherbuildscript.proj" />
</Project>

Sequence of events during build file processing:

  1. Set built-in properties and load environment variables into properties
  2. Read the build script, evaluating properties and items and loading imported files recursively. Only static PropertyGroups/ItemGroups (at the root level of each file) are evaluated at this time.
  3. Execute targets, either the default one, or the one specified on command line, recursively executing its dependencies
  4. For each target, execute the steps inside the target sequentially, evaluating target's properties and items

This concludes Part 1. To be continued.

Tags:

Comments

Comments are closed