I have a list of projects in my MSBuild file:
<ItemGroup>
<SubProject Include="**\*.csproj" />
</ItemGroup>
And now, I would like to set, on each project, its TargetPath
in a metadata property for each project.
I already know how to extract the target path for each project, and put it on a separate items list:
<Target Name="ExtractTargetPaths">
<MSBuild Projects="%(SubProject.Identity)" Targets="GetTargetPath">
<Output TaskParameter="TargetOutputs" ItemName="SubProjectTargetPath" />
</MSBuild>
</Target>
However, I would like to be able to access that "SubProjectTargetPath" as metadata on the SubProject
items instead of having a separate list of items.
That is, instead of writing e.g. this:
<SomeTask Parameter="%(SubProjectTargetPath.Identity)" />
I would be able to write something like:
<SomeTask Parameter="%(SubProject.TargetPath)" />
OK, I have found one solution, which is to use target batching, with a temporary property:
<ItemGroup>
<SubProject Include="**\*.csproj" />
</ItemGroup>
<Target Name="UpdateSubProjectMetadata" Outputs="%(SubProject.Identity)">
<!-- Retrieves the Target DLL path and puts it in the temporary property "_TempTargetPath" -->
<MSBuild Projects="%(SubProject.Identity)" Targets="GetTargetPath">
<Output TaskParameter="TargetOutputs" PropertyName="_TempTargetPath" />
</MSBuild>
<!-- Set the metadata item for TestProject to the value of the temporary property -->
<ItemGroup>
<SubProject Condition="'%(SubProject.Identity)' == '%(Identity)'" >
<TargetPath>$(_TempTargetPath)</TargetPath>
</SubProject>
</ItemGroup>
<!-- Clear the temporary property -->
<PropertyGroup>
<_TempTargetPath></_TempTargetPath>
</PropertyGroup>
</Target>
Once that target has run, TargetPath is available on every metadata item.
Implementation note: The above code is only tested for MSBuild 4.0 - I think it works as is on MSBuild 3.5, and users of previous versions would use the <CreateItem>
and <CreateProperty>
tasks instead of putting <PropertyGroup>
and <ItemGroup>
.