-
Notifications
You must be signed in to change notification settings - Fork 59
Description
What would you like to be added:
A trimming-safe alternative to ConfigurationBinder.BindInstance().
Why is this needed:
If you build uno.chefs for macOS + NativeAOT:
dotnet publish -c Release -r osx-x64 -f net10.0-desktop -p:TargetFrameworkOverride=net10.0-desktop \
-bl Chefs/Chefs.csproj -p:UseSkiaRendering=true -p:SelfContained=true \
-p:PublishAot=true -p:IsAotCompatible=true -p:TrimmerSingleWarn=false -p:_ExtraTrimmerArgs=--verbose \
-p:IlcGenerateMapFile=true -p:IlcGenerateMstatFile=true -p:IlcGenerateDgmlFile=true -p:IlcGenerateMetadataLog=true \
-p:EmitCompilerGeneratedFiles=true -p:CompilerGeneratedFilesOutputPath=`pwd`/_gen
several of the warnings are around configuration:
…/Chefs/App.xaml.cs(45,16): warning IL2026: Using member 'Uno.Extensions.ApplicationBuilderExtensions.NavigateAsync<TShell>(IApplicationBuilder, Func<IServiceProvider, INavigator, Task>)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Cannot statically analyze the type of instance so its members may be trimmed. [From TypeDescriptor.GetConverter() and others.].
…/Chefs/App.xaml.host.cs(20,23): warning IL2026: Using member 'Uno.Extensions.Localization.HostBuilderExtensions.UseLocalization(IHostBuilder, Action<HostBuilderContext, IServiceCollection>)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Cannot statically analyze the type of instance so its members may be trimmed. [From TypeDescriptor.GetConverter() and others.].
…/Chefs/App.xaml.host.cs(20,23): warning IL3050: Using member 'Uno.Extensions.Localization.HostBuilderExtensions.UseLocalization(IHostBuilder, Action<HostBuilderContext, IServiceCollection>)' which has 'RequiresDynamicCodeAttribute' can break functionality when AOT compiling. Binding strongly typed objects to configuration values may require generating dynamic code at runtime. [From Array.CreateInstance() and others.].
…/Chefs/App.xaml.host.cs(20,23): warning IL2026: Using member 'Uno.Extensions.HostBuilderExtensions.UseSerialization(IHostBuilder, Action<HostBuilderContext, IServiceCollection>)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Default behavior requires Reflection. Use UseJsonSerializationResolvers instead.
…/Chefs/App.xaml.host.cs(20,23): warning IL3050: Using member 'Uno.Extensions.HostBuilderExtensions.UseSerialization(IHostBuilder, Action<HostBuilderContext, IServiceCollection>)' which has 'RequiresDynamicCodeAttribute' can break functionality when AOT compiling. Default behavior requires Reflection. Use UseJsonSerializationResolvers instead.
…/Chefs/App.xaml.host.cs(20,23): warning IL2026: Using member 'Uno.Extensions.HostBuilderExtensions.UseNavigation(IHostBuilder, IDictionary<Type, Type>, Action<IViewRegistry, IRouteRegistry>, Func<IServiceCollection, MappedViewRegistry>, Func<IServiceCollection, IRouteRegistry>, Func<NavigationConfiguration, NavigationConfiguration>, Action<HostBuilderContext, IServiceCollection>)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Cannot statically analyze the type of instance so its members may be trimmed. [From TypeDescriptor.GetConverter() and others.].
…/Chefs/App.xaml.host.cs(51,6): warning IL2026: Using member 'Uno.Extensions.Configuration.ConfigBuilderExtensions.Section<TSettingsOptions>(IConfigBuilder, String, Func<HostBuilderContext, IConfigurationSection>)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Cannot statically analyze the type of instance so its members may be trimmed. [From TypeDescriptor.GetConverter() and others.].
…/Chefs/App.xaml.host.cs(51,6): warning IL3050: Using member 'Uno.Extensions.Configuration.ConfigBuilderExtensions.Section<TSettingsOptions>(IConfigBuilder, String, Func<HostBuilderContext, IConfigurationSection>)' which has 'RequiresDynamicCodeAttribute' can break functionality when AOT compiling. Binding strongly typed objects to configuration values may require generating dynamic code at runtime. [From Array.CreateInstance() and others.].
…/Chefs/App.xaml.host.cs(51,6): warning IL2026: Using member 'Uno.Extensions.Configuration.ConfigBuilderExtensions.Section<TSettingsOptions>(IConfigBuilder, String, Func<HostBuilderContext, IConfigurationSection>)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Cannot statically analyze the type of instance so its members may be trimmed. [From TypeDescriptor.GetConverter() and others.].
…/Chefs/App.xaml.host.cs(51,6): warning IL3050: Using member 'Uno.Extensions.Configuration.ConfigBuilderExtensions.Section<TSettingsOptions>(IConfigBuilder, String, Func<HostBuilderContext, IConfigurationSection>)' which has 'RequiresDynamicCodeAttribute' can break functionality when AOT compiling. Binding strongly typed objects to configuration values may require generating dynamic code at runtime. [From Array.CreateInstance() and others.].
We see that HostBuilderExtensions.UseNavigation() hits ConfigBuilderExtensions.Section<TSettingsOptions>(), which eventually hits ConfigurationBinder.BindInstance(), which uses TryConvertValue():
.Section<NavigationConfiguration>(nameof(NavigationConfiguration))) public static IConfigBuilder Section<TSettingsOptions>( if (configValue != null && TryConvertValue(type, configValue, section?.Path!, out convertedValue, out error))
All of these are annotated with [RequiresDynamicCode] and [RequiresUnreferencedCode] -- added in commit cd3e1a6 -- because:
TryConvertValue()requiresTypeDescriptor.GetConverter(), which basically throws up its hands and says "no trimming support for you!": https://learn.microsoft.com/en-us/dotnet/api/system.componentmodel.typedescriptor.getconverter?view=net-10.0#system-componentmodel-typedescriptor-getconverter(system-type)BindToCollection()/etc. hitType.MakeGenericType()and/orArray.CreateInstance()…
In trying to be helpful and useful, this codepath is fundamentally incompatible with trimming.
"Fortunately," Uno isn't alone in this: IConfiguration.Bind() has the same annotations!:
[System.Diagnostics.CodeAnalysis.RequiresDynamicCode("Binding strongly typed objects to configuration values requires generating dynamic code at runtime, for example instantiating generic types.")]
[System.Diagnostics.CodeAnalysis.RequiresUnreferencedCode("Cannot statically analyze the type of instance so its members may be trimmed")]
public static void Bind(this Microsoft.Extensions.Configuration.IConfiguration configuration, string key, object? instance);If .NET is in the same proverbial boat, what does .NET do to support trimming around IConfiguration?
Source generators, of course: Configuration-binding source generator.
Alas, the above docs are rather sparse on what it does and how it works:
// !! Configure call - to be replaced with source-gen'd implementation
builder.Services.Configure<MyOptions>(section);
// !! Get call - to be replaced with source-gen'd implementation
MyOptions? options0 = section.Get<MyOptions>();
// !! Bind call - to be replaced with source-gen'd implementation
MyOptions options1 = new();
section.Bind(options1);How are the calls "replaced with source-gem'd implementation"s?
It's something to explore.
Questions
- Do we need to care about these "originating" IL2026 and IL3050 warnings? uno.chefs appears to work even with these warnings, so they might not be a "real" problem (yet).
- Assuming we do care, how do we fix them? Using the Configuration-binding source generator looks like an interesting solution, but should other ideas be considered?
- Is it possible to "retcon" a solution atop
.Section<TSettingsOptions>()/etc.? If possible, this means we don't need to update existing assemblies to propagate a fix.
For which Platform:
- iOS
- Android
- WebAssembly
- WebAssembly renders for Xamarin.Forms
- Windows
- Build tasks