Search code examples
c#sourcegenerators

Can't use analyzer in nuget package - An instance of analyzer cannot be created from DLL


I've created a source generator which barring some issues mostly seems to work.

I tested it during development using a test project with a project reference to the generator.

I've now packaged it up into a nuget package and am trying to use it in a different project with that but I'm getting this not very helpful warning:

CSC : warning CS8032: An instance of analyzer SuperFluid.Internal.SourceGenerators.FluidApiSourceGenerator cannot be created from /home/james/.nuget/packages/superfluid/0.0.1/analyzers/dotnet/cs/SuperFluid.dll : Exception has been thrown by the target of an invocation.. [/home/james/repos/SuperFluid/src/DemoProject/DemoProject.csproj]

The (abridged) csproj for my source generator is:

<Project Sdk="Microsoft.NET.Sdk">

    <PropertyGroup>
        <TargetFramework>net7.0</TargetFramework>
        <ImplicitUsings>enable</ImplicitUsings>
        <Nullable>enable</Nullable>
        <LangVersion>default</LangVersion>
        <GeneratePackageOnBuild>true</GeneratePackageOnBuild>
        <IncludeBuildOutput>false</IncludeBuildOutput>
        <EnforceExtendedAnalyzerRules>true</EnforceExtendedAnalyzerRules>
    </PropertyGroup>

    <ItemGroup>
        <None Include="../../README.md" Pack="true" PackagePath="\" />
    </ItemGroup>

    <ItemGroup>
        <InternalsVisibleTo Include="SuperFluid.Tests" />
    </ItemGroup>

    <ItemGroup>
        <PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.4.0" PrivateAssets="all" />
        <PackageReference Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.4" PrivateAssets="all" />
        <PackageReference Include="YamlDotNet" Version="13.1.0" PrivateAssets="all" GeneratePathProperty="true" />
    </ItemGroup>
    
    <!-- Gross hack to let source generator use nuget packages -->
    <PropertyGroup>
        <GetTargetPathDependsOn>$(GetTargetPathDependsOn);GetDependencyTargetPaths</GetTargetPathDependsOn>
    </PropertyGroup>
    
    <Target Name="GetDependencyTargetPaths" AfterTargets="ResolvePackageDependenciesForBuild">
            <ItemGroup>
                <TargetPathWithTargetPlatformMoniker Include="@(ResolvedCompileFileDefinitions)" IncludeRuntimeDependency="false" />
                <None Include="@(ResolvedCompileFileDefinitions)" Pack="true" PackagePath="analyzers/dotnet/cs" Visible="false" />
            </ItemGroup>
    </Target>
    <!-- End Hack -->
    
    
    <ItemGroup>
        <None Include="$(OutputPath)\$(AssemblyName).dll" Pack="true" PackagePath="analyzers/dotnet/cs" Visible="false" />
    </ItemGroup>
</Project>

And my test project is:

<Project Sdk="Microsoft.NET.Sdk">

    <PropertyGroup>
        <OutputType>Exe</OutputType>
        <TargetFramework>net7.0</TargetFramework>
        <ImplicitUsings>enable</ImplicitUsings>
        <Nullable>enable</Nullable>
    </PropertyGroup>

    <ItemGroup>
      <AdditionalFiles Include="DemoApiDefinition.fluid.yml" />
    </ItemGroup>

    <ItemGroup>
      <PackageReference Include="SuperFluid" Version="0.0.1" />
    </ItemGroup>

</Project>

Does anyone know what might be causing this? If not, how can I get the details of this inner exception?


Edit: I've retargetted my Source Generator to use netstandard2.0 and that doesn't seem to have helped:

I've also noticed this warning that may or may not be relevant when I pack:

/usr/share/dotnet/sdk/7.0.105/Sdks/NuGet.Build.Tasks.Pack/build/NuGet.Build.Tasks.Pack.targets(221,5): warning NU5128: - Add lib or ref assemblies for the netstandard2.0 target framework


Solution

  • I have finally managed to get this working, although I'm not entirely sure why this works, so I'd defer to the other answer for that.

    First, include the package as a private asset and set GeneratePathProperty="true":

      <ItemGroup>
            <PackageReference Include="YamlDotNet" Version="16.3.0" GeneratePathProperty="true" PrivateAssets="all" />
        </ItemGroup>
    
    

    Then add this magic snippet:

        <PropertyGroup>
            <GetTargetPathDependsOn>$(GetTargetPathDependsOn);GetDependencyTargetPaths</GetTargetPathDependsOn>
        </PropertyGroup>
    

    Then manually include your analyzer and your dependencies:

        <Target Name="GetDependencyTargetPaths">
            <ItemGroup>
                <TargetPathWithTargetPlatformMoniker Include="$(PKGYamlDotNet)\lib\netstandard2.0\YamlDotNet.dll" IncludeRuntimeDependency="false" />
            </ItemGroup>
        </Target>
        
        
        <ItemGroup>
            <None Include="$(OutputPath)\$(AssemblyName).dll" Pack="true" PackagePath="analyzers/dotnet/cs" Visible="false" />
            <None Include="$(PKGYamlDotNet)\lib\netstandard2.0\YamlDotNet.dll" Pack="true" PackagePath="analyzers/dotnet/cs" Visible="false" />
        </ItemGroup>
    

    I am not entirely sure why this works, but it does.