Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ WARNING: DO NOT MODIFY this file unless you are knowledgeable about MSBuild and
<_AndroidTargetingPackId Condition=" '$(_AndroidTargetingPackId)' != '$(_AndroidLatestStableApiLevel)' and '$(_AndroidTargetingPackId)' != '$(_AndroidLatestUnstableApiLevel)' ">$(_AndroidLatestStableApiLevel)</_AndroidTargetingPackId>
<_AndroidRuntimePackId Condition=" '$(_AndroidRuntimePackId)' == '' ">$(_AndroidTargetingPackId)</_AndroidRuntimePackId>
<_AndroidRuntimePackId Condition=" '$(_AndroidRuntimePackId)' != '$(_AndroidLatestStableApiLevel)' and '$(_AndroidRuntimePackId)' != '$(_AndroidLatestUnstableApiLevel)' ">$(_AndroidLatestStableApiLevel)</_AndroidRuntimePackId>
<_AndroidRuntimePackRuntime Condition=" '$(PublishAot)' == 'true' ">NativeAOT</_AndroidRuntimePackRuntime>
<_AndroidRuntimePackRuntime Condition=" '$(_AndroidRuntimePackRuntime)' == '' ">Mono</_AndroidRuntimePackRuntime>
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is now set in Microsoft.Android.Sdk.NativeAOT.targets.

</PropertyGroup>
<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,13 @@
See: https://github.com/dotnet/sdk/blob/955c0fc7b06e2fa34bacd076ed39f61e4fb61716/src/Tasks/Microsoft.NET.Build.Tasks/targets/Microsoft.NET.Publish.targets#L16
-->
<_GetChildProjectCopyToPublishDirectoryItems>false</_GetChildProjectCopyToPublishDirectoryItems>
<UseMonoRuntime Condition=" '$(PublishAot)' == 'true' and '$(UseMonoRuntime)' == '' ">false</UseMonoRuntime>
<!-- Define a $(_AndroidNativeAot) property, as the logic detecting NativeAOT may change in the future -->
<_AndroidNativeAot Condition=" '$(PublishAot)' == 'true' ">true</_AndroidNativeAot>
<_AndroidNativeAot Condition=" '$(_AndroidNativeAot)' == '' ">false</_AndroidNativeAot>
<UseMonoRuntime Condition=" '$(_AndroidNativeAot)' == 'true' and '$(UseMonoRuntime)' == '' ">false</UseMonoRuntime>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What happens/what should happen when $(PublishAot)=true and $(UseMonoRuntime)=true? As $(UseMonoRuntime) is a public property, there is potential expectation that users could do this, so what should happen?

Perhaps we should warn?

Copy link
Member Author

@jonathanpeppers jonathanpeppers Dec 16, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Customers usually would not set $(UseMonoRuntime), but they would set $(PublishAot) to opt into NativeAOT.

iOS has the following logic in .NET 9, that is up for discussion:

  • dotnet build uses Mono, unless you specify -p:_IsPublishing=true
  • dotnet publish uses NativeAOT, both Debug & Release

I don't think we should change anything, until we know what it should do and align with iOS.

I kind of feel like Debug mode should use Mono (regardless of $(PublishAot)) and Release is NativeAOT when $(PublishAot) is true. No need to use a private $(_IsPublishing) property or dotnet publish.

<UseMonoRuntime Condition=" '$(UseMonoRuntime)' == '' ">true</UseMonoRuntime>
<!-- HACK: make dotnet restore include Microsoft.NETCore.App.Runtime.NativeAOT.linux-bionic-arm64 -->
<_IsPublishing Condition=" '$(_IsPublishing)' == '' and '$(PublishAot)' == 'true' ">true</_IsPublishing>
<_IsPublishing Condition=" '$(_IsPublishing)' == '' and '$(_AndroidNativeAot)' == 'true' ">true</_IsPublishing>

<!-- Use $(AndroidMinimumSupportedApiLevel) for $(SupportedOSPlatformVersion) if unset -->
<SupportedOSPlatformVersion Condition=" '$(SupportedOSPlatformVersion)' == '' ">$(AndroidMinimumSupportedApiLevel)</SupportedOSPlatformVersion>
Expand Down Expand Up @@ -94,7 +97,7 @@
<RuntimeIdentifier Condition=" '$(RuntimeIdentifiers)' != '' And '$(RuntimeIdentifier)' != '' " />
<GenerateApplicationManifest Condition=" '$(GenerateApplicationManifest)' == '' ">true</GenerateApplicationManifest>
<!-- Default to Mono's AOT in Release mode -->
<RunAOTCompilation Condition=" '$(RunAOTCompilation)' == '' and '$(AotAssemblies)' == '' and '$(Configuration)' == 'Release' and '$(PublishAot)' != 'true' ">true</RunAOTCompilation>
<RunAOTCompilation Condition=" '$(RunAOTCompilation)' == '' and '$(AotAssemblies)' == '' and '$(Configuration)' == 'Release' and '$(_AndroidNativeAot)' != 'true' ">true</RunAOTCompilation>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I realize that this is pre-existing logic, but we really shouldn't be using '$(Configuration)' == 'Release' (or == 'Debug', for that matter). Looking at the structure of Microsoft.Android.Sdk.DefaultProperties.targets, I'm not sure why we have thisCondition setup this way either, given that the file already has a block:

<PropertyGroup  Condition=" '$(Configuration)' == 'Release' ">
  …
</PropertyGroup>

Do we need to check $(Configuration) at all here?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we really shouldn't be using '$(Configuration)' == 'Release' (or == 'Debug', for that matter)

This is the same way the .NET SDK specifies $(Optimize), for example, which is problematic due to:

For SDK-style projects, we basically have to declare defaults based on $(Configuration).

the file already has a block:

We could move this expression up to be inside <PropertyGroup Condition=" '$(Configuration)' == 'Release' ">.

<RunAOTCompilation Condition=" '$(RunAOTCompilation)' == '' and '$(AotAssemblies)' == 'true' ">true</RunAOTCompilation>
<RunAOTCompilation Condition=" '$(RunAOTCompilation)' == '' ">false</RunAOTCompilation>
<_AndroidXA1029 Condition=" '$(AotAssemblies)' != '' ">true</_AndroidXA1029>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@ This file contains the NativeAOT-specific MSBuild logic for .NET for Android.
-->
<Project>

<!-- Default property values for NativeAOT -->
<PropertyGroup>
<_AndroidRuntimePackRuntime>NativeAOT</_AndroidRuntimePackRuntime>
</PropertyGroup>

<!-- Make IlcCompile depend on the trimmer -->
<PropertyGroup>
<IlcCompileDependsOn>
Expand Down Expand Up @@ -60,12 +65,17 @@ This file contains the NativeAOT-specific MSBuild logic for .NET for Android.
<SuppressTrimAnalysisWarnings>$(_OriginalSuppressTrimAnalysisWarnings)</SuppressTrimAnalysisWarnings>
</PropertyGroup>
<ItemGroup>
<!-- Android needs a proper soname property or it will refuse to load the library -->
<LinkerArg Include="-Wl,-soname,lib$(TargetName)$(NativeBinaryExt)" />
<!-- Give ILLink's output to ILC -->
<IlcCompileInput Remove="@(IlcCompileInput)" />
<IlcCompileInput Include="$(IntermediateLinkDir)$(TargetName)$(TargetExt)" />
<_AndroidILLinkAssemblies Include="@(ManagedAssemblyToLink->'$(IntermediateLinkDir)%(Filename)%(Extension)')" Condition="Exists('$(IntermediateLinkDir)%(Filename)%(Extension)')" />
<IlcReference Remove="@(IlcReference)" />
<IlcReference Include="@(PrivateSdkAssemblies)" />
<IlcReference Include="@(ManagedAssemblyToLink->'$(IntermediateLinkDir)%(Filename)%(Extension)')" Condition="Exists('$(IntermediateLinkDir)%(Filename)%(Extension)')" Exclude="@(IlcCompileInput)" />
<IlcReference Include="@(_AndroidILLinkAssemblies)" />
<!-- Passes linked assemblies to outer MSBuild tasks/targets -->
<ResolvedFileToPublish Include="@(IlcCompileInput);@(_AndroidILLinkAssemblies)" RuntimeIdentifier="$(_OriginalRuntimeIdentifier)" />
</ItemGroup>
</Target>

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

<Target Name="_AndroidFixNativeLibraryFileName" AfterTargets="ComputeFilesToPublish">
<ItemGroup>
<!-- Fix paths to contain lib-prefix -->
<ResolvedFileToPublish Update="@(ResolvedFileToPublish)" ArchiveFileName="lib%(FileName)%(Extension)" Condition=" '%(Filename)%(Extension)' == '$(TargetName)$(NativeBinaryExt)' " />
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This means that if $(TargetName) starts with lib, there may be too many lib prefixes.

I don't know if this is an actual problem.

</ItemGroup>
</Target>

</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,6 @@
<Import Project="Microsoft.Android.Sdk.DefaultProperties.targets" />
<Import Project="$(MSBuildThisFileDirectory)..\tools\Xamarin.Android.Common.Debugging.props"
Condition="Exists('$(MSBuildThisFileDirectory)..\tools\Xamarin.Android.Common.Debugging.props')"/>
<Import Project="Microsoft.Android.Sdk.NativeAOT.targets" Condition=" '$(PublishAot)' == 'true' " />
<Import Project="Microsoft.Android.Sdk.NativeAOT.targets" Condition=" '$(_AndroidNativeAot)' == 'true' " />

</Project>
8 changes: 8 additions & 0 deletions src/Xamarin.Android.Build.Tasks/Tasks/GenerateJavaStubs.cs
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,8 @@ public class GenerateJavaStubs : AndroidTask
[Output]
public ITaskItem[] GeneratedBinaryTypeMaps { get; set; }

public bool NativeAot { get; set; }

internal const string AndroidSkipJavaStubGeneration = "AndroidSkipJavaStubGeneration";

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

void GenerateAdditionalProviderSources (NativeCodeGenState codeGenState, IList<string> additionalProviders)
{
if (NativeAot) {
Log.LogDebugMessage ("Skipping MonoRuntimeProvider generation for NativeAot");
return;
}

// Create additional runtime provider java sources.
string providerTemplateFile = "MonoRuntimeProvider.Bundled.java";
string providerTemplate = GetResource (providerTemplateFile);
Expand Down Expand Up @@ -347,6 +354,7 @@ IList<string> MergeManifest (NativeCodeGenState codeGenState, Dictionary<string,
Debug = Debug,
MultiDex = MultiDex,
NeedsInternet = NeedsInternet,
NativeAot = NativeAot,
};
// Only set manifest.VersionCode if there is no existing value in AndroidManifest.xml.
if (manifest.HasVersionCode) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -115,18 +115,49 @@ public void NativeAOT ()
}

var proj = new XamarinAndroidApplicationProject {
ProjectName = "Hello",
IsRelease = true,
RuntimeIdentifier = "android-arm64",
// Add locally downloaded NativeAOT packs
ExtraNuGetConfigSources = {
Path.Combine (XABuildPaths.BuildOutputDirectory, "nuget-unsigned"),
}
};
proj.SetRuntimeIdentifier ("arm64-v8a");
proj.SetProperty ("PublishAot", "true");
proj.SetProperty ("PublishAotUsingRuntimePack", "true");
proj.SetProperty ("AndroidNdkDirectory", AndroidNdkPath);

using var b = CreateApkBuilder ();
Assert.IsTrue (b.Build (proj), "Build should have succeeded.");

string [] mono_classes = [
"Lmono/MonoRuntimeProvider;",
];
string[] mono_files = [
"lib/arm64-v8a/libmonosgen-2.0.so",
];
string [] nativeaot_files = [
$"lib/arm64-v8a/lib{proj.ProjectName}.so",
];

var intermediate = Path.Combine (Root, b.ProjectDirectory, proj.IntermediateOutputPath, proj.RuntimeIdentifier);
var output = Path.Combine (Root, b.ProjectDirectory, proj.OutputPath, proj.RuntimeIdentifier);

var dexFile = Path.Combine (intermediate, "android", "bin", "classes.dex");
FileAssert.Exists (dexFile);
foreach (var className in mono_classes) {
Assert.IsFalse (DexUtils.ContainsClassWithMethod (className, "<init>", "()V", dexFile, AndroidSdkPath), $"`{dexFile}` should *not* include `{className}`!");
}

var apkFile = Path.Combine (output, $"{proj.PackageName}-Signed.apk");
FileAssert.Exists (apkFile);
using var zip = ZipHelper.OpenZip (apkFile);
foreach (var mono_file in mono_files) {
Assert.IsFalse (zip.ContainsEntry (mono_file, caseSensitive: true), $"APK must *not* contain `{mono_file}`.");
}
foreach (var nativeaot_file in nativeaot_files) {
Assert.IsTrue (zip.ContainsEntry (nativeaot_file, caseSensitive: true), $"APK must contain `{nativeaot_file}`.");
}
}

[Test]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,11 @@ public bool UseJackAndJill {
set { SetProperty (KnownProperties.UseJackAndJill, value.ToString ()); }
}

public string RuntimeIdentifier {
get { return GetProperty (KnownProperties.RuntimeIdentifier); }
set { SetProperty (KnownProperties.RuntimeIdentifier, value); }
}

public AndroidLinkMode AndroidLinkModeDebug {
get {
AndroidLinkMode m;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ internal class ManifestDocument
public bool ForceDebuggable { get; set; }
public string VersionName { get; set; }
public IVersionResolver VersionResolver { get; set; } = new MonoAndroidHelperVersionResolver ();
public bool NativeAot { get; set; }

string versionCode;

Expand Down Expand Up @@ -672,6 +673,11 @@ XElement CreateApplicationElement (XElement manifest, string applicationClass, L

IList<string> AddMonoRuntimeProviders (XElement app)
{
if (NativeAot) {
//TODO: implement NativeAOT provider logic
return [];
}

app.Add (CreateMonoRuntimeProvider ("mono.MonoRuntimeProvider", null, --AppInitOrder));

var providerNames = new List<string> ();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -324,9 +324,9 @@ Copyright (C) 2011-2012 Xamarin. All rights reserved.
<AndroidUseAssemblyStore Condition=" '$(AndroidUseAssemblyStore)' == '' ">true</AndroidUseAssemblyStore>
<AndroidAotEnableLazyLoad Condition=" '$(AndroidAotEnableLazyLoad)' == '' And '$(AotAssemblies)' == 'true' And '$(AndroidIncludeDebugSymbols)' != 'true' ">True</AndroidAotEnableLazyLoad>
<AndroidEnableMarshalMethods Condition=" '$(AndroidEnableMarshalMethods)' == '' and ('$(UsingMicrosoftNETSdkRazor)' == 'true') ">False</AndroidEnableMarshalMethods>
<AndroidEnableMarshalMethods Condition=" '$(AndroidEnableMarshalMethods)' == '' and '$(PublishAot)' != 'true' ">True</AndroidEnableMarshalMethods>
<AndroidEnableMarshalMethods Condition=" '$(AndroidEnableMarshalMethods)' == '' and '$(_AndroidNativeAot)' != 'true' ">True</AndroidEnableMarshalMethods>
<!-- NOTE: temporarily disable for NativeAOT for now, to get build passing -->
<AndroidEnableMarshalMethods Condition=" '$(AndroidEnableMarshalMethods)' == '' and '$(PublishAot)' == 'true' ">False</AndroidEnableMarshalMethods>
<AndroidEnableMarshalMethods Condition=" '$(AndroidEnableMarshalMethods)' == '' and '$(_AndroidNativeAot)' == 'true' ">False</AndroidEnableMarshalMethods>
<_AndroidUseMarshalMethods Condition=" '$(AndroidIncludeDebugSymbols)' == 'True' ">False</_AndroidUseMarshalMethods>
<_AndroidUseMarshalMethods Condition=" '$(AndroidIncludeDebugSymbols)' != 'True' ">$(AndroidEnableMarshalMethods)</_AndroidUseMarshalMethods>
</PropertyGroup>
Expand Down Expand Up @@ -1374,6 +1374,7 @@ because xbuild doesn't support framework reference assemblies.
DependsOnTargets="_CollectRuntimeJarFilenames;$(_BeforeAddStaticResources);_GetMonoPlatformJarPath">
<CopyResource ResourceName="machine.config" OutputPath="$(MonoAndroidIntermediateAssemblyDir)machine.config" />
<CopyResource
Condition=" '$(_AndroidNativeAot)' != 'true' "
ResourceName="MonoRuntimeProvider.Bundled.java"
OutputPath="$(_AndroidIntermediateJavaSourceDirectory)mono\MonoRuntimeProvider.java"
/>
Expand Down Expand Up @@ -1492,6 +1493,7 @@ because xbuild doesn't support framework reference assemblies.
</ItemGroup>

<GenerateJavaStubs
NativeAot="$(_AndroidNativeAot)"
ResolvedAssemblies="@(_ResolvedAssemblies)"
ResolvedUserAssemblies="@(_ResolvedUserMonoAndroidAssemblies)"
ErrorOnCustomJavaObject="$(AndroidErrorOnCustomJavaObject)"
Expand Down Expand Up @@ -1721,6 +1723,7 @@ because xbuild doesn't support framework reference assemblies.
</Target>

<Target Name="_GeneratePackageManagerJava"
Condition=" '$(_AndroidNativeAot)' != 'true' "
DependsOnTargets="$(_GeneratePackageManagerJavaDependsOn)"
Inputs="@(_GeneratePackageManagerJavaInputs)"
Outputs="$(_AndroidStampDirectory)_GeneratePackageManagerJava.stamp">
Expand Down Expand Up @@ -1939,7 +1942,7 @@ because xbuild doesn't support framework reference assemblies.

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

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