Skip to content

Commit 8d77130

Browse files
[NativeAOT] improve build logic, part 1 (#9614)
Introduce `$(_AndroidNativeAot)` to be used throughout a build to know if it is a NativeAOT build. The logic for detecting a NativeAOT build will likely change for Debug vs Release in the future. Skip generation of `mono.MonoRuntimeProvider` for NativeAOT and don't emit the value in `AndroidManifest.xml`. Update `Microsoft.Android.Sdk.NativeAOT.targets` to use `@(LinkerArg)` and `%(ResolvedFileToPublish.ArchiveFileName)` to ensure that the NativeAOT-generated native library has a `lib` prefix, as `System.loadLibrary("@name@")` only looks for `lib@[email protected]`. Update `BuildTest2.NativeAOT()` to ensure that the native library `libHello.so` is created, and that `classes.dex` does NOT contain `mono.MonoRuntimeProvider`.
1 parent 0d4c1cb commit 8d77130

File tree

9 files changed

+82
-10
lines changed

9 files changed

+82
-10
lines changed

src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/in/Microsoft.Android.Sdk.BundledVersions.in.targets

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ WARNING: DO NOT MODIFY this file unless you are knowledgeable about MSBuild and
2020
<_AndroidTargetingPackId Condition=" '$(_AndroidTargetingPackId)' != '$(_AndroidLatestStableApiLevel)' and '$(_AndroidTargetingPackId)' != '$(_AndroidLatestUnstableApiLevel)' ">$(_AndroidLatestStableApiLevel)</_AndroidTargetingPackId>
2121
<_AndroidRuntimePackId Condition=" '$(_AndroidRuntimePackId)' == '' ">$(_AndroidTargetingPackId)</_AndroidRuntimePackId>
2222
<_AndroidRuntimePackId Condition=" '$(_AndroidRuntimePackId)' != '$(_AndroidLatestStableApiLevel)' and '$(_AndroidRuntimePackId)' != '$(_AndroidLatestUnstableApiLevel)' ">$(_AndroidLatestStableApiLevel)</_AndroidRuntimePackId>
23-
<_AndroidRuntimePackRuntime Condition=" '$(PublishAot)' == 'true' ">NativeAOT</_AndroidRuntimePackRuntime>
2423
<_AndroidRuntimePackRuntime Condition=" '$(_AndroidRuntimePackRuntime)' == '' ">Mono</_AndroidRuntimePackRuntime>
2524
</PropertyGroup>
2625
<ItemGroup>

src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.DefaultProperties.targets

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,13 @@
2424
See: https://github.com/dotnet/sdk/blob/955c0fc7b06e2fa34bacd076ed39f61e4fb61716/src/Tasks/Microsoft.NET.Build.Tasks/targets/Microsoft.NET.Publish.targets#L16
2525
-->
2626
<_GetChildProjectCopyToPublishDirectoryItems>false</_GetChildProjectCopyToPublishDirectoryItems>
27-
<UseMonoRuntime Condition=" '$(PublishAot)' == 'true' and '$(UseMonoRuntime)' == '' ">false</UseMonoRuntime>
27+
<!-- Define a $(_AndroidNativeAot) property, as the logic detecting NativeAOT may change in the future -->
28+
<_AndroidNativeAot Condition=" '$(PublishAot)' == 'true' ">true</_AndroidNativeAot>
29+
<_AndroidNativeAot Condition=" '$(_AndroidNativeAot)' == '' ">false</_AndroidNativeAot>
30+
<UseMonoRuntime Condition=" '$(_AndroidNativeAot)' == 'true' and '$(UseMonoRuntime)' == '' ">false</UseMonoRuntime>
2831
<UseMonoRuntime Condition=" '$(UseMonoRuntime)' == '' ">true</UseMonoRuntime>
2932
<!-- HACK: make dotnet restore include Microsoft.NETCore.App.Runtime.NativeAOT.linux-bionic-arm64 -->
30-
<_IsPublishing Condition=" '$(_IsPublishing)' == '' and '$(PublishAot)' == 'true' ">true</_IsPublishing>
33+
<_IsPublishing Condition=" '$(_IsPublishing)' == '' and '$(_AndroidNativeAot)' == 'true' ">true</_IsPublishing>
3134

3235
<!-- Use $(AndroidMinimumSupportedApiLevel) for $(SupportedOSPlatformVersion) if unset -->
3336
<SupportedOSPlatformVersion Condition=" '$(SupportedOSPlatformVersion)' == '' ">$(AndroidMinimumSupportedApiLevel)</SupportedOSPlatformVersion>
@@ -94,7 +97,7 @@
9497
<RuntimeIdentifier Condition=" '$(RuntimeIdentifiers)' != '' And '$(RuntimeIdentifier)' != '' " />
9598
<GenerateApplicationManifest Condition=" '$(GenerateApplicationManifest)' == '' ">true</GenerateApplicationManifest>
9699
<!-- Default to Mono's AOT in Release mode -->
97-
<RunAOTCompilation Condition=" '$(RunAOTCompilation)' == '' and '$(AotAssemblies)' == '' and '$(Configuration)' == 'Release' and '$(PublishAot)' != 'true' ">true</RunAOTCompilation>
100+
<RunAOTCompilation Condition=" '$(RunAOTCompilation)' == '' and '$(AotAssemblies)' == '' and '$(Configuration)' == 'Release' and '$(_AndroidNativeAot)' != 'true' ">true</RunAOTCompilation>
98101
<RunAOTCompilation Condition=" '$(RunAOTCompilation)' == '' and '$(AotAssemblies)' == 'true' ">true</RunAOTCompilation>
99102
<RunAOTCompilation Condition=" '$(RunAOTCompilation)' == '' ">false</RunAOTCompilation>
100103
<_AndroidXA1029 Condition=" '$(AotAssemblies)' != '' ">true</_AndroidXA1029>

src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.NativeAOT.targets

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,11 @@ This file contains the NativeAOT-specific MSBuild logic for .NET for Android.
77
-->
88
<Project>
99

10+
<!-- Default property values for NativeAOT -->
11+
<PropertyGroup>
12+
<_AndroidRuntimePackRuntime>NativeAOT</_AndroidRuntimePackRuntime>
13+
</PropertyGroup>
14+
1015
<!-- Make IlcCompile depend on the trimmer -->
1116
<PropertyGroup>
1217
<IlcCompileDependsOn>
@@ -60,12 +65,17 @@ This file contains the NativeAOT-specific MSBuild logic for .NET for Android.
6065
<SuppressTrimAnalysisWarnings>$(_OriginalSuppressTrimAnalysisWarnings)</SuppressTrimAnalysisWarnings>
6166
</PropertyGroup>
6267
<ItemGroup>
68+
<!-- Android needs a proper soname property or it will refuse to load the library -->
69+
<LinkerArg Include="-Wl,-soname,lib$(TargetName)$(NativeBinaryExt)" />
6370
<!-- Give ILLink's output to ILC -->
6471
<IlcCompileInput Remove="@(IlcCompileInput)" />
6572
<IlcCompileInput Include="$(IntermediateLinkDir)$(TargetName)$(TargetExt)" />
73+
<_AndroidILLinkAssemblies Include="@(ManagedAssemblyToLink->'$(IntermediateLinkDir)%(Filename)%(Extension)')" Condition="Exists('$(IntermediateLinkDir)%(Filename)%(Extension)')" />
6674
<IlcReference Remove="@(IlcReference)" />
6775
<IlcReference Include="@(PrivateSdkAssemblies)" />
68-
<IlcReference Include="@(ManagedAssemblyToLink->'$(IntermediateLinkDir)%(Filename)%(Extension)')" Condition="Exists('$(IntermediateLinkDir)%(Filename)%(Extension)')" Exclude="@(IlcCompileInput)" />
76+
<IlcReference Include="@(_AndroidILLinkAssemblies)" />
77+
<!-- Passes linked assemblies to outer MSBuild tasks/targets -->
78+
<ResolvedFileToPublish Include="@(IlcCompileInput);@(_AndroidILLinkAssemblies)" RuntimeIdentifier="$(_OriginalRuntimeIdentifier)" />
6979
</ItemGroup>
7080
</Target>
7181

@@ -76,4 +86,11 @@ This file contains the NativeAOT-specific MSBuild logic for .NET for Android.
7686
</PropertyGroup>
7787
</Target>
7888

89+
<Target Name="_AndroidFixNativeLibraryFileName" AfterTargets="ComputeFilesToPublish">
90+
<ItemGroup>
91+
<!-- Fix paths to contain lib-prefix -->
92+
<ResolvedFileToPublish Update="@(ResolvedFileToPublish)" ArchiveFileName="lib%(FileName)%(Extension)" Condition=" '%(Filename)%(Extension)' == '$(TargetName)$(NativeBinaryExt)' " />
93+
</ItemGroup>
94+
</Target>
95+
7996
</Project>

src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.targets

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,6 @@
2727
<Import Project="Microsoft.Android.Sdk.DefaultProperties.targets" />
2828
<Import Project="$(MSBuildThisFileDirectory)..\tools\Xamarin.Android.Common.Debugging.props"
2929
Condition="Exists('$(MSBuildThisFileDirectory)..\tools\Xamarin.Android.Common.Debugging.props')"/>
30-
<Import Project="Microsoft.Android.Sdk.NativeAOT.targets" Condition=" '$(PublishAot)' == 'true' " />
30+
<Import Project="Microsoft.Android.Sdk.NativeAOT.targets" Condition=" '$(_AndroidNativeAot)' == 'true' " />
3131

3232
</Project>

src/Xamarin.Android.Build.Tasks/Tasks/GenerateJavaStubs.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,8 @@ public class GenerateJavaStubs : AndroidTask
9393
[Output]
9494
public ITaskItem[] GeneratedBinaryTypeMaps { get; set; }
9595

96+
public bool NativeAot { get; set; }
97+
9698
internal const string AndroidSkipJavaStubGeneration = "AndroidSkipJavaStubGeneration";
9799

98100
public override bool RunTask ()
@@ -294,6 +296,11 @@ Dictionary<string, ITaskItem> MaybeGetArchAssemblies (Dictionary<AndroidTargetAr
294296

295297
void GenerateAdditionalProviderSources (NativeCodeGenState codeGenState, IList<string> additionalProviders)
296298
{
299+
if (NativeAot) {
300+
Log.LogDebugMessage ("Skipping MonoRuntimeProvider generation for NativeAot");
301+
return;
302+
}
303+
297304
// Create additional runtime provider java sources.
298305
string providerTemplateFile = "MonoRuntimeProvider.Bundled.java";
299306
string providerTemplate = GetResource (providerTemplateFile);
@@ -347,6 +354,7 @@ IList<string> MergeManifest (NativeCodeGenState codeGenState, Dictionary<string,
347354
Debug = Debug,
348355
MultiDex = MultiDex,
349356
NeedsInternet = NeedsInternet,
357+
NativeAot = NativeAot,
350358
};
351359
// Only set manifest.VersionCode if there is no existing value in AndroidManifest.xml.
352360
if (manifest.HasVersionCode) {

src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/BuildTest2.cs

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,18 +115,49 @@ public void NativeAOT ()
115115
}
116116

117117
var proj = new XamarinAndroidApplicationProject {
118+
ProjectName = "Hello",
118119
IsRelease = true,
120+
RuntimeIdentifier = "android-arm64",
119121
// Add locally downloaded NativeAOT packs
120122
ExtraNuGetConfigSources = {
121123
Path.Combine (XABuildPaths.BuildOutputDirectory, "nuget-unsigned"),
122124
}
123125
};
124-
proj.SetRuntimeIdentifier ("arm64-v8a");
125126
proj.SetProperty ("PublishAot", "true");
126127
proj.SetProperty ("PublishAotUsingRuntimePack", "true");
128+
proj.SetProperty ("AndroidNdkDirectory", AndroidNdkPath);
127129

128130
using var b = CreateApkBuilder ();
129131
Assert.IsTrue (b.Build (proj), "Build should have succeeded.");
132+
133+
string [] mono_classes = [
134+
"Lmono/MonoRuntimeProvider;",
135+
];
136+
string[] mono_files = [
137+
"lib/arm64-v8a/libmonosgen-2.0.so",
138+
];
139+
string [] nativeaot_files = [
140+
$"lib/arm64-v8a/lib{proj.ProjectName}.so",
141+
];
142+
143+
var intermediate = Path.Combine (Root, b.ProjectDirectory, proj.IntermediateOutputPath, proj.RuntimeIdentifier);
144+
var output = Path.Combine (Root, b.ProjectDirectory, proj.OutputPath, proj.RuntimeIdentifier);
145+
146+
var dexFile = Path.Combine (intermediate, "android", "bin", "classes.dex");
147+
FileAssert.Exists (dexFile);
148+
foreach (var className in mono_classes) {
149+
Assert.IsFalse (DexUtils.ContainsClassWithMethod (className, "<init>", "()V", dexFile, AndroidSdkPath), $"`{dexFile}` should *not* include `{className}`!");
150+
}
151+
152+
var apkFile = Path.Combine (output, $"{proj.PackageName}-Signed.apk");
153+
FileAssert.Exists (apkFile);
154+
using var zip = ZipHelper.OpenZip (apkFile);
155+
foreach (var mono_file in mono_files) {
156+
Assert.IsFalse (zip.ContainsEntry (mono_file, caseSensitive: true), $"APK must *not* contain `{mono_file}`.");
157+
}
158+
foreach (var nativeaot_file in nativeaot_files) {
159+
Assert.IsTrue (zip.ContainsEntry (nativeaot_file, caseSensitive: true), $"APK must contain `{nativeaot_file}`.");
160+
}
130161
}
131162

132163
[Test]

src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Android/XamarinAndroidApplicationProject.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,11 @@ public bool UseJackAndJill {
134134
set { SetProperty (KnownProperties.UseJackAndJill, value.ToString ()); }
135135
}
136136

137+
public string RuntimeIdentifier {
138+
get { return GetProperty (KnownProperties.RuntimeIdentifier); }
139+
set { SetProperty (KnownProperties.RuntimeIdentifier, value); }
140+
}
141+
137142
public AndroidLinkMode AndroidLinkModeDebug {
138143
get {
139144
AndroidLinkMode m;

src/Xamarin.Android.Build.Tasks/Utilities/ManifestDocument.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ internal class ManifestDocument
9494
public bool ForceDebuggable { get; set; }
9595
public string VersionName { get; set; }
9696
public IVersionResolver VersionResolver { get; set; } = new MonoAndroidHelperVersionResolver ();
97+
public bool NativeAot { get; set; }
9798

9899
string versionCode;
99100

@@ -672,6 +673,11 @@ XElement CreateApplicationElement (XElement manifest, string applicationClass, L
672673

673674
IList<string> AddMonoRuntimeProviders (XElement app)
674675
{
676+
if (NativeAot) {
677+
//TODO: implement NativeAOT provider logic
678+
return [];
679+
}
680+
675681
app.Add (CreateMonoRuntimeProvider ("mono.MonoRuntimeProvider", null, --AppInitOrder));
676682

677683
var providerNames = new List<string> ();

src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -329,9 +329,9 @@ Copyright (C) 2011-2012 Xamarin. All rights reserved.
329329
<AndroidUseAssemblyStore Condition=" '$(AndroidUseAssemblyStore)' == '' ">true</AndroidUseAssemblyStore>
330330
<AndroidAotEnableLazyLoad Condition=" '$(AndroidAotEnableLazyLoad)' == '' And '$(AotAssemblies)' == 'true' And '$(AndroidIncludeDebugSymbols)' != 'true' ">True</AndroidAotEnableLazyLoad>
331331
<AndroidEnableMarshalMethods Condition=" '$(AndroidEnableMarshalMethods)' == '' and ('$(UsingMicrosoftNETSdkRazor)' == 'true') ">False</AndroidEnableMarshalMethods>
332-
<AndroidEnableMarshalMethods Condition=" '$(AndroidEnableMarshalMethods)' == '' and '$(PublishAot)' != 'true' ">True</AndroidEnableMarshalMethods>
332+
<AndroidEnableMarshalMethods Condition=" '$(AndroidEnableMarshalMethods)' == '' and '$(_AndroidNativeAot)' != 'true' ">True</AndroidEnableMarshalMethods>
333333
<!-- NOTE: temporarily disable for NativeAOT for now, to get build passing -->
334-
<AndroidEnableMarshalMethods Condition=" '$(AndroidEnableMarshalMethods)' == '' and '$(PublishAot)' == 'true' ">False</AndroidEnableMarshalMethods>
334+
<AndroidEnableMarshalMethods Condition=" '$(AndroidEnableMarshalMethods)' == '' and '$(_AndroidNativeAot)' == 'true' ">False</AndroidEnableMarshalMethods>
335335
<_AndroidUseMarshalMethods Condition=" '$(AndroidIncludeDebugSymbols)' == 'True' ">False</_AndroidUseMarshalMethods>
336336
<_AndroidUseMarshalMethods Condition=" '$(AndroidIncludeDebugSymbols)' != 'True' ">$(AndroidEnableMarshalMethods)</_AndroidUseMarshalMethods>
337337
</PropertyGroup>
@@ -1379,6 +1379,7 @@ because xbuild doesn't support framework reference assemblies.
13791379
DependsOnTargets="_CollectRuntimeJarFilenames;$(_BeforeAddStaticResources);_GetMonoPlatformJarPath">
13801380
<CopyResource ResourceName="machine.config" OutputPath="$(MonoAndroidIntermediateAssemblyDir)machine.config" />
13811381
<CopyResource
1382+
Condition=" '$(_AndroidNativeAot)' != 'true' "
13821383
ResourceName="MonoRuntimeProvider.Bundled.java"
13831384
OutputPath="$(_AndroidIntermediateJavaSourceDirectory)mono\MonoRuntimeProvider.java"
13841385
/>
@@ -1497,6 +1498,7 @@ because xbuild doesn't support framework reference assemblies.
14971498
</ItemGroup>
14981499

14991500
<GenerateJavaStubs
1501+
NativeAot="$(_AndroidNativeAot)"
15001502
ResolvedAssemblies="@(_ResolvedAssemblies)"
15011503
ResolvedUserAssemblies="@(_ResolvedUserMonoAndroidAssemblies)"
15021504
ErrorOnCustomJavaObject="$(AndroidErrorOnCustomJavaObject)"
@@ -1726,6 +1728,7 @@ because xbuild doesn't support framework reference assemblies.
17261728
</Target>
17271729

17281730
<Target Name="_GeneratePackageManagerJava"
1731+
Condition=" '$(_AndroidNativeAot)' != 'true' "
17291732
DependsOnTargets="$(_GeneratePackageManagerJavaDependsOn)"
17301733
Inputs="@(_GeneratePackageManagerJavaInputs)"
17311734
Outputs="$(_AndroidStampDirectory)_GeneratePackageManagerJava.stamp">
@@ -1944,7 +1947,7 @@ because xbuild doesn't support framework reference assemblies.
19441947

19451948
<!-- Shrink Mono.Android.dll by removing attribute only needed for GenerateJavaStubs -->
19461949
<RemoveRegisterAttribute
1947-
Condition="'$(AndroidLinkMode)' != 'None' and '$(AndroidIncludeDebugSymbols)' != 'true' and '$(AndroidStripILAfterAOT)' != 'true' and '$(PublishAot)' != 'true' "
1950+
Condition="'$(AndroidLinkMode)' != 'None' and '$(AndroidIncludeDebugSymbols)' != 'true' and '$(AndroidStripILAfterAOT)' != 'true' and '$(_AndroidNativeAot)' != 'true' "
19481951
ShrunkFrameworkAssemblies="@(_ShrunkAssemblies)" />
19491952

19501953
<MakeDir Directories="$(MonoAndroidIntermediateAssemblyDir)shrunk" />

0 commit comments

Comments
 (0)