Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Trimmed compilation fails with annotations #539

Open
ProphetLamb opened this issue Aug 9, 2023 · 1 comment
Open

Trimmed compilation fails with annotations #539

ProphetLamb opened this issue Aug 9, 2023 · 1 comment
Labels

Comments

@ProphetLamb
Copy link

ProphetLamb commented Aug 9, 2023

Compilation with trimming fails due to reflection. Trimming is often used with single file executables:

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

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

    <PublishSingleFile>true</PublishSingleFile>
    <SelfContained>true</SelfContained>
    <PublishTrimmed>true</PublishTrimmed>
    <PublishReadyToRun>true</PublishReadyToRun>
    <EnableCompressionInSingleFile>true</EnableCompressionInSingleFile>
    <RuntimeIdentifier>win-x64</RuntimeIdentifier>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="McMaster.Extensions.CommandLineUtils" Version="4.0.2" />
  </ItemGroup>
</Project>

Compilation yields the following warning:

...\mcmaster.extensions.commandlineutils\4.0.2\lib\netstandard2.1\McMaster.E
xtensions.CommandLineUtils.dll : warning IL2104: Assembly 'McMaster.Extensions.CommandLineUtils' prod 
uced trim warnings. For more information see https://aka.ms/dotnet-illink/libraries [...]

Execution fails with the following exception:

Unhandled exception. System.InvalidOperationException: No method named 'OnExecute' or 'OnExecuteAsync' could be found.
   at McMaster.Extensions.CommandLineUtils.Conventions.ExecuteMethodConvention.OnExecute(ConventionContext, CancellationToken)
   at McMaster.Extensions.CommandLineUtils.Conventions.ExecuteMethodConvention.<>c__DisplayClass0_0.<<Apply>b__0>d.MoveNext()
--- End of stack trace from previous location ---
   at McMaster.Extensions.CommandLineUtils.CommandLineApplication.ExecuteAsync(String[], CancellationToken )
   at McMaster.Extensions.CommandLineUtils.CommandLineApplication.ExecuteAsync[TApp](CommandLineContext, CancellationToken )
   at McMaster.Extensions.CommandLineUtils.CommandLineApplication.Execute[TApp](CommandLineContext)   
   at McMaster.Extensions.CommandLineUtils.CommandLineApplication.Execute[TApp](IConsole, String[] )  
   at Program.<Main>$(String[])

Enabling reflection for public methods yield the following exception:

Unhandled exception. System.InvalidOperationException: Could not find any public constructors of type 
'MyCommand'.
   at McMaster.Extensions.CommandLineUtils.Conventions.ConstructorInjectionConvention.<>c__6`1.<FindMatchedConstructor>b__6_0()
   at System.Lazy`1.ViaFactory(LazyThreadSafetyMode)
   at System.Lazy`1.ExecutionAndPublication(LazyHelper, Boolean)
   at System.Lazy`1.CreateValue()
   at McMaster.Extensions.CommandLineUtils.CommandLineApplication`1.McMaster.Extensions.CommandLineUtils.Abstractions.IModelAccessor.GetModel()
   at McMaster.Extensions.CommandLineUtils.Conventions.ArgumentAttributeConvention.<>c__DisplayClass1_0.<AddArgument>b__1(ParseResult)
   at McMaster.Extensions.CommandLineUtils.CommandLineApplication.HandleParseResult(ParseResult)      
   at McMaster.Extensions.CommandLineUtils.CommandLineApplication.Parse(String[] )
   at McMaster.Extensions.CommandLineUtils.CommandLineApplication.ExecuteAsync(String[], CancellationToken )
   at McMaster.Extensions.CommandLineUtils.CommandLineApplication.ExecuteAsync[TApp](CommandLineContext, CancellationToken )
   at McMaster.Extensions.CommandLineUtils.CommandLineApplication.Execute[TApp](CommandLineContext)   
   at McMaster.Extensions.CommandLineUtils.CommandLineApplication.Execute[TApp](IConsole, String[] )  
   at Program.<Main>$(String[])

Enabling reflection for both, public methods and constructors resolves the issue.

This requires the following annotation:

using System.Diagnostics.CodeAnalysis;
using McMaster.Extensions.CommandLineUtils;

Execute<MyCommand>();

void Execute<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods | DynamicallyAccessedMemberTypes.PublicConstructors)] T>()
	where T : class
{
	CommandLineApplication.Execute<T>(args);
}

Please add these annotations to all reflection methods consuming Types and generic type arguments.

I am glad to provide more information on the subject, please also refer to https://learn.microsoft.com/en-us/dotnet/core/deploying/trimming/prepare-libraries-for-trimming

@ProphetLamb ProphetLamb added the bug label Aug 9, 2023
@ProphetLamb
Copy link
Author

ProphetLamb commented Aug 9, 2023

Warnings for reflection can be enabled using the following switch

<IsTrimmable>true</IsTrimmable>

samuel-lucas6 added a commit to samuel-lucas6/Kryptor that referenced this issue Dec 3, 2023
Added some new lines to shorten and clarify the dotnet publish command. Unfortunately, PublishTrimmed can't be set to true like in .NET 6 due to issues with the CommandLineUtils library: natemcmaster/CommandLineUtils#539. If that's fixed, it will be changed as it significantly reduces the executable size. EnableCompressionInSingleFile also reduces the executable size but worsens performance. PublishReadyToRunComposite is worth investigating for better start up time on Linux but increases executable size. Finally, PublishAot could also be investigated but requires trimming and may cause problems.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

1 participant