Msbuild: Exclude patterns behaving different in static evaluation and at runtime

Created on 31 Aug 2017  ยท  4Comments  ยท  Source: dotnet/msbuild

Following up on https://stackoverflow.com/questions/45964967/msbuild-itemgroup-exclude-doesnt-work-with-wildcards

Exclude patterns behave different at runtime than during static evaluation. For example:

<Project>
    <ItemGroup>
        <SourcItem Include="..\..\References\AnotherFolder\ReferencedAssembly.dll" />
        <SourcItem Include="bin\GeneratedAssembly1.dll" />
        <SourcItem Include="bin\GeneratedAssembly2.dll" />
        <SourcItem Include="somefolder\somefile.txt" />
        <SourcItem Include="somefolder\somefile.exe" />
        <SourcItem Include="bin\anexe.exe" />
    </ItemGroup>

    <ItemGroup>
      <StaticallyFilteredItem Include="@(SourcItem)" Exclude="..\..\References\**\*" />
    </ItemGroup>

    <Target Name="Build">
      <ItemGroup>
        <TargetFilteredItem Include="@(SourcItem)" Exclude="..\..\References\**\*" />
      </ItemGroup>
      <Message Importance="high" Text="StaticallyFilteredItem: %(StaticallyFilteredItem.Identity)" />
      <Message Importance="high" Text="TargetFilteredItem: %(TargetFilteredItem.Identity)" />
    </Target>
</Project>

produces:

$ dotnet msbuild
Microsoft (R) Build Engine version 15.3.409.57025 for .NET Core
Copyright (C) Microsoft Corporation. All rights reserved.

  StaticallyFilteredItem: bin/GeneratedAssembly1.dll
  StaticallyFilteredItem: bin/GeneratedAssembly2.dll
  StaticallyFilteredItem: somefolder/somefile.txt
  StaticallyFilteredItem: somefolder/somefile.exe
  StaticallyFilteredItem: bin/anexe.exe
  TargetFilteredItem: ../../References/AnotherFolder/ReferencedAssembly.dll
  TargetFilteredItem: bin/GeneratedAssembly1.dll
  TargetFilteredItem: bin/GeneratedAssembly2.dll
  TargetFilteredItem: somefolder/somefile.txt
  TargetFilteredItem: somefolder/somefile.exe
  TargetFilteredItem: bin/anexe.exe

Is this by design and a desired behaviour or a bug?

Feature - Globbing bug

Most helpful comment

Added this to the larger saga of unifying the two item evaluation clones: #1124 . The correct fix is to unify the cloned item evaluation code between static items and dynamic items.
I am going to mark it for dev16 for visibility, but there's a chance we won't get to it. :(

All 4 comments

I compared latest msbuild with msbuild that shipped with vs2015. Old msbuild only excluded the relative files if the files exist, but doesn't if the files do not exist. Latest msbuild has the old behaviour for target items, but static items exclude the file regardless whether it exists or not.

Simplified test project:

<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
    <ItemGroup>
        <SourcItem Include="..\a\b.cs" />
    </ItemGroup>

    <ItemGroup>
      <StaticallyFilteredItem Include="@(SourcItem)" Exclude="..\a\**" />
    </ItemGroup>

    <Target Name="Build">
      <ItemGroup>
        <TargetFilteredItem Include="@(SourcItem)" Exclude="..\a\**" />
      </ItemGroup>
      <Message Importance="high" Text="StaticallyFilteredItem: %(StaticallyFilteredItem.Identity)" />
      <Message Importance="high" Text="TargetFilteredItem: %(TargetFilteredItem.Identity)" />
    </Target>
</Project>

When the file exists:

E:.
โ”‚
โ”œโ”€โ”€โ”€a
โ”‚       b.cs
โ”‚
โ””โ”€โ”€โ”€sub
        build.proj

msbuild sub\build.proj /clp:v=m
Microsoft (R) Build Engine version 14.0.25420.1
Copyright (C) Microsoft Corporation. All rights reserved.

  StaticallyFilteredItem:
  TargetFilteredItem:

E:\projects\tests\projects\play>e:\projects\msbuild_2\bin\Bootstrap\MSBuild\15.0\Bin\MSBuild.exe sub\build.proj /clp:v=m
Microsoft (R) Build Engine version 15.5.165.8245 for .NET Framework
Copyright (C) Microsoft Corporation. All rights reserved.

  StaticallyFilteredItem:
  TargetFilteredItem:

When the file does not exist:

E:.
โ”‚
โ”œโ”€โ”€โ”€a
โ”‚       c.cs
โ”‚
โ””โ”€โ”€โ”€sub
        build.proj

msbuild sub\build.proj /clp:v=m
Microsoft (R) Build Engine version 14.0.25420.1
Copyright (C) Microsoft Corporation. All rights reserved.

  StaticallyFilteredItem: ..\a\b.cs
  TargetFilteredItem: ..\a\b.cs

e:\projects\msbuild_2\bin\Bootstrap\MSBuild\15.0\Bin\MSBuild.exe sub\build.proj /clp:v=m
Microsoft (R) Build Engine version 15.5.165.8245 for .NET Framework
Copyright (C) Microsoft Corporation. All rights reserved.

  StaticallyFilteredItem:
  TargetFilteredItem: ..\a\b.cs

Personally I think that relative excludes should work, regardless if the files exist or not. I am going to mark this as a bug, where static items are doing the right thing now, but target items still need to be fixed.

@cdmihai any chance to address this in 16.0 or do you want to close it as "we'll just need to live with the difference"?

Added this to the larger saga of unifying the two item evaluation clones: #1124 . The correct fix is to unify the cloned item evaluation code between static items and dynamic items.
I am going to mark it for dev16 for visibility, but there's a chance we won't get to it. :(

I've been affected this... So, how long until MSBuild 16.0 lands?

Also, Exclude is pretty poorly documented(!), so discovering it doesn't work as intended is not so surprising..
I have an example here in the docs issue I raised that also demonstates this issue with static vs. runtime:
#2780

Was this page helpful?
0 / 5 - 0 ratings

Related issues

rainersigwald picture rainersigwald  ยท  3Comments

jaredpar picture jaredpar  ยท  4Comments

ghost picture ghost  ยท  4Comments

justintoth picture justintoth  ยท  3Comments

Chopping picture Chopping  ยท  4Comments