Skip to content

Commit

Permalink
[NativeAOT] MSBuild-related logic to get projects to build (#9583)
Browse files Browse the repository at this point in the history
This is an initial step to get the NativeAOT build working the same
as iOS does.  At a high level, the changes are:

  * Run `ILLink` with our existing trimmer/linker pipeline.

  * Temporarily change our RID to `linux-bionic-arm64`.

  * Pass the output to `ILC`, the NativeAOT compiler.

  * Turn the RID back to `android-arm64`.

A list of MSBuild/workload changes required so far:

  * `$(UseMonoRuntime)` is false when `$(PublishAot)` is true.

  * Set `$(_IsPublishing)` as NativeAOT expects `dotnet publish` to
    be the only way NativeAOT is used.  Setting this in our targets
    allows the proper `*.NativeAOT.*` packs to restore inside of a
    `dotnet build`.

  * `$(SelfContained)=true`, seems to be required for the
    `linux-bionic-arm64` runtime packs to restore.  All Android apps
    are self-contained, so this might be fine.

  * Create a new `Microsoft.Android.Sdk.NativeAOT.targets` file that
    uses `$(_AndroidNdkDirectory)` to set various properties for
    NativeAOT's build (ILC).

  * `HACK:` set `$(_targetOS)` to `linux` to make the NativeAOT build
    attempt to run.  `--targetos:android` results in a build error
    that says Android is not supported.

  * Disable `$(RunAOTCompilation)`, Mono's AOT compiler and the
    `<RemoveRegisterAttribute/>` MSBuild task.

  * Disable `$(AndroidEnableMarshalMethods)` to be re-enabled in a
    future PR.

A list of blockers or things that don't work yet:

  * NativeAOT apps won't launch yet (future changes for that)

  * The NativeAOT cross compiler doesn't run on Windows:

        Microsoft.NETCore.Native.Publish.targets(61,5): Cross-OS native compilation is not supported.
        Microsoft.NETCore.Native.Unix.targets(296,5): error :
          Platform linker ('C:\Android\android-sdk\ndk\26.3.11579264\toolchains/llvm/prebuilt/windows-x86_64/bin/aarch64-linux-android21-clang++' or 'gcc')
          not found in PATH. Ensure you have all the required prerequisites documented at https://aka.ms/nativeaot-prerequisites.

  * You can only target `-r android-arm64` as there are no other
    `linux-bionic-*` runtime packs yet.

  * `-p:PublishAotUsingRuntimePack=true` is currently required, but I
    will investigate if we should just set this by default.
  • Loading branch information
jonathanpeppers authored Dec 11, 2024
1 parent 6aa2522 commit 2fa7954
Show file tree
Hide file tree
Showing 6 changed files with 115 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ _ResolveAssemblies MSBuild target.
;_OuterOutputPath=$(OutputPath)
;_OuterIntermediateOutputPath=$(IntermediateOutputPath)
;_OuterCustomViewMapFile=$(_CustomViewMapFile)
;_AndroidNdkDirectory=$(_AndroidNdkDirectory)
</_AdditionalProperties>
<_AndroidBuildRuntimeIdentifiersInParallel Condition=" '$(_AndroidBuildRuntimeIdentifiersInParallel)' == '' ">true</_AndroidBuildRuntimeIdentifiersInParallel>
</PropertyGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
<AndroidUseIntermediateDesignerFile Condition=" '$(AndroidUseDesignerAssembly)' == 'True' ">false</AndroidUseIntermediateDesignerFile>
<AndroidUseIntermediateDesignerFile Condition=" '$(AndroidUseIntermediateDesignerFile)' == '' ">$(AndroidGenerateResourceDesigner)</AndroidUseIntermediateDesignerFile>
<AllowSelfContainedWithoutRuntimeIdentifier Condition =" '$(AllowSelfContainedWithoutRuntimeIdentifier)' == '' ">true</AllowSelfContainedWithoutRuntimeIdentifier>
<SelfContained Condition=" '$(SelfContained)' == '' ">true</SelfContained>
<GenerateDependencyFile Condition=" '$(GenerateDependencyFile)' == '' ">false</GenerateDependencyFile>
<CopyLocalLockFileAssemblies Condition=" '$(CopyLocalLockFileAssemblies)' == '' ">false</CopyLocalLockFileAssemblies>
<ComputeNETCoreBuildOutputFiles Condition=" '$(ComputeNETCoreBuildOutputFiles)' == '' ">false</ComputeNETCoreBuildOutputFiles>
Expand All @@ -23,7 +24,10 @@
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>
<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>

<!-- Use $(AndroidMinimumSupportedApiLevel) for $(SupportedOSPlatformVersion) if unset -->
<SupportedOSPlatformVersion Condition=" '$(SupportedOSPlatformVersion)' == '' ">$(AndroidMinimumSupportedApiLevel)</SupportedOSPlatformVersion>
Expand Down Expand Up @@ -89,8 +93,8 @@
<RuntimeIdentifiers Condition=" '$(RuntimeIdentifier)' == '' And '$(RuntimeIdentifiers)' == '' ">android-arm64;android-x64</RuntimeIdentifiers>
<RuntimeIdentifier Condition=" '$(RuntimeIdentifiers)' != '' And '$(RuntimeIdentifier)' != '' " />
<GenerateApplicationManifest Condition=" '$(GenerateApplicationManifest)' == '' ">true</GenerateApplicationManifest>
<!-- Default to AOT in Release mode -->
<RunAOTCompilation Condition=" '$(RunAOTCompilation)' == '' and '$(AotAssemblies)' == '' and '$(Configuration)' == 'Release' ">true</RunAOTCompilation>
<!-- 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)' == '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
@@ -0,0 +1,79 @@
<!--
***********************************************************************************************
Microsoft.Android.Sdk.NativeAOT.targets
This file contains the NativeAOT-specific MSBuild logic for .NET for Android.
***********************************************************************************************
-->
<Project>

<!-- Make IlcCompile depend on the trimmer -->
<PropertyGroup>
<IlcCompileDependsOn>
_AndroidBeforeIlcCompile;
SetupOSSpecificProps;
PrepareForILLink;
ILLink;
ComputeIlcCompileInputs;
_AndroidComputeIlcCompileInputs;
$(IlcCompileDependsOn)
</IlcCompileDependsOn>
</PropertyGroup>

<Target Name="_AndroidBeforeIlcCompile" BeforeTargets="SetupProperties">
<!-- Example settings from: https://github.com/jonathanpeppers/Android-NativeAOT/blob/ea69d122cdc7de67aa6a5db14b7e560763c63cdd/DotNet/libdotnet.targets -->
<PropertyGroup>
<_NdkSysrootAbi>aarch64-linux-android</_NdkSysrootAbi>
<_NdkClangPrefix>aarch64-linux-android21-</_NdkClangPrefix>
<_NdkPrebuiltAbi Condition=" $([MSBuild]::IsOSPlatform('windows')) ">windows-x86_64</_NdkPrebuiltAbi>
<_NdkPrebuiltAbi Condition=" $([MSBuild]::IsOSPlatform('osx')) ">darwin-x86_64</_NdkPrebuiltAbi>
<_NdkPrebuiltAbi Condition=" $([MSBuild]::IsOSPlatform('linux')) ">linux-x86_64</_NdkPrebuiltAbi>
<_NdkSysrootDir>$(_AndroidNdkDirectory)toolchains/llvm/prebuilt/$(_NdkPrebuiltAbi)/sysroot/usr/lib/$(_NdkSysrootAbi)</_NdkSysrootDir>
<_NdkBinDir>$(_AndroidNdkDirectory)toolchains/llvm/prebuilt/$(_NdkPrebuiltAbi)/bin/</_NdkBinDir>
<CppCompilerAndLinker>$(_NdkBinDir)$(_NdkClangPrefix)clang++</CppCompilerAndLinker>
<CppLinker>$(CppCompilerAndLinker)</CppLinker>
<ObjCopyName>$(_NdkBinDir)llvm-objcopy</ObjCopyName>

<!-- Example settings from: https://github.com/xamarin/xamarin-macios/blob/c43d4ea40bc777969e3b158cf46446df292d8449/dotnet/targets/Xamarin.Shared.Sdk.targets#L541-L550 -->
<RunILLink>true</RunILLink>
<!--
We want to suppress warnings from trimmer and only show warnings from ILC.
Otherwise, you would get 2x for every warning.
-->
<_OriginalSuppressTrimAnalysisWarnings>$(SuppressTrimAnalysisWarnings)</_OriginalSuppressTrimAnalysisWarnings>
<SuppressTrimAnalysisWarnings>true</SuppressTrimAnalysisWarnings>

<!-- The list of hacks below should go away when we have NativeAOT.android-* packs -->
<!-- HACK: we are android-arm64, so this is required for the right path(s) to be found -->
<_OriginalRuntimeIdentifier>$(RuntimeIdentifier)</_OriginalRuntimeIdentifier>
<RuntimeIdentifier Condition=" '$(RuntimeIdentifier)' == 'android-arm64' ">linux-bionic-arm64</RuntimeIdentifier>
<!-- HACK: -targetos:android results in error, so use linux -->
<_targetOS>linux</_targetOS>
<!-- HACK: prevents libSystem.Net.Security.Native.a from being added -->
<_linuxLibcFlavor>bionic</_linuxLibcFlavor>
</PropertyGroup>
</Target>

<Target Name="_AndroidComputeIlcCompileInputs">
<PropertyGroup>
<!-- Turn trimmer warnings back to original value -->
<SuppressTrimAnalysisWarnings>$(_OriginalSuppressTrimAnalysisWarnings)</SuppressTrimAnalysisWarnings>
</PropertyGroup>
<ItemGroup>
<!-- Give ILLink's output to ILC -->
<IlcCompileInput Remove="@(IlcCompileInput)" />
<IlcCompileInput Include="$(IntermediateLinkDir)$(TargetName)$(TargetExt)" />
<IlcReference Remove="@(IlcReference)" />
<IlcReference Include="@(PrivateSdkAssemblies)" />
<IlcReference Include="@(ManagedAssemblyToLink->'$(IntermediateLinkDir)%(Filename)%(Extension)')" Condition="Exists('$(IntermediateLinkDir)%(Filename)%(Extension)')" Exclude="@(IlcCompileInput)" />
</ItemGroup>
</Target>

<Target Name="_AndroidAfterLinkNative" AfterTargets="LinkNative">
<PropertyGroup>
<!-- Turn $(RuntimeIdentifier) back to original value -->
<RuntimeIdentifier>$(_OriginalRuntimeIdentifier)</RuntimeIdentifier>
</PropertyGroup>
</Target>

</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -27,5 +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' " />

</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,30 @@ public void BuildBasicApplication ([Values (true, false)] bool isRelease, [Value
}
}

[Test]
public void NativeAOT ()
{
if (IsWindows) {
// Microsoft.NETCore.Native.Publish.targets(61,5): Cross-OS native compilation is not supported.
// Set $(DisableUnsupportedError)=true, Microsoft.NETCore.Native.Unix.targets(296,5): error : Platform linker ('C:\Android\android-sdk\ndk\26.3.11579264\toolchains/llvm/prebuilt/windows-x86_64/bin/aarch64-linux-android21-clang++' or 'gcc') not found in PATH. Ensure you have all the required prerequisites documented at https://aka.ms/nativeaot-prerequisites.
Assert.Ignore ("This test is not valid on Windows.");
}

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

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

[Test]
public void BuildBasicApplicationThenMoveIt ([Values (true, false)] bool isRelease)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -324,7 +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)' == '' ">True</AndroidEnableMarshalMethods>
<AndroidEnableMarshalMethods Condition=" '$(AndroidEnableMarshalMethods)' == '' and '$(PublishAot)' != 'true' ">True</AndroidEnableMarshalMethods>
<!-- NOTE: temporarily disable for NativeAOT for now, to get build passing -->
<AndroidEnableMarshalMethods Condition=" '$(AndroidEnableMarshalMethods)' == '' and '$(PublishAot)' == 'true' ">False</AndroidEnableMarshalMethods>
<_AndroidUseMarshalMethods Condition=" '$(AndroidIncludeDebugSymbols)' == 'True' ">False</_AndroidUseMarshalMethods>
<_AndroidUseMarshalMethods Condition=" '$(AndroidIncludeDebugSymbols)' != 'True' ">$(AndroidEnableMarshalMethods)</_AndroidUseMarshalMethods>
</PropertyGroup>
Expand Down Expand Up @@ -1937,7 +1939,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'"
Condition="'$(AndroidLinkMode)' != 'None' and '$(AndroidIncludeDebugSymbols)' != 'true' and '$(AndroidStripILAfterAOT)' != 'true' and '$(PublishAot)' != 'true' "
ShrunkFrameworkAssemblies="@(_ShrunkAssemblies)" />

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

0 comments on commit 2fa7954

Please sign in to comment.