Friday 14 June 2013

Posted by Prasad KM | 10:57 Categories:

Msuild Properties

To be able to parameterize a build script, MSBuild has implemented properties. A property is a simple key/value type, which can be used from multiple locations in the scripts. Let’s look at an example using properties:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?xml version="1.0" encoding="utf-8" ?>
  <PropertyGroup>
    <MyReleaseOutput>.\release</MyReleaseOutput>
  </PropertyGroup>
  <Target Name="Build">
    <Message Text="Building msbuildintro" />
    <MSBuild Projects="msbuildintro.csproj" Targets="Build" />
  </Target>
  <Target Name="Release" DependsOnTargets="Build">
    <MakeDir Directories="$(MyReleaseOutput)" />
    <Copy SourceFiles=".\bin\debug\msbuildintro.exe" DestinationFolder="$(MyReleaseOutput)" />
  </Target>
</Project>
This example defines a property defined in a property group. Properties can be defined both outside and inside the scope of a target. When a property is defined as in this example, the value of the property is assigned before executing the actual targets. In this example, I define a property called MyReleaseOutput and add the value .\release. I have added two targets as well: Build and Release. The Build target is similar to the one specified in the previous example, while the Release target is new. The Release target introduces a new attribute called DependsOnTargets, which is the way to define dependencies between targets in MSBuild. In this case, we tell MSBuild to run the Build target before running the Release targets. If you run the Build target manually before running the Release target, the Build target is run only once.
The release target introduces two new tasks as well. MakeDir, which (well you guessed it) creates a new directory and Copy, which copies on or more files from A to B. MakeDir contains a single attribute, defining the path of the new directory.
In this example that path is the value of the MyReleaseOutput property. Notice the use of the $(propertyname) syntax here. $() is used to reference properties in MSBuild. The copy task in our example points out a single file and the destination folder where this file should be copied to when executing the Release target. The $(MyReleaseOutput) used is again replaced by the value of this property.

Items

The example above copied a single file from one directory to another. This can certainly be useful in many situations, but sometimes this is simply not flexible enough. This is where items come in. An item gives the possibility of creating dynamic lists of, for instance, file names. Let’s start by looking at an example:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?xml version="1.0" encoding="utf-8" ?>
  <PropertyGroup>
    <MyReleaseOutput>.\release</MyReleaseOutput>
  </PropertyGroup>
  <ItemGroup>
    <MyReleaseFiles Include=".\bin\debug\*.*" />
  </ItemGroup>
  <Target Name="Build">
    <Message Text="Building msbuildintro" />
    <MSBuild Projects="msbuildintro.csproj" Targets="Build" />
  </Target>
  <Target Name="Release" DependsOnTargets="Build">
    <MakeDir Directories="$(MyReleaseOutput)" />
    <Copy SourceFiles="@(MyReleaseFiles)" DestinationFolder="$(MyReleaseOutput)" />
  </Target>
</Project>
We start by defining an ItemGroup outer scope of a target. This means that the content is calculated before actually running any targets. In this example, I define an ItemGroup containing a single item called MyReleaseFiles. The item contains a single attribute called Include, which acts as a filter for the generated file list. In this case, all files beneath the bin\debug directory. I use this item in the copy task beneath the Release target to indicate which files should be copied when doing a release.
The Include filter decides which file to include. We also have the possibility to specify an Exclude filter. The following example shows how:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?xml version="1.0" encoding="utf-8" ?>
  <PropertyGroup>
    <MyReleaseOutput>.\release</MyReleaseOutput>
  </PropertyGroup>
  <ItemGroup>
    <MyReleaseFiles Include=".\bin\debug\*.*" Exclude=".\bin\debug\*vshost.exe" />
  </ItemGroup>
  <Target Name="Build">
    <Message Text="Building msbuildintro" />
    <MSBuild Projects="msbuildintro.csproj" Targets="Build" />
  </Target>
  <Target Name="Release" DependsOnTargets="Build">
    <MakeDir Directories="$(MyReleaseOutput)" />
    <Copy SourceFiles="@(MyReleaseFiles)" DestinationFolder="$(MyReleaseOutput)" />
  </Target>
</Project>
I added an Exlude attribute to my MyReleaseFiles item. The exclude in this example excludes all files beneath the bin\debug directory which end in vshost.exe. An item containing both Include and Exclude will be generated by taking all the files specified in the Include and subtracting the files specified in the Exlude.
The last two examples of using items are actually not that useful because the content for the MyReleaseFiles item is generated before running the actual targets. On a new checkout or after a clean, no files exist in the bin\debug directory meaning that the generated file list will therefore be completely empty. Bummer! Let us fix the example. We define a new item inside the scope of a target instead:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?xml version="1.0" encoding="utf-8" ?>
  <PropertyGroup>
    <MyReleaseOutput>.\release</MyReleaseOutput>
  </PropertyGroup>
  <Target Name="Build">
    <Message Text="Building msbuildintro" />
    <MSBuild Projects="msbuildintro.csproj" Targets="Build" />
  </Target>
  <Target Name="Release" DependsOnTargets="Build">
    <MakeDir Directories="$(MyReleaseOutput)" />
    <CreateItem Include=".\bin\debug\*.*" Exclude=".\bin\debug\*vshost.exe">
      <Output TaskParameter="Include" ItemName="MyReleaseFiles"/>
    </CreateItem>
    <Copy SourceFiles="@(MyReleaseFiles)" DestinationFolder="$(MyReleaseOutput)" />
  </Target>
</Project>
I moved the MyReleaseOutput item inside the Release target. This is done using the CreateItem task. The CreateItem task creates a new item on the fly which means that the content is generated at the point in time when the CreateItem task is executed. Notice that the CreateItem task contains an Output element. The Output element is used in a lot of different places in MSBuild where a target is able to output some data. In this case, it uses the ItemName attribute to define the name from the previous example.
Anyone still reading? If you have read this far, you deserve a little prize:


dilbert2002444471010.gif

0 comments:

  • RSS
  • Delicious
  • Digg
  • Facebook
  • Twitter
  • Linkedin
  • Youtube