IT:AD:MSbuild:HowTo:Project Syntax/Properties and Arrays
References:
Summary
Continuing on the basis demonstrated earlier (IT:AD:MSbuild:HowTo:Project Syntax Intro), here are some examples of Conditional Flow Control in a MSBuild Build Project file.
Notes
Static versus Dyamic
Properties that are defined outside of a Target
are static.
Dynamic properties are defined with a Target
.
Scalar Properties
All scripts have global properties of some kind, defined within PropertyGroup
tags:
<?xml version="1.0" encoding="utf-8"?> <Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <PropertyGroup> <MyProperty>Hello</MyProperty> <MyOtherProperty>World</MyOtherProperty> </PropertyGroup> <PropertyGroup> <MyOtherProperty>Sky</MyOtherProperty> </PropertyGroup> </Project>
These properties are just embedded defaults – and anyone can be overridden by command line switches:
MsBuild.exe /p:MyProperty="Bonjour"
Notice how the switch ends with ':' and the property pairs are separated by '='
Second Parse Overrides the First Value
If you define the property twice, normally the second one parsed crushes the first.
This means that the value of MyOtherProperty
is Sky
Tip: That is, until we introduce Conditions where we get a lot more control over what value is used.
Self Referenceing
If you define the property twice, normally the second one parsed crushes the first.
But there is a case for when you want to reference and reuse the previous value:
<MyVar>Some new Suff that references $(MyVar)]</MyVar>
Arrays of Properties
In addition to Scalar properties, Arrays can be defined:
<?xml version="1.0" encoding="utf-8"?> <Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <ItemGroup> <!-- Note: this is an Array of Items/Properties - not a Dictionary, so the NodeName is the name of the Array to which the Include is added as a Value (note: not a key) And you can therefore work on two arrays in the same ItemGroup --> <MyArray Include="MyProperty" /> <MyArray Include="MySecondProperty"> <PropertyOne>X</PropertyOne> <PropertyTwo>Y</PropertyTwo> </MyArray> <!-- Note how within one ItemGroup the syntax allows you to handle adding items to more than one array at a time --> <MySecondArrayIsAnArrayOfFiles Include="$(MSBuildThisFileDirectory)*.*"/> <MyArray Include="MyThirdProperty" /> <MyThirdArray Include="PropA"> <X>12</X> <Y>34</Y> </MyThirdArray> <MyThirdArray Include="PropB"> <X>56</X> <Y>78</Y> </MyThirdArray> </ItemGroup> </Project>
Note: ItemGroups have extended support when dealing with referencing files -- as demonstrated above by `MySecondIsAnArrayOfFiles` which is importing a whole group of File objects. We'll come back to the $(MSBuildThisFileDirectory) Well Known Parameter in a moment.
In fact, a *.csproj file is made up of a whole bunch of ItemGroup
elements:
<ItemGroup> <!-- Include some (excluding others), adding them to an array called CodeFiles --> <sxhFiles Include="**\*.cs" Exclude="**\generated\*.cs" /> <!-- Include a specific file, adding it to an array called Reference --> <Reference Include="NUnit.dll" /> <!-- Include some files, adding them to an array called Compile --> <Compile Include="UnitTesting\*.cs" Condition="$(Configuration)=='Debug'" /> etc.
When you see it explained like that, suddenly your average `*.csproj` begins to make a lot more sense!
Dealing with Individual Array Items
As you saw, the output of a whole array was clumped up into a string. Not very helpful:
Z:\Dropbox\Code\Spikes\MSBuild.MyProj Study\MyProj.proj;Z:\Dropbox\Code\Spikes\MSBuild.MyProj Study\readme.txt
If you want to work on each element in the Array, you need the .Identity
property:
<Target Name="MyTarget" DependsOnTargets="MyOtherTarget"> <Message Text="!!!"/> <!-- <Copy SourceFiles="c:\test.txt" DestinationFolder="d:\" /> --> <!-- Output of ItemGroup (ie, Arrays) is done using a @(...) instead of a $(...) --> <Message Text="@(MyArray)"/> <Message Text="@(MySecondArrayIsAnArrayOfFiles)"/> <Message Text="%(MySecondArrayIsAnArrayOfFiles.Identity)"/> </Target>
Note: notice that in the case of addressing object within an item array we use not $(), nor @(), but %()
Iterating through Arrays
Based on what was already covered in IT:AD:MSbuild:HowTo:Project Syntax Intro we can understand how the following
- Adds two files to an array called Stuff, each
Item
of which contains aMetadata
called Display - The Target called Batching displays the whole Array's contents whose individual items are marked with Display == true.
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <ItemGroup> <Stuff Include="One.cs" > <Display>false</Display> </Stuff> <Stuff Include="Two.cs"> <Display>true</Display> </Stuff> </ItemGroup> <Target Name="Batching"> <Message Text="@(Stuff)" Condition=" '%(Display)' == 'true' "/> </Target> </Project>
Resources
- Referencing Metadata: http://msdn.microsoft.com/en-us/library/ms171453.aspx#BKMK_ReferencingItemMetadata