Trimmed compilation fails with annotations
ProphetLamb opened this issue · 3 comments
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 Type
s 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
Warnings for reflection can be enabled using the following switch
<IsTrimmable>true</IsTrimmable>