msbuildmsbuild-itemgroup

Import element does not expand ItemGroup correctly


I'm trying to populate an ItemGroup with directory basenames, pass it through a transform to create absolute paths from them and import the files residing there. It works flawlessly in a Message element, but fails to do anything in an Import. What am I missing?

<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
    <ItemGroup>
        <MyDependencies Include="Dir1" />
        <MyDependencies Include="Dir2" />
    </ItemGroup>

    <!-- "Expansion: C:\path\Dir1\import.targets;C:\some\path\Dir2\import.targets" -->
    <Target Name="TestMessage" BeforeTargets="PrepareForBuild">
        <Message
            Importance="High"
            Text="Expansion: @(MyDependencies -> 'C:\path\%(Identity)\import.targets')"
        />
    </Target>

<!-- Uncomment to trigger error -->
<!--<Import Project="@(MyDependencies -> 'C:\path\%(Identity)\import.targets')" />-->
</Project>

The Import's path remains unexpanded and leads to:

error MSB4102: The value "@(MyDependencies -> 'C:\path\%(Identity)\import.targets')" of the "Project" attribute in element <Import> is invalid. Illegal characters in path.

Solution

  • This happens because the ItemGroup gets evaluated after Import only. See https://learn.microsoft.com/en-us/visualstudio/msbuild/comparing-properties-and-items?view=vs-2022#property-and-item-evaluation-order:

    During the evaluation phase of a build, imported files are incorporated into the build in the order in which they appear. Properties and items are defined in three passes in the following order:

    In other words an Import is almost the same as copy-pasting the content of the file at the location of that import, and only after that MSBuild begins to evaluate properties and items.