dotnet / linker

389 stars 127 forks source link

TrimMode=partial seems broken with PublishReadyToRun=true on .NET 7 RC1 #3058

Open perlun opened 2 years ago

perlun commented 2 years ago

Description

When using /p:PublishReadyToRun=true, I can't seem to prevent an assembly from trimming by setting the TrimMode property in the .csproj file like this:

    <PropertyGroup>
        <TrimMode>partial</TrimMode>
    </PropertyGroup>

The assembly is always unconditionally trimmed, breaking my application which relies on run-time loading of assemblies.

Reproduction Steps

Unfortunately not so minimal, but it's a least a fully FOSS project which exhibits the problem: https://github.com/perlang-org/perlang/pull/347.

Check out that branch and run dotnet publish src/Perlang.ConsoleApp/Perlang.ConsoleApp.csproj -c Release -r linux-x64 --self-contained true /p:PublishReadyToRun=true /p:SolutionDir=$(pwd)/ to get a local src/Perlang.ConsoleApp/bin/Release/net7.0/linux-x64/publish/Perlang.Stdlib.dll which reproduces the problem.

Expected behavior

In the current (.NET 6-based) version, the Perlang.Stdlib.dll compiled with PublishReadyToRun=true contains these typedefs:

$ ~/.perlang/release/bin/perlang -V
Perlang 0.2.0 (built from git commit 78fbc1f) on .NET 6.0.5

  Number of detected (v)CPUs: 20
  Running in 64-bit mode: True
  Operating system info: Unix 5.18.0.4

$ monodis --typedef ~/.perlang/release/bin/Perlang.Stdlib.dll
Typedef Table
1: (null) (flist=1, mlist=1, flags=0x0, extends=0x0)
2: Microsoft.CodeAnalysis.EmbeddedAttribute (flist=1, mlist=1, flags=0x100100, extends=0x21)
3: System.Runtime.CompilerServices.NullableAttribute (flist=1, mlist=2, flags=0x100100, extends=0x21)
4: System.Runtime.CompilerServices.NullableContextAttribute (flist=2, mlist=4, flags=0x100100, extends=0x21)
5: Perlang.Stdlib.Argv (flist=3, mlist=5, flags=0x100001, extends=0x2d)
6: Perlang.Stdlib.Base64 (flist=4, mlist=7, flags=0x100181, extends=0x2d)
7: Perlang.Stdlib.Libc (flist=4, mlist=9, flags=0x100181, extends=0x2d)
8: Perlang.Stdlib.Posix (flist=4, mlist=13, flags=0x100181, extends=0x2d)
9: Perlang.Stdlib.Time (flist=4, mlist=18, flags=0x100181, extends=0x2d)
10: Perlang.Exceptions.IllegalStateException (flist=4, mlist=19, flags=0x100001, extends=0x2c)
11: Perlang.Exceptions.StdlibException (flist=4, mlist=20, flags=0x100081, extends=0x61)
12: Perlang.Stdlib.Libc/Internal (flist=4, mlist=21, flags=0x100183, extends=0x2d)
13: Perlang.Stdlib.Posix/Internal (flist=4, mlist=22, flags=0x100183, extends=0x2d)

Actual behavior

In .NET 7 RC1, this behaves differently. Even when trying to explicitly exclude this assembly from trimming like this:

diff --git src/Perlang.Stdlib/Perlang.Stdlib.csproj src/Perlang.Stdlib/Perlang.Stdlib.csproj
index d6cc03c..1598b7a 100644
--- src/Perlang.Stdlib/Perlang.Stdlib.csproj
+++ src/Perlang.Stdlib/Perlang.Stdlib.csproj
@@ -3,6 +3,7 @@
     <PropertyGroup>
         <GenerateAssemblyInfo>false</GenerateAssemblyInfo>
         <RootNamespace>Perlang</RootNamespace>
+        <TrimMode>partial</TrimMode>
     </PropertyGroup>

     <PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">

...I still get an assembly where (almost) all the relevant types have been trimmed away:

$ src/Perlang.ConsoleApp/bin/Release/net7.0/linux-x64/publish/perlang -V
Perlang 0.3.0-dev.5 (built from git commit abcfc05) on .NET 7.0.0

  Number of detected (v)CPUs: 20
  Running in 64-bit mode: True
  Operating system info: Unix 5.18.0.4

$ monodis --typedef src/Perlang.ConsoleApp/bin/Release/net7.0/linux-x64/publish/Perlang.Stdlib.dll 
Typedef Table
1: (null) (flist=1, mlist=1, flags=0x0, extends=0x0)
2: Perlang.Stdlib.Argv (flist=1, mlist=1, flags=0x100001, extends=0x5)
3: Perlang.Exceptions.IllegalStateException (flist=2, mlist=2, flags=0x100001, extends=0x10)
4: Perlang.Exceptions.StdlibException (flist=2, mlist=3, flags=0x100081, extends=0x15)

Regression?

It worked in .NET 6; the above problem is likely because of the trimming-related changes described here: https://devblogs.microsoft.com/dotnet/announcing-dotnet-7-preview-7/#trimming-and-nativeaot-all-assemblies-trimmed-by-default

Known Workarounds

No response

Configuration

.NET 7 RC1. Debian GNU/Linux 12 (bookworm).

Other information

No response

dotnet-issue-labeler[bot] commented 2 years ago

I couldn't figure out the best area label to add to this issue. If you have write-permissions please help me learn by adding exactly one area label.

MichalStrehovsky commented 2 years ago

Do I understand it correctly that Perlang.Stdlib.csproj produces a library and Perlang.ConsoleApp.csproj produces an executable?

If so, <TrimMode>partial</TrimMode> should be applied on Perlang.ConsoleApp.csproj. It has no effect on Perlang.Stdlib.csproj. How the application should be trimmed is decided by the application, not by one of its libraries. See more: https://learn.microsoft.com/en-us/dotnet/core/deploying/trimming/prepare-libraries-for-trimming

marek-safar commented 2 years ago

/cc @sbomer

vitek-karas commented 2 years ago

Maybe we should warn when TrimMode is specified in a non-exe project file... Probably starting with .NET 8 to avoid breaking things.

perlun commented 2 years ago

@MichalStrehovsky Thanks a lot! :pray: You were absolutely right; the <TrimMode>partial</TrimMode was applied on the wrong project. For some reason, I got the impression that this setting should be applied on the Perlang.Stdlib.csproj project, since that was the assembly that got incorrectly trimmed...

Thanks for the helpful reference also. Would it make sense to mention on that page (https://learn.microsoft.com/en-us/dotnet/core/deploying/trimming/prepare-libraries-for-trimming) something about TrimMode and where it should be properly applied? :thinking: It is actually mentioned on https://learn.microsoft.com/en-us/dotnet/core/deploying/trimming/trimming-options?pivots=dotnet-7-0 though. I have <PublishTrimmed>true</PublishTrimmed> set on the executable project (Perlang.ConsoleApp.csproj), so I guess I should have been able to figure this out...

Maybe we should warn when TrimMode is specified in a non-exe project file... Probably starting with .NET 8 to avoid breaking things.

I guess this wouldn't hurt, @vitek-karas. :+1:


The issue is resolved for me; by applying the above changes, my project runs correctly. (of course, making it work properly with no trim warnings would be even better, but that's a separate story)

I'm fine with closing it, but will keep it open if you want to do any docs/warning-related issue as a followup first.