it:ad:msbuild:howto:project_syntax_properties_and_arrays

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.

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!

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 %()

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 a Metadata 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>

  • /home/skysigal/public_html/data/pages/it/ad/msbuild/howto/project_syntax_properties_and_arrays.txt
  • Last modified: 2023/11/04 22:59
  • by 127.0.0.1