dotnet/sdk

Add support for root assembly trimming mode

jeromelaban opened this issue · 2 comments

Is your feature request related to a problem? Please describe.

With the rise of source generators, and syntactic sugar like record, a lot of code is being generated that may not be required by an app. This code may end up being in the main assembly, and this assembly is not currently eligible for trimming, as its mode passed to the ILLinker is set to copy, therefore disabling general trimming, but also more importantly feature substitutions.

There's one workaround that can be applied to change the "root assembly" trimming mode (based on this piece of code):

	<Target Name="_AdjustILLinkParameters" AfterTargets="PrepareForILLink">
		<ItemGroup>
			<TrimmerRootAssembly Update="@(TrimmerRootAssembly)" RootMode="library" />
		</ItemGroup>
	</Target>

Yet an official solution would be more appropriate.

Describe the solution you'd like

In a similar way <TrimMode>copyused</TrimMode> can be used, something like <TrimRootAssemblyMode>library</TrimRootAssemblyMode>, following the modes provided by ILLink: default, all, visible, entrypoint and library.

Additional context

Note that this feature is particularly important in the case of iOS, Android, Catalyst and macOS.

While moving the code to a separate assembly could remove this "root assembly" issue, Visual Studio does not does not support partial build of multi-targeted assemblies. This causes dependent projects (while the main assembly only builds one target framework) to build the full set of target frameworks, a very expensive operation slowing down the dev inner loop.

In .NET 7 we've made changes to this:

  • Introduced "better" names for the TrimMode - you can specify TrimMode=partial (matches the existing behavior), or TrimMode=full which will trim all assemblies.
  • Changed the default for console apps to TrimMode=full

That said, for Xamarin/MAUI/Blazor apps, it's potentially problematic to turn on full trimming as it's much more likely to break the app. These modes disable trim warnings (SuppressTrimAnalysisWarnings) and with it they make guesses as to what needs to be kept around to make the app work. But these are just guesses. (Unlike console apps which show trim warnings by default).

Also - the library mode is not something we support externally (at least yet). It changes the behavior of the trimmer in many different (and often subtle) ways, and it's not tested in scenarios like the one you propose. Its effectiveness in reducing the size of the app is also questionable (it will root all public types/APIs, so it depends on the specific app if it uses public types or not).

If entrypoint trimming of the root assembly is acceptable, you can also set <IsTrimmable>true</IsTrimmable> which should result in it being trimmed even with TrimMode=partial.