dotnet / sdk

Core functionality needed to create .NET Core projects, that is shared between Visual Studio and CLI
https://dot.net/core
MIT License
2.6k stars 1.03k forks source link

AOT compile gives incorrect error about Roslyn source generator coming from a ProjectReference #37228

Open jasonmalinowski opened 7 months ago

jasonmalinowski commented 7 months ago

It appears there's a bug in the SDK's enforcement around project references and AOT compile. If you're doing an AOT compile, all the dependencies are checked for being a valid TFM for AOT, which 100% makes sense. However if a user is consuming a Roslyn source generator from another project (which folks often do), that project is also being checked even though we enforce that Roslyn source generators must be compiled as netstandard2.0. Note the generator in this case is being ran not as a part of deployed app but as a part of the build, so AOT shouldn't be applying in the first place.

I'd say the bug in this case would be that a project reference that's marked as ReferenceOutputAssembly="false" or OutputItemType="Analyzer" shouldn't be getting considered for purposes of AOT. I'm not sure exactly where that condition check should go but I'd expect it to be somewhere.

Discussed in https://github.com/dotnet/roslyn/discussions/70900

Originally posted by **rudiv** November 20, 2023 We have a test project that references our source generator: ```xml ``` This works fine until we try to compile as AOT, it is trying to compile the source generator too which obviously fails due to the netstandard2.0 target. ``` 1.148 /usr/share/dotnet/sdk/8.0.100/Sdks/Microsoft.NET.Sdk/targets/Microsoft.NET.Sdk.FrameworkReferenceResolution.targets(90,5): error NETSDK1207: Ahead-of-time compilation is not supported for the target framework. [/src/src/Reaper.SourceGenerator/Reaper.SourceGenerator.csproj] ------ ``` The Source Generator is marked as a Roslyn Component and works in other scenarios for AOT (ie. referenced from NuGet). What is the correct way to test this? Our generator is designed to produce code that makes the project AOT friendly, but we would obviously like the ability to test this. The workaround we're using now is to compile the source generator first, get the nupkg and create a target that references this local package. However that seems cumbersome.
vitek-karas commented 7 months ago

We need to get clarity if this is caused by passing PublishAOT=true on the command line or not.

If it is passed on the command line, then this is very likely the same problem as described in https://github.com/dotnet/runtime/issues/94406.

hwoodiwiss commented 6 months ago

I've run into the same issue in a project, and it's as you describe above, with the following in my csproj:

  <PropertyGroup Condition="$([MSBuild]::IsTargetFrameworkCompatible($(TargetFramework), 'net8.0'))">
    <IsAotCompatible>true</IsAotCompatible>
    <PublishAot>true</PublishAot>
  </PropertyGroup>

and using the command dotnet publish .\examples\ExampleMinimalApi\ExampleMinimalApi.csproj -r win-x64 -c Release --framework net8.0 with a netstandard2.0 project dependency, the build runs fine and outputs an AoT compiled exe.

With the command dotnet publish .\examples\ExampleMinimalApi\ExampleMinimalApi.csproj /p:PublishAot=true -r win-x64 -c Release --framework net8.0, I get the same error as above:

C:\Program Files\dotnet\sdk\8.0.100\Sdks\Microsoft.NET.Sdk\targets\Microsoft.NET.Sdk.FrameworkReferenceResolution.targe
ts(90,5): error NETSDK1207: Ahead-of-time compilation is not supported for the target framework. [R:\source\repos\Argum
entativeFilters\src\ArgumentativeFilters.Generator\ArgumentativeFilters.Generator.csproj]

C:\Program Files\dotnet\sdk\8.0.100\Sdks\Microsoft.NET.Sdk\targets\Microsoft.NET.Sdk.FrameworkReferenceResolution.targe
ts(90,5): error NETSDK1207: Ahead-of-time compilation is not supported for the target framework. [R:\source\repos\Argum
entativeFilters\src\ArgumentativeFilters\ArgumentativeFilters.csproj]
vitek-karas commented 6 months ago

With the command dotnet publish .\examples\ExampleMinimalApi\ExampleMinimalApi.csproj /p:PublishAot=true -r win-x64 -c Release --framework net8.0, I get the same error as above:

Unfortunately, as described above, this is an expected behavior right now. Passing the property on the command line "forces" the property on all projects, including dependent library projects.

AshleighAdams commented 4 months ago

@vitek-karas What's the recommended way to produce 2 builds, one AOT'd and one not, without resorting to modifying the csproj with shell commands?

vitek-karas commented 4 months ago

You can introduce conditionals into the project:

<PublishAot Condition="'$(MyPublishWithoutAot)' != 'true'">true</PublishAot>

And then on command line:

This will produce the AOT build

dotnet publish

This will produce a non-AOT build

dotnet publish /p:MyPublishWithoutAot=true
AshleighAdams commented 4 months ago

Thanks @vitek-karas, tho I found mirroring the value to be more... canonical?

<PublishAot Condition="'$(ProjectPublishAot)' != ''">$(ProjectPublishAot)</PublishAot>
vitek-karas commented 4 months ago

I intentionally made it to default to PublishAOT - because this property also enables analyzers during build/IDE, and if the app is supposed to be AOT ready then it should use the analyzers by default.

AshleighAdams commented 4 months ago

Ah, I slapped <IsAotCompatible Condition="'$(IsAotCompatible)'==''">true</IsAotCompatible> in my Directory.Build.props instead for that, so I can enable it for all projects in the solution, then selectively disable the ones that aren't AOT compatible