roslyn: Source generator dependency unable to be resolved
Version Used:
MSBuild: 16.9.0.11203
.NET: 5.0.201
CSC: 3.900.21.12328 (comes with .NET 5.0.201 and used by dotnet build
), 3.900.21.16010 (comes with Visual Studio and used at least by msbuild
but probably VS too) - All the commits between these two versions
Visual Studio: 16.9.2
Steps to Reproduce / Actual Behaviour: Sample project to recreate issue: https://github.com/Turnerj/SourceGeneratorDependencyTest
Using .NET CLI (like we use on a CI)
- Clean solution
- Build solution with command
dotnet build
- Solution builds đ
Using MSBuild
- Clean solution
- Build solution with command
msbuild
- Solution fails (see generator warning) đ
Using Visual Studio
- Clean solution
- Build solution via Visual Studio
- Solution fails (see generator warning) đ
Generator Warning
CSC : warning CS8784: Generator âCustomSourceGeneratorâ failed to initialize. It will not contribute to the output and compilation errors may occur as a result. Exception was of type âFileNotFoundExceptionâ with message âCould not load file or assembly âSystem.Text.Encodings.Web, Version=5.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51â or one of its dependencies. The system cannot find the file specified.â
Expected Behavior:
Each method builds the project.
Notes:
The sample project is a minimum example of what we use in a full project: https://github.com/RehanSaeed/Schema.NET/
Iâm following the guidance listed in this discussion about how to mark the package reference: https://github.com/dotnet/roslyn/discussions/47517#discussioncomment-64145
This is also seen on the Roslyn SDK C# samples: https://github.com/dotnet/roslyn-sdk/blob/0313c80ed950ac4f4eef11bb2e1c6d1009b328c4/samples/CSharp/SourceGenerators/SourceGeneratorSamples/SourceGeneratorSamples.csproj#L13-L30
Iâve added the transient dependency (in my case System.Text.Encodings.Web
) as per this comment in the same discussion: https://github.com/dotnet/roslyn/discussions/47517#discussioncomment-277339
If I use the version 5.0.0
of System.Text.Encodings.Web
, it does build with all methods. Iâve tried to debug binlogs of this but I havenât found anything explaining why it resolves correctly via dotnet build
and not via Visual Studio (or msbuild
).
I donât see why I canât specifically use version 5.0.1
of System.Text.Encodings.Web
, hopefully you can work out what is going on!
About this issue
- Original URL
- State: closed
- Created 3 years ago
- Comments: 37 (7 by maintainers)
Iâve been looking into ways that a user can avoid manually specifying transient dependencies for a source generator and have something working with the following:
This effectively adds:
This isnât perfect as it adds a few other libraries against
TargetPathWithTargetPlatformMoniker
that shouldnât be there but with some more time processing the available data in the custom target, it would be possible to have this configured without any issues.My question though goes back to: Why isnât something like this done automatically for projects with source generators anyway?
Honestly, I donât know really if this is much a Roslyn issue now or a default targets issue with MSBuild or .NET itself. I want to push for having this automatically handled by some part of the build process so users donât need to bother with manually configuring it.
Any advice on where this would be best to further discuss would be appreciated!
@aktxyz Thank you for that information. My situation must be different since that solution doesnât fully work for me. In the case of locally referencing an analyzer that can work but when generating a Nuget package it seems required to manually specify transitient dependencies.
Additionally, my use of the AdhocWorkspace type ends up meaning that compilation of the source generator fails without also adding:
</ItemGroup>This is such a confusing feature of C#. It seems very difficult to use source generators due to all these issues. Hopefully this is all resolved one day by Microsoft.
Source Generators also have different behavior with assembly loading/redirection when generating nugets vs local project references. Itâs actually an absolute headache really.
I guess my main issue here is that where one would normally just install the specific dependency they need, for a source generator I need to specify the entire tree of dependencies in my csproj file manually. While Iâm sure a mountain of work has gone into making source generators work, this (and debugging source generators) make it feel somewhat incomplete.
While @jmarolf went out of their way to list all of the dependencies in my case (thank you!), basically Iâm wondering why some combination of NuGet restore/compilation process isnât doing this automatically. NuGet restore already has to work out all the dependencies anyway however this current process of manually adding everything is quite intensive, especially for when package updates happen as I would need to re-check to see if any new dependencies are added.
So would there be any plans on changing this behaviour and having the compiler (or some other part of the build process) automatically handle this?
I literally canât get this to work no matter what I do. Iâll have to switch to another Json package and lick my wounds. This is not worth my time and I wouldnât expect anyone to be an expert in the inner workings of msbuild/csproj.
It would be great if someone could update the section on nuget dependencies in the cookbook to include this: https://github.com/dotnet/roslyn/blob/main/docs/features/source-generators.cookbook.md
Hmm, this has got me thinking though. @jmarolf it looks like
ResolvePackageAssets
is explicitly spitting out the analyzers, which the compiler consumes. Presumably at this point (or earlier on when we write the cache file) we have access to the assets.json which describe the analyzer dependencies?Can we just hook that task to return the dependencies as part of the analyzers directly (or even better, as an
AnalyzerDependencies
item group that we can merge later on to make debugging easier?)What @Turnerj recommended did not work for me:
This is a source generator used against a .net 5 project.
This bug has been open for nearly two years, are there any official updates on this issue? All of the solutions above seem to be unreliable workaroundsâI havenât personally gotten them to work.
Glad you got something working for yourself @HavenDV ! In my cases with source generators, they have been local projects and are only to aid the build of a different local project rather than packing the dependencies.
Still hoping for some movement on dotnet/sdk#17775 to automate all of this though AFAIK there are various blockers that are preventing progress. Fingers crossed for a .NET 7 fix!
@Turnerj
The
ResolvePackageDependenciesForBuild
target is involved in restore so wonât occur in future builds which is probably the behaviour youâre seeing. I (think) you can substitute it forResolvePackageAssets
and it should fix it.As you said above however, the trouble with this approach is it doesnât discriminate and basically adds _everything _ as an analyzer dependency. For small projects or things under your control that might be ok, but will slow the compilation as the list gets bigger, and worse potentially lead to really hard to debug version mismatches when you start adding more dependencies.
Its definitely on our radar, and something that has come up more since the introduction of source generators. The problem existed with analyzers too, but authors were just less likely to use dependencies. Weâve been discussing a range of steps that would improve all these scenarios. Most of that work is going to be outside of Roslyn (though weâll obviously help) so youâre probably best opening an issue in http://github.com/dotnet/sdk to get the ball rolling.
That level of MSBuild magic is a bit beyond me. @chsienki can likely better say.
Iâve been having the issue myself @kamronbatman . Iâm having trouble tracking what the TargetPathWithTargetPlatformMoniker actually does. In some cases it seems to work, in others, it doesnât.
Iâm creating a custom NuGet repo on disk, and I have a project called âMy.Analyzers.Extensionsâ
I have another project, which is an analyzer, called âMy.Microservice.Builder.Analyzersâ which references System.Text.Json, Microsoft.Bcl.AsyncInterfaces, and My.Analyzers.Extensions.
When I add
<TargetPathWithTargetPlatformMoniker Include="@(ResolvedCompileFileDefinitions)" IncludeRuntimeDependency="false" />, then my My.Analyzer.Extensions dll has the same FileNotFound error.
However I have a workaround that seems to work, that uses the <None Include> tag, which effectively packages a dll in the package. Iâm concerned that it means that if the parent library that inherits this package has a different version, this analyzer will NOT use the different version, but will continue to use the packaged version. Is that Works as Designed?
Hereâs my workaround that only packages what you need. You just need to add 'Pack=âtrueâ â to the PackageReference.
It uses a combination of @Turnerj and @kzuâs blog post: https://til.cazzulino.com/msbuild/how-to-include-package-reference-files-in-your-nuget-package
I would appreciate it if you would complete your article with this workaround for NuGet. I think it would save time for some people like me. I manually maintained a large number of transient dependencies for about a year.
I am on the latest vs 16.10.0 ⌠and the relevant sections of my csproj look like this ⌠hope this helps
woohoo ! thanks !
at first I switched to to 5.0.0 and was still getting the same exception when calling
JsonSerializer.Serialize
BUT ⌠then I decided to try adding this incantation to the csproj and BOOM it worked.
Now, should I spend my day learning about the above stuff (TargetPathWithTargetPlatformMoniker/etc) âŚ
or actually making progress on the project ⌠hmm ⌠project it is !
All DLLs in the same folder as the analyzer will essentially be passed via
/analyzer
automatically. Itâs essentially implicit. Generally if the package has the right dependencies it will just work.This is why I was asking for the binlog though. It will make it apparent what is happening here.