AArnott / CodeGeneration.Roslyn

Assists in performing Roslyn-based code generation during a build.
Microsoft Public License
408 stars 59 forks source link

netstandard2.0 breaks Generator #57

Closed amis92 closed 6 years ago

amis92 commented 6 years ago

I've targeted netstandard2.0 with my generator in private project and it took some time before I realized that this was the change that broke my builds. I've created separate issue although I see #48 - I think that I generalized the issue since the other one is about the example from this repo. It may very well be closed as duplicate if it's not separate enough.

I've created a repro repo https://github.com/amis92/CodeGenerationBugDemo

Repro steps:

  1. Change CodeGenerationBugDemo.Generator target to netstandard2.0 (as opposed to netstandard1.5 or netstandard1.6).
  2. Observe that: a. CodeGenerationBugDemo.Library.DemoClass doesn't compile since the invoked method was not generated. b. CodeGenerationBugDemo.GeneratorTests.DemoGeneratorTests.GivenTestClass_CanInvokeGeneratedMethod test fails because the method was not generated.

Expected: netstandard2.0 target for Generator is supported.

amis92 commented 6 years ago

I've forked the repo and tried to pinpoint where in the generator framework (this repo) is the error happening and successfully found the original source: https://github.com/amis92/CodeGeneration.Roslyn/commit/d5c7e176b5e55c4327aaa0303c689a5bf775a765

The exact exception caught on assembly.GetTypes() is logged as follows:

          codegen: Generator 'CodeGeneration.Roslyn.Tests.Generators.DuplicateWithSuffixGenerator' from assembly 'CodeGeneration.Roslyn.Tests.Generators, Version=0.4.0.0, Culture=neutral, PublicKeyToken=null' failed to load.
            codegen: Exception listing assembly types: System.Reflection.ReflectionTypeLoadException: Unable to load one or more of the requested types. Retrieve the LoaderExceptions property for more information.
     at System.Reflection.RuntimeModule.GetTypes(RuntimeModule module)
     at System.Reflection.Assembly.GetTypes()
     at CodeGeneration.Roslyn.DocumentTransform.GetCodeGeneratorTypeForAttribute(INamedTypeSymbol attributeType, Func`2 assemblyLoader)
            codegen: Exception listing assembly types: System.IO.FileNotFoundException: Could not load file or assembly 'netstandard, Version=2.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51'. The system cannot find the file specified.
  File name: 'netstandard, Version=2.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51'
            codegen: Exception listing assembly types: System.IO.FileNotFoundException: Could not load file or assembly 'netstandard, Version=2.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51'. The system cannot find the file specified.
  File name: 'netstandard, Version=2.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51'
            codegen: Exception listing assembly types: System.IO.FileNotFoundException: Could not load file or assembly 'netstandard, Version=2.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51'. The system cannot find the file specified.
  File name: 'netstandard, Version=2.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51'
            codegen: Exception listing assembly types: System.IO.FileNotFoundException: Could not load file or assembly 'netstandard, Version=2.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51'. The system cannot find the file specified.
  File name: 'netstandard, Version=2.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51'
            codegen: Exception listing assembly types: System.IO.FileNotFoundException: Could not load file or assembly 'netstandard, Version=2.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51'. The system cannot find the file specified.
  File name: 'netstandard, Version=2.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51'
            codegen: Exception listing assembly types: System.IO.FileNotFoundException: Could not load file or assembly 'netstandard, Version=2.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51'. The system cannot find the file specified.
  File name: 'netstandard, Version=2.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51'
            codegen: Exception listing assembly types: System.IO.FileNotFoundException: Could not load file or assembly 'netstandard, Version=2.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51'. The system cannot find the file specified.
  File name: 'netstandard, Version=2.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51'
            codegen: Exception listing assembly types: System.IO.FileNotFoundException: Could not load file or assembly 'netstandard, Version=2.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51'. The system cannot find the file specified.
  File name: 'netstandard, Version=2.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51'
            codegen: Exception listing assembly types: System.IO.FileNotFoundException: Could not load file or assembly 'netstandard, Version=2.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51'. The system cannot find the file specified.
  File name: 'netstandard, Version=2.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51'
            codegen: Exception listing assembly types: System.IO.FileNotFoundException: Could not load file or assembly 'netstandard, Version=2.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51'. The system cannot find the file specified.
  File name: 'netstandard, Version=2.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51'
amis92 commented 6 years ago

Tracking further, it may have to do with https://github.com/dotnet/standard/issues/481

AArnott commented 6 years ago

This is by design for now. MSBuild Tasks must target either .NET Core or .NET Framework -- they cannot target .NET Standard and expect to run on the .NET Framework version of MSBuild because MSBuild.exe does not guarantee all the .NET Standard contract assemblies are discoverable.

One issue tracking the general problem is here: https://github.com/Microsoft/msbuild/issues/1940

So you should compile your generator for .NET Framework. If you want to run on dotnet build you can also build your generator for netcoreapp by multi-targeting with this xml in your project:

  <TargetFrameworks>net46;netcoreapp1.0</TargetFrameworks>