From e3fb10978dbb0d0ef5599415378a677dd11c43ca Mon Sep 17 00:00:00 2001 From: Jonathan Peppers Date: Wed, 18 Dec 2024 13:42:52 -0600 Subject: [PATCH] [NativeAOT] improve build logic, part 2 This is another set of changes to Android apps to *run* under NativeAOT: * Default to `$(TrimMode)=Full` for NativeAOT, this enables trimmer warnings and should be the default mode for NativeAOT. * Ensure `_PrepareLinking` MSBuild target runs at the appropriate time. This was causing `Android.App.Activity`'s `GetOnCreate_Landroid_os_Bundle_Handler()` to get trimmed away. * Default to `$(LinkerFlavor)=lld` to avoid a `java.lang.UnsatisfiedLinkError` at runtime. * Include `libc++_shared.so` to avoid a `java.lang.UnsatisfiedLinkError` at runtime. * Emit `JavaPeerStyle.JavaInterop1` java stubs for NativeAOT, as it is easier to get working in place of `JavaPeerStyle.XAJavaInterop1`. I updated our existing `NativeAOT()` to assert for these changes where possible. --- .../Microsoft.Android.Sdk.DefaultProperties.targets | 2 +- .../targets/Microsoft.Android.Sdk.NativeAOT.targets | 10 ++++++++-- .../Tasks/GenerateJavaStubs.cs | 4 +++- .../Tests/Xamarin.Android.Build.Tests/BuildTest2.cs | 13 +++++++++++++ .../Utilities/JCWGenerator.cs | 4 +++- 5 files changed, 28 insertions(+), 5 deletions(-) diff --git a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.DefaultProperties.targets b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.DefaultProperties.targets index d4e0572ee41..fd91967d398 100644 --- a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.DefaultProperties.targets +++ b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.DefaultProperties.targets @@ -88,7 +88,7 @@ SdkOnly None - full + full partial false true diff --git a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.NativeAOT.targets b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.NativeAOT.targets index 8f0d03ac750..868a8fa9f19 100644 --- a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.NativeAOT.targets +++ b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.NativeAOT.targets @@ -25,7 +25,9 @@ This file contains the NativeAOT-specific MSBuild logic for .NET for Android. - + <_NdkSysrootAbi>aarch64-linux-android @@ -33,7 +35,7 @@ This file contains the NativeAOT-specific MSBuild logic for .NET for Android. <_NdkPrebuiltAbi Condition=" $([MSBuild]::IsOSPlatform('windows')) ">windows-x86_64 <_NdkPrebuiltAbi Condition=" $([MSBuild]::IsOSPlatform('osx')) ">darwin-x86_64 <_NdkPrebuiltAbi Condition=" $([MSBuild]::IsOSPlatform('linux')) ">linux-x86_64 - <_NdkSysrootDir>$(_AndroidNdkDirectory)toolchains/llvm/prebuilt/$(_NdkPrebuiltAbi)/sysroot/usr/lib/$(_NdkSysrootAbi) + <_NdkSysrootDir>$(_AndroidNdkDirectory)toolchains/llvm/prebuilt/$(_NdkPrebuiltAbi)/sysroot/usr/lib/$(_NdkSysrootAbi)/ <_NdkBinDir>$(_AndroidNdkDirectory)toolchains/llvm/prebuilt/$(_NdkPrebuiltAbi)/bin/ $(_NdkBinDir)$(_NdkClangPrefix)clang++ $(CppCompilerAndLinker) @@ -56,6 +58,8 @@ This file contains the NativeAOT-specific MSBuild logic for .NET for Android. <_targetOS>linux <_linuxLibcFlavor>bionic + + lld @@ -76,6 +80,8 @@ This file contains the NativeAOT-specific MSBuild logic for .NET for Android. + + diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/GenerateJavaStubs.cs b/src/Xamarin.Android.Build.Tasks/Tasks/GenerateJavaStubs.cs index 18b5543e252..b1ae8f6f750 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/GenerateJavaStubs.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/GenerateJavaStubs.cs @@ -387,7 +387,9 @@ IList MergeManifest (NativeCodeGenState codeGenState, Dictionary allJavaTypes, List javaTypesForJCW) = ScanForJavaTypes (resolver, tdCache, assemblies, userAssemblies, useMarshalMethods); var jcwContext = new JCWGeneratorContext (arch, resolver, assemblies.Values, javaTypesForJCW, tdCache, useMarshalMethods); - var jcwGenerator = new JCWGenerator (Log, jcwContext); + var jcwGenerator = new JCWGenerator (Log, jcwContext) { + NativeAot = NativeAot, + }; bool success; if (generateJavaCode) { diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/BuildTest2.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/BuildTest2.cs index a244bfb060b..4eb45aeeae4 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/BuildTest2.cs +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/BuildTest2.cs @@ -129,6 +129,7 @@ public void NativeAOT () using var b = CreateApkBuilder (); Assert.IsTrue (b.Build (proj), "Build should have succeeded."); + b.Output.AssertTargetIsNotSkipped ("_PrepareLinking"); string [] mono_classes = [ "Lmono/MonoRuntimeProvider;", @@ -138,11 +139,23 @@ public void NativeAOT () ]; string [] nativeaot_files = [ $"lib/arm64-v8a/lib{proj.ProjectName}.so", + "lib/arm64-v8a/libc++_shared.so", ]; var intermediate = Path.Combine (Root, b.ProjectDirectory, proj.IntermediateOutputPath, proj.RuntimeIdentifier); var output = Path.Combine (Root, b.ProjectDirectory, proj.OutputPath, proj.RuntimeIdentifier); + var linkedMonoAndroidAssembly = Path.Combine (intermediate, "linked", "Mono.Android.dll"); + FileAssert.Exists (linkedMonoAndroidAssembly); + using (var assembly = AssemblyDefinition.ReadAssembly (linkedMonoAndroidAssembly)) { + var typeName = "Android.App.Activity"; + var methodName = "GetOnCreate_Landroid_os_Bundle_Handler"; + var type = assembly.MainModule.GetType (typeName); + Assert.IsNotNull (type, $"{linkedMonoAndroidAssembly} should contain {typeName}"); + var method = type.Methods.FirstOrDefault (m => m.Name == methodName); + Assert.IsNotNull (method, $"{linkedMonoAndroidAssembly} should contain {typeName}.{methodName}"); + } + var dexFile = Path.Combine (intermediate, "android", "bin", "classes.dex"); FileAssert.Exists (dexFile); foreach (var className in mono_classes) { diff --git a/src/Xamarin.Android.Build.Tasks/Utilities/JCWGenerator.cs b/src/Xamarin.Android.Build.Tasks/Utilities/JCWGenerator.cs index 97050698cc1..ba9e9bde3a5 100644 --- a/src/Xamarin.Android.Build.Tasks/Utilities/JCWGenerator.cs +++ b/src/Xamarin.Android.Build.Tasks/Utilities/JCWGenerator.cs @@ -44,6 +44,8 @@ class JCWGenerator readonly TaskLoggingHelper log; readonly JCWGeneratorContext context; + public bool NativeAot { get; set; } + public MarshalMethodsClassifier? Classifier { get; private set; } public JCWGenerator (TaskLoggingHelper log, JCWGeneratorContext context) @@ -125,7 +127,7 @@ bool GenerateCode (CallableWrapperType generator, TypeDefinition type, string ou bool ok = true; using var writer = MemoryStreamPool.Shared.CreateStreamWriter (); var writer_options = new CallableWrapperWriterOptions { - CodeGenerationTarget = JavaPeerStyle.XAJavaInterop1 + CodeGenerationTarget = NativeAot ? JavaPeerStyle.JavaInterop1 : JavaPeerStyle.XAJavaInterop1 }; try {