Skip to content

Commit

Permalink
[One .NET] AOT support
Browse files Browse the repository at this point in the history
Helpful reading:

* https://github.com/dotnet/runtime/blob/15dec9a2aa5a4236d6ba70de2e9c146867b9d2e0/src/tasks/AotCompilerTask/MonoAOTCompiler.cs
* https://github.com/dotnet/runtime/blob/15dec9a2aa5a4236d6ba70de2e9c146867b9d2e0/src/mono/netcore/nuget/Microsoft.NET.Runtime.MonoAOTCompiler.Task/README.md

To make this work, I moved the existing `<Aot/>` MSBuild task calls to
a new `_AndroidAot` MSBuild target in `Xamarin.Android.Legacy.targets`.

In the .NET 6 targets, there is a *different* `_AndroidAot` MSBuild
target that runs the new `<MonoAOTCompiler/>` MSBuild task. The
`_AndroidAot` target runs per `$(RuntimeIdentifier)` after the linker
completes. Native libraries are added to the
`@(ResolvedFileToPublish)` item group to be included in the final
`.apk`.

To follow convention with Blazor WASM:

https://devblogs.microsoft.com/aspnet/asp-net-core-updates-in-net-6-preview-4/#blazor-webassembly-ahead-of-time-aot-compilation

The `$(RunAOTCompilation)` MSBuild property enables AOT. To help with
backwards compatibility with "legacy" Xamarin.Android, I kept the
`$(AotAssemblies)` MSBuild property intact.

Unfortunately, we have to manually import things to support
`$(AotAssemblies)`:

    <ImportGroup Condition=" '$(MonoAOTCompilerTasksAssemblyPath)' == '' and '$(AotAssemblies)' == 'true' ">
      <Import Project="Sdk.props" Sdk="Microsoft.NET.Runtime.MonoAOTCompiler.Task" />
      <Import Project="Sdk.props" Sdk="Microsoft.NETCore.App.Runtime.AOT.Cross.android-x86" />
      <Import Project="Sdk.props" Sdk="Microsoft.NETCore.App.Runtime.AOT.Cross.android-x64" />
      <Import Project="Sdk.props" Sdk="Microsoft.NETCore.App.Runtime.AOT.Cross.android-arm" />
      <Import Project="Sdk.props" Sdk="Microsoft.NETCore.App.Runtime.AOT.Cross.android-arm64" />
    </ImportGroup>

Since, the default Mono workload does not support `$(AotAssemblies)`:

https://github.com/dotnet/runtime/blob/69711860262e44458bbe276393ea3eb9f7a2192a/src/mono/nuget/Microsoft.NET.Workload.Mono.Toolchain.Manifest/WorkloadManifest.targets.in#L20-L25

I think this is reasonable for now.

~~ Results ~~

All tests were running on a Pixel 5.

Using the HelloAndroid app:

https://github.com/dotnet/maui-samples/tree/main/HelloAndroid

Defaults to two architectures: arm64 and x86

Average of 10 runs with `-c Release` and no AOT:

    Activity: Displayed     00:00:00.308

Apk size: 8367969

Average of 10 runs with `-c Release -p:RunAOTCompilation=true`:

    Activity: Displayed     00:00:00.209

Apk size: 12082123

Using the HelloMaui app:

https://github.com/dotnet/maui-samples/tree/main/HelloMaui

Defaults to two architectures: arm64 and x86

Average of 10 runs with `-c Release` and no AOT:

    Activity: Displayed     00:00:01.117

Apk size: 16272964

Average of 10 runs with `-c Release -p:RunAOTCompilation=true`:

    Activity: Displayed     00:00:00.568

Apk size: 42869016
  • Loading branch information
jonathanpeppers committed Jul 27, 2021
1 parent 2ead7f4 commit 252e3b9
Show file tree
Hide file tree
Showing 18 changed files with 539 additions and 262 deletions.
12 changes: 12 additions & 0 deletions Documentation/guides/OneDotNet.md
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,18 @@ It is recommended to migrate to the new linker settings, as
[linker]: https://docs.microsoft.com/dotnet/core/deploying/trimming-options
[linker-full]: https://docs.microsoft.com/dotnet/core/deploying/trimming-options#trimmed-assemblies

## AOT

`$(RunAOTCompilation)` will be the new MSBuild property for enabling
AOT. This is the same property used for [Blazor WASM][blazor].
`$(AotAssemblies)` will also enable AOT, in order to help with
migration from "legacy" Xamarin.Android to .NET 6.

It is recommended to migrate to the new `$(RunAOTCompilation)`
property, as `$(AotAssemblies)` will eventually be deprecated.

[blazor]: https://devblogs.microsoft.com/aspnet/asp-net-core-updates-in-net-6-preview-4/#blazor-webassembly-ahead-of-time-aot-compilation

## dotnet cli

There are currently a few "verbs" we are aiming to get working in
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,10 @@ public override bool Execute ()
writer.WriteAttributeString ("Condition", " '$(TargetPlatformVersion)' == '' ");
writer.WriteString (versions.MaxStableVersion.ApiLevel.ToString ("0.0", CultureInfo.InvariantCulture));
writer.WriteEndElement (); // </TargetPlatformVersion>
writer.WriteStartElement ("AndroidMinimumSupportedApiLevel");
writer.WriteAttributeString ("Condition", " '$(AndroidMinimumSupportedApiLevel)' == '' ");
writer.WriteString (MinimumApiLevel.ToString ());
writer.WriteEndElement (); // </AndroidMinimumSupportedApiLevel>
writer.WriteEndElement (); // </PropertyGroup>

writer.WriteStartElement ("ItemGroup");
Expand Down
14 changes: 13 additions & 1 deletion build-tools/automation/azure-pipelines.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ variables:
# - This is a non-fork branch with name containing "mono-" (for Mono bumps)
IsMonoBranch: $[and(ne(variables['System.PullRequest.IsFork'], 'True'), or(contains(variables['Build.SourceBranchName'], 'mono-'), contains(variables['System.PullRequest.SourceBranch'], 'mono-')))]
RunAllTests: $[or(eq(variables['XA.RunAllTests'], true), eq(variables['IsMonoBranch'], true))]
DotNetNUnitCategories: '& TestCategory != DotNetIgnore & TestCategory != AOT & TestCategory != MkBundle & TestCategory != MonoSymbolicate & TestCategory != PackagesConfig & TestCategory != StaticProject & TestCategory != Debugger & TestCategory != SystemApplication'
DotNetNUnitCategories: '& TestCategory != DotNetIgnore & TestCategory != HybridAOT & TestCategory != ProfiledAOT & TestCategory != LLVM & TestCategory != MkBundle & TestCategory != MonoSymbolicate & TestCategory != PackagesConfig & TestCategory != StaticProject & TestCategory != Debugger & TestCategory != SystemApplication'
NUnit.NumberOfTestWorkers: 4
GitHub.Token: $(github--pat--vs-mobiletools-engineering-service2)
CONVERT_JAVADOC_TO_XMLDOC: $[ne(variables['Build.DefinitionName'], 'Xamarin.Android-PR')]
Expand Down Expand Up @@ -798,6 +798,18 @@ stages:
artifactFolder: net6-Interpreter
useDotNet: true

- template: yaml-templates/apk-instrumentation.yaml
parameters:
configuration: $(XA.Build.Configuration)
testName: Mono.Android.NET_Tests-Aot
project: tests/Mono.Android-Tests/Runtime-Microsoft.Android.Sdk/Mono.Android.NET-Tests.csproj
testResultsFiles: TestResult-Mono.Android.NET_Tests-$(XA.Build.Configuration)-Aot.xml
# InetAccess excluded due to: https://github.com/dotnet/runtime/issues/56315
extraBuildArgs: /p:RunAOTCompilation=true /p:ExcludeCategories=InetAccess
artifactSource: bin/Test$(XA.Build.Configuration)/net6.0-android/Mono.Android.NET_Tests-Signed.apk
artifactFolder: net6-aot
useDotNet: true

- task: MSBuild@1
displayName: shut down emulator
inputs:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ This file is imported *after* the Microsoft.NET.Sdk/Sdk.targets.
<Import Project="..\tools\Xamarin.Android.Bindings.Core.targets" />
<Import Project="..\tools\Xamarin.Android.Bindings.ClassParse.targets" />
<Import Project="Microsoft.Android.Sdk.AndroidLibraries.targets" />
<Import Project="Microsoft.Android.Sdk.Aot.targets" Condition=" '$(AndroidApplication)' == 'true' " />
<Import Project="Microsoft.Android.Sdk.Application.targets" Condition=" '$(AndroidApplication)' == 'true' " />
<Import Project="Microsoft.Android.Sdk.AssemblyResolution.targets" />
<Import Project="Microsoft.Android.Sdk.ILLink.targets" />
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
<!--
***********************************************************************************************
Microsoft.Android.Sdk.Aot.targets
.NET 6 AOT support. You can find "legacy" Xamarin.Android AOT support
in Xamarin.Android.Legacy.targets.
For <MonoAOTCompiler/> usage, see:
* https://github.com/dotnet/runtime/blob/15dec9a2aa5a4236d6ba70de2e9c146867b9d2e0/src/tasks/AotCompilerTask/MonoAOTCompiler.cs
* https://github.com/dotnet/runtime/blob/15dec9a2aa5a4236d6ba70de2e9c146867b9d2e0/src/mono/netcore/nuget/Microsoft.NET.Runtime.MonoAOTCompiler.Task/README.md
These targets are running within the _ComputeFilesToPublishForRuntimeIdentifiers target.
They run in a context of an inner build with a single $(RuntimeIdentifier).
***********************************************************************************************
-->
<Project>

<!--
NOTE: currently, the only way to allow $(AotAssemblies) in
.csproj files is to import these in the Android workload
when $(MonoAOTCompilerTasksAssemblyPath) is blank:
https://github.com/dotnet/runtime/blob/69711860262e44458bbe276393ea3eb9f7a2192a/src/mono/nuget/Microsoft.NET.Workload.Mono.Toolchain.Manifest/WorkloadManifest.targets.in#L20-L25
-->
<ImportGroup Condition=" '$(MonoAOTCompilerTasksAssemblyPath)' == '' and '$(AotAssemblies)' == 'true' ">
<Import Project="Sdk.props" Sdk="Microsoft.NET.Runtime.MonoAOTCompiler.Task" />
<Import Project="Sdk.props" Sdk="Microsoft.NETCore.App.Runtime.AOT.Cross.android-x86" />
<Import Project="Sdk.props" Sdk="Microsoft.NETCore.App.Runtime.AOT.Cross.android-x64" />
<Import Project="Sdk.props" Sdk="Microsoft.NETCore.App.Runtime.AOT.Cross.android-arm" />
<Import Project="Sdk.props" Sdk="Microsoft.NETCore.App.Runtime.AOT.Cross.android-arm64" />
</ImportGroup>

<UsingTask TaskName="Xamarin.Android.Tasks.GetAotArguments" AssemblyFile="$(_XamarinAndroidBuildTasksAssembly)" />

<Target Name="_AndroidAotInputs">
<ItemGroup>
<_AndroidAotInputs Include="@(ResolvedFileToPublish)" Condition=" '%(Extension)' == '.dll' " />
</ItemGroup>
</Target>

<Target Name="_AndroidAot"
Condition=" '$(AotAssemblies)' == 'true' and '$(RuntimeIdentifier)' != '' "
DependsOnTargets="_AndroidAotInputs"
Inputs="@(_AndroidAotInputs)"
Outputs="$(_AndroidStampDirectory)_AndroidAot.stamp">
<GetAotArguments
AndroidAotMode="$(AndroidAotMode)"
AndroidNdkDirectory="$(_AndroidNdkDirectory)"
AndroidBinUtilsDirectory="$(AndroidBinUtilsDirectory)"
AndroidApiLevel="$(_AndroidApiLevel)"
MinimumSupportedApiLevel="$(AndroidMinimumSupportedApiLevel)"
AndroidSequencePointsMode="$(_SequencePointsMode)"
AotAdditionalArguments="$(AndroidAotAdditionalArguments)"
AotOutputDirectory="$(_AndroidAotBinDirectory)"
RuntimeIdentifier="$(RuntimeIdentifier)"
EnableLLVM="$(EnableLLVM)"
Profiles="@(_AotProfiles)">
<Output PropertyName="_AotArguments" TaskParameter="Arguments" />
<Output PropertyName="_LLVMPath" TaskParameter="LLVMPath" />
</GetAotArguments>
<ItemGroup>
<_MonoAOTAssemblies Include="@(_AndroidAotInputs->'%(FullPath)')" AotArguments="$(_AotArguments)" />
</ItemGroup>
<MakeDir Directories="$(IntermediateOutputPath)aot\" />
<MonoAOTCompiler
Assemblies="@(_MonoAOTAssemblies)"
CompilerBinaryPath="@(MonoAotCrossCompiler->WithMetadataValue('RuntimeIdentifier', '$(RuntimeIdentifier)'))"
DisableParallelAot="$(_DisableParallelAot)"
LibraryFormat="So"
Mode="$(AndroidAotMode)"
OutputDir="$(IntermediateOutputPath)aot\"
OutputType="Library"
UseAotDataFile="false"
UseLLVM="$(EnableLLVM)"
LLVMPath="$(_LLVMPath)">
<Output TaskParameter="CompiledAssemblies" ItemName="_AotCompiledAssemblies" />
<Output TaskParameter="FileWrites" ItemName="FileWrites" />
</MonoAOTCompiler>
<Touch Files="$(_AndroidStampDirectory)_AndroidAot.stamp" AlwaysCreate="true" />
<ItemGroup>
<ResolvedFileToPublish
Include="@(_AotCompiledAssemblies->'%(LibraryFile)')"
ArchiveFileName="libaot-$([System.IO.Path]::GetFileNameWithoutExtension('%(_AotCompiledAssemblies.LibraryFile)')).so"
/>
</ItemGroup>
</Target>
</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ _ResolveAssemblies MSBuild target.
</PropertyGroup>

<Target Name="_ComputeFilesToPublishForRuntimeIdentifiers"
DependsOnTargets="_FixupIntermediateAssembly;ResolveReferences;ComputeFilesToPublish"
DependsOnTargets="_FixupIntermediateAssembly;ResolveReferences;ComputeFilesToPublish;_AndroidAot"
Returns="@(ResolvedFileToPublish)">
<ItemGroup>
<ResolvedFileToPublish
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,9 @@
<AndroidManifest Condition=" '$(AndroidManifest)' == '' and Exists ('Properties\AndroidManifest.xml') and !Exists ('AndroidManifest.xml') ">Properties\AndroidManifest.xml</AndroidManifest>
<AndroidManifest Condition=" '$(AndroidManifest)' == '' ">AndroidManifest.xml</AndroidManifest>
<GenerateApplicationManifest Condition=" '$(GenerateApplicationManifest)' == '' ">true</GenerateApplicationManifest>
<RunAOTCompilation Condition=" '$(RunAOTCompilation)' == '' and '$(AotAssemblies)' == 'true' ">true</RunAOTCompilation>
<RunAOTCompilation Condition=" '$(RunAOTCompilation)' == '' ">false</RunAOTCompilation>
<AotAssemblies>$(RunAOTCompilation)</AotAssemblies>

<!--
Runtime libraries feature switches defaults
Expand Down

0 comments on commit 252e3b9

Please sign in to comment.