Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[Xamarin.Android.Build.Tasks] add $(AndroidStripILAfterAOT) (#8172)
Context: xamarin/monodroid@388bf4b Context: 59ec488 Context: c929289 Context: 88215f9 Context: dotnet/runtime#86722 Context: dotnet/runtime#44855 Once Upon A Time™ we had a brilliant thought: if AOT pre-compiles C# methods, do we need the managed method anymore? Removing the C# method body would allow assemblies to be smaller. ("Even better", iOS does this too! Why Can't Android™?!) While the idea is straightforward, implementation was not: iOS uses ["Full" AOT][0], which AOT's *all* methods into a form that doesn't require a runtime JIT. This allowed iOS to run [`cil-strip`][1], removing all method bodies from all managed types. At the time, Xamarin.Android only supported "normal" AOT, and normal AOT requires a JIT for certain constructs such as generic types and generic methods. This meant that attempting to run `cil-strip` would result in runtime errors if a method body was removed that was actually required at runtime. (This was particularly bad because `cil-strip` could only remove *all* method bodies, not some!) This limitation was relaxed with the introduction of "Hybrid" AOT, which is "Full AOT while supporting a JIT". This meant that *all* methods could be AOT'd without requiring a JIT, which allowed method bodies to be removed; see xamarin/monodroid@388bf4b3. Unfortunately, this wasn't a great long-term solution: 1. Hybrid AOT was restricted to Visual Studio Enterprise customers. 2. Enabling Hybrid AOT would slow down Release configuration builds. 3. Hybrid AOT would result in larger apps. 4. As a consequence of (1), it didn't get as much testing 5. `cil-strip` usage was dropped as part of the .NET 5+ migration (c929289) Re-intoduce IL stripping for .NET 8. Add a new `$(AndroidStripILAfterAOT)` MSBuild property. When true, the `<MonoAOTCompiler/>` task will track which method bodies were actually AOT'd, storing this information into `%(_MonoAOTCompiledAssemblies.MethodTokenFile)`, and the new `<ILStrip/>` task will update the input assemblies, removing all method bodies that can be removed. By default setting `$(AndroidStripILAfterAOT)`=true will *override* the default `$(AndroidEnableProfiledAot)` setting, allowing all trimmable AOT'd methods to be removed. Profiled AOT and IL stripping can be used together by explicitly setting both within the `.csproj`: <PropertyGroup> <AndroidStripILAfterAOT>true</AndroidStripILAfterAOT> <AndroidEnableProfiledAot>true</AndroidEnableProfiledAot> </PropertyGroup> `.apk` size results for a `dotnet new android` app: | `$(AndroidStripILAfterAOT)` | `$(AndroidEnableProfiledAot)` | `.apk` size | | --------------------------- | ----------------------------- | ------------- | | true | true | 7.7MB | | true | false | 8.1MB | | false | true | 7.7MB | | false | false | 8.4MB | Note that `$(AndroidStripILAfterAOT)`=false and `$(AndroidEnableProfiledAot)`=true is the *default* Release configuration environment, for 7.7MB. A project that *only* sets `$(AndroidStripILAfterAOT)`=true implicitly sets `$(AndroidEnableProfiledAot)`=false, resulting in an 8.1MB app. Co-authored-by: Fan Yang <yangfan@microsoft.com> [0]: https://www.mono-project.com/docs/advanced/aot/#full-aot [1]: https://github.com/mono/mono/tree/2020-02/mcs/tools/cil-strip
- Loading branch information