AArnott / CodeGeneration.Roslyn

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

Cannot load generator dependencies when packed as nuget package #166

Closed cezarypiatek closed 4 years ago

cezarypiatek commented 4 years ago

Hi, I create a generator using CodeGeneration.Roslyn. Everything works when I'm using it in the same solution where the generator is defined. However, when I pack everything into a NuGet package and I try to use it in another project it fails. I'm getting the following exceptions:

1>------ Rebuild All started: Project: ConsoleApp4, Configuration: Debug Any CPU ------
1>Exception in file processing: System.IO.FileNotFoundException: Could not load file or assembly 'Microsoft.CodeAnalysis.Workspaces, Version=3.1.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35'. Nie można odnaleźć określonego pliku.
1>File name: 'Microsoft.CodeAnalysis.Workspaces, Version=3.1.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35'
1>   at OnBuildGenerator.OnBuildMappingGenerator.GenerateRichAsync(TransformationContext context, IProgress`1 progress, CancellationToken cancellationToken)
1>   at CodeGeneration.Roslyn.Engine.DocumentTransform.TransformAsync(CSharpCompilation compilation, SyntaxTree inputDocument, String projectDirectory, Func`2 assemblyLoader, IProgress`1 progress)
1>   at CodeGeneration.Roslyn.Engine.CompilationGenerator.Generate(IProgress`1 progress, CancellationToken cancellationToken)
1>
1>
1>AggregateException: One or more errors occurred. (Could not load file or assembly 'Microsoft.CodeAnalysis.Workspaces, Version=3.1.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35'. Nie można odnaleźć określonego pliku.)
1>System.AggregateException: One or more errors occurred. (Could not load file or assembly 'Microsoft.CodeAnalysis.Workspaces, Version=3.1.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35'. Nie można odnaleźć określonego pliku.) ---> System.IO.FileNotFoundException: Could not load file or assembly 'Microsoft.CodeAnalysis.Workspaces, Version=3.1.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35'. Nie można odnaleźć określonego pliku.
1>   at OnBuildGenerator.OnBuildMappingGenerator.GenerateRichAsync(TransformationContext context, IProgress`1 progress, CancellationToken cancellationToken)
1>   at CodeGeneration.Roslyn.Engine.DocumentTransform.TransformAsync(CSharpCompilation compilation, SyntaxTree inputDocument, String projectDirectory, Func`2 assemblyLoader, IProgress`1 progress)
1>   at CodeGeneration.Roslyn.Engine.CompilationGenerator.Generate(IProgress`1 progress, CancellationToken cancellationToken)
1>   --- End of inner exception stack trace ---
1>   at CodeGeneration.Roslyn.Engine.CompilationGenerator.Generate(IProgress`1 progress, CancellationToken cancellationToken)
1>   at CodeGeneration.Roslyn.Generate.Program.Main(String[] args)
1>---> (Inner Exception #0) System.IO.FileNotFoundException: Could not load file or assembly 'Microsoft.CodeAnalysis.Workspaces, Version=3.1.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35'. Nie można odnaleźć określonego pliku.
1>File name: 'Microsoft.CodeAnalysis.Workspaces, Version=3.1.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35'
1>   at OnBuildGenerator.OnBuildMappingGenerator.GenerateRichAsync(TransformationContext context, IProgress`1 progress, CancellationToken cancellationToken)
1>   at CodeGeneration.Roslyn.Engine.DocumentTransform.TransformAsync(CSharpCompilation compilation, SyntaxTree inputDocument, String projectDirectory, Func`2 assemblyLoader, IProgress`1 progress)
1>   at CodeGeneration.Roslyn.Engine.CompilationGenerator.Generate(IProgress`1 progress, CancellationToken cancellationToken)
1>

I verified and the Microsoft.CodeAnalysis.Workspaces assembly with the expected version is present in the tools folder inside the nuget package. It looks like a problem with loading generator dependencies.

Update: My project is available here https://github.com/cezarypiatek/MappingGenerator/tree/feature/on_build_code_generation

The generator is defined in OnBuildGenerator project. Nuget should be generated automatically on build.

amis92 commented 4 years ago

Indeed, loading dependencies is currently an issue. See #114 for tracking an attempt at fixing.

cezarypiatek commented 4 years ago

I've discovered that my generator assembly is loaded from the lib directory instead of the tools. I have definedGeneratorAssemblySearchPaths` in the following way:

<GeneratorAssemblySearchPaths Include="$(MSBuildThisFileDirectory)..\tools" />

How to force CodeGeneration.Roslyn to load generators from the tools directory?

cezarypiatek commented 4 years ago

Next observation: I think the problem is caused by this method https://github.com/AArnott/CodeGeneration.Roslyn/blob/0deb38f8c07461e44077e606dba619552e1c1018/src/CodeGeneration.Roslyn.Engine/CompilationGenerator.cs#L318

Because the generator assembly is searched in the first place in ReferencePath instead of GeneratorAssemblySearchPaths.

The problem occurs when the Attribute and Generator are in the same assembly.

amis92 commented 4 years ago

Yes, so that'll be why for p2p (same solution) this works - that's because then you're referencing this project (and in turn assembly), so it becomes included in ReferencePath item.

I don't think there's an easy solution here, aside from separating attribute into another assembly.

PS Good investigation BTW.

cezarypiatek commented 4 years ago

For p2p approach, the GeneratorAssemblySearchPaths variable is not set so changing the order of searching: first GeneratorAssemblySearchPaths then ReferencePath should fix the issue without any negative side effects.

chinwobble commented 4 years ago

I'm running into similar issues. I'm writing a generator that depends on Microsoft.Data.SqlClient. I've combined the attributes and generators into the same assembly for simplicity. If my lib is written against .net standard then I get these load exceptions.

Also for some reason the generator able to connect to local databases.

amis92 commented 4 years ago

This will be resolved via Plugin.Sdk. Tracked in #113