.netmsbuildmsbuild-task

Add MSBuild batched task output as item metadata


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)" />

Solution

  • 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>.