dotnet / roslyn

The Roslyn .NET compiler provides C# and Visual Basic languages with rich code analysis APIs.
https://docs.microsoft.com/dotnet/csharp/roslyn-sdk/
MIT License
19.07k stars 4.04k forks source link

`MSBuildWorkspace` does not recognize the `Remove` attribute for MSBuild items in an ItemGroup #21275

Open dpaoliello opened 7 years ago

dpaoliello commented 7 years ago

Version Used: 2.3.1

Steps to Reproduce: Consider this csproj file:

<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
  <PropertyGroup>
    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
    <OutputType>Library</OutputType>
    <AssemblyName>TestApp</AssemblyName>
    <TargetFrameworkVersion>v4.6.2</TargetFrameworkVersion>
    <OutputPath>.\</OutputPath>
  </PropertyGroup>
  <ItemGroup>
    <Compile Include="Class1.cs" />
    <Compile Remove="Class1.cs" />
  </ItemGroup>
  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>

When compiled with MSBuild, it correctly recognizes that there are no source files:

>msbuild minimal.csproj /v:minimal
Microsoft (R) Build Engine version 15.1.1012.6693
Copyright (C) Microsoft Corporation. All rights reserved.

CSC : warning CS2008: No source files specified. [minimal.csproj]
  minimal -> TestApp.dll

However, when attempting to load the same csproj via Roslyn's MSBuildWorkspace API:

static void Main(string[] args)
{
    MSBuildWorkspace msbuildWorkspace = MSBuildWorkspace.Create();
    Project project = msbuildWorkspace.OpenProjectAsync(@".\minimal.csproj").Result;

    foreach (WorkspaceDiagnostic workspaceDiagnostic in msbuildWorkspace.Diagnostics)
    {
        if (workspaceDiagnostic.Kind == WorkspaceDiagnosticKind.Failure)
        {
            Console.WriteLine(workspaceDiagnostic.ToString());
        }
    }
}

It reports an error:

[Failure] Msbuild failed when processing the file '.\minimal.csproj' with message: The attribute "Remove" in element <Compile> is unrecognized.

Roslyn's MSBuildWorkspace API should be able to handle Remove attributes.

uhaciogullari commented 7 years ago

Would I have the same problem if I'm running "dotnet build" command in Debian? My project compiles in Windows but not in the build server.

@dpaoliello Did you find any workarounds?

sharwell commented 7 years ago

💭 Sounds like MSBuildWorkspace is using an older version of the MSBuild internals. Not sure why though.

dpaoliello commented 7 years ago

@uhaciogullari I was lucky enough that the only Remove attribute in my code base was not actually being used by the project, so I refactored my targets files to put the Remove into its own targets file which is conditionally not included by the project I was loading.

@sharwell Given that the Remove attribute was added in .NET 3.5, I don't believe that this is the case. It's more likely that the MSBuild parsing was rewritten for Rolsyn and this feature was never implemented.

sharwell commented 7 years ago

@dpaoliello I've used remove a whole bunch recently in my work to convert projects to the new project system. For example, it's used by default to prevent <Compile> items from also appearing as <None> items in the project.

sharwell commented 7 years ago

💭 I'm not sure that documentation is correct. I tried earlier this week to use Remove in Visual Studio 2013 and got an error. I just reproduced it too:

image

image

rainersigwald commented 7 years ago

Remove has been available since MSBuild 3.5 within a Target element. In MSBuild 15, we started supporting it in a top-level ItemGroup.

I agree with @sharwell that it looks like MSBuild is using the wrong engine version. I suspect that this is another symptom of https://github.com/dotnet/roslyn/issues/21583 / https://github.com/Microsoft/msbuild/issues/2369.

rainersigwald commented 7 years ago

Actually, there's another possible explanation: @dpaoliello do you have binding redirects for Microsoft.Build assemblies in your app's .exe.config?

If not, is the behavior correct after adding:

  <runtime>
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
      <dependentAssembly>
        <assemblyIdentity name="Microsoft.Build" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
        <bindingRedirect oldVersion="0.0.0.0-15.1.0.0" newVersion="15.1.0.0" />
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="Microsoft.Build.Framework" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
        <bindingRedirect oldVersion="0.0.0.0-15.1.0.0" newVersion="15.1.0.0" />
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="Microsoft.Build.Tasks.Core" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
        <bindingRedirect oldVersion="0.0.0.0-15.1.0.0" newVersion="15.1.0.0" />
      </dependentAssembly>
    </assemblyBinding>
  </runtime>