diff --git a/build-tools/automation/azure-pipelines.yaml b/build-tools/automation/azure-pipelines.yaml index fabd51a8fdd..cf31bee22e4 100644 --- a/build-tools/automation/azure-pipelines.yaml +++ b/build-tools/automation/azure-pipelines.yaml @@ -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 != HybridAOT & TestCategory != ProfiledAOT & TestCategory != LLVM & TestCategory != MkBundle & TestCategory != MonoSymbolicate & TestCategory != PackagesConfig & TestCategory != StaticProject & TestCategory != Debugger & TestCategory != SystemApplication' + DotNetNUnitCategories: '& TestCategory != DotNetIgnore & TestCategory != HybridAOT & TestCategory != ProfiledAOT & 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')] @@ -809,6 +809,17 @@ stages: artifactFolder: net6-aot useDotNet: true + - template: yaml-templates/apk-instrumentation.yaml + parameters: + configuration: $(XA.Build.Configuration) + testName: Mono.Android.NET_Tests-AotLlvm + project: tests/Mono.Android-Tests/Runtime-Microsoft.Android.Sdk/Mono.Android.NET-Tests.csproj + testResultsFiles: TestResult-Mono.Android.NET_Tests-$(XA.Build.Configuration)AotLlvm.xml + extraBuildArgs: /p:TestsFlavor=AotLlvm /p:RunAOTCompilation=true /p:EnableLlvm=true + artifactSource: bin/Test$(XA.Build.Configuration)/net6.0-android/Mono.Android.NET_Tests-Signed.apk + artifactFolder: net6-aotllvm + useDotNet: true + - task: MSBuild@1 displayName: shut down emulator inputs: diff --git a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.Aot.targets b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.Aot.targets index 705affcc8b0..e6ec675b479 100644 --- a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.Aot.targets +++ b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.Aot.targets @@ -54,17 +54,26 @@ They run in a context of an inner build with a single $(RuntimeIdentifier). AotOutputDirectory="$(_AndroidAotBinDirectory)" RuntimeIdentifier="$(RuntimeIdentifier)" EnableLLVM="$(EnableLLVM)" + UsingAndroidNETSdk="true" Profiles="@(_AotProfiles)"> - + + + <_MonoAOTCompilerPath>@(MonoAotCrossCompiler->WithMetadataValue('RuntimeIdentifier', '$(RuntimeIdentifier)')) + <_LLVMPath Condition=" '$(EnableLLVM)' == 'true' ">$([System.IO.Path]::GetDirectoryName ('$(_MonoAOTCompilerPath)')) + - <_MonoAOTAssemblies Include="@(_AndroidAotInputs->'%(FullPath)')" AotArguments="$(_AotArguments)" /> + <_MonoAOTAssemblies + Include="@(_AndroidAotInputs->'%(FullPath)')" + TempDirectory="$([MSBuild]::EnsureTrailingSlash($(_AotOutputDirectory)))%(FileName)" + AotArguments="$(_AotArguments),temp-path=$([System.IO.Path]::GetFullPath(%(_MonoAOTAssemblies.TempDirectory)))" + /> - + GetAotConfigs (NdkTools ndk) } string toolPrefix = GetToolPrefix (ndk, arch, out int level); - var toolchainPath = toolPrefix.Substring(0, toolPrefix.LastIndexOf(Path.DirectorySeparatorChar)); - var ldFlags = string.Empty; - if (EnableLLVM) { - if (string.IsNullOrEmpty (AndroidNdkDirectory)) { - yield return Config.Invalid; - yield break; - } - - string androidLibPath = string.Empty; - try { - androidLibPath = ndk.GetDirectoryPath (NdkToolchainDir.PlatformLib, arch, level); - } catch (InvalidOperationException ex) { - Diagnostic.Error (5101, ex.Message); - } - - string toolchainLibDir; - if (ndk.UsesClang) - toolchainLibDir = GetNdkToolchainLibraryDir (ndk, toolchainPath, arch); - else - toolchainLibDir = GetNdkToolchainLibraryDir (ndk, toolchainPath); - - var libs = new List(); - if (ndk.UsesClang) { - libs.Add ($"-L{toolchainLibDir.TrimEnd ('\\')}"); - libs.Add ($"-L{androidLibPath.TrimEnd ('\\')}"); - - if (arch == AndroidTargetArch.Arm) { - // Needed for -lunwind to work - string compilerLibDir = Path.Combine (toolchainPath, "..", "sysroot", "usr", "lib", ndk.GetArchDirName (arch)); - libs.Add ($"-L{compilerLibDir.TrimEnd ('\\')}"); - } - } - - libs.Add (Path.Combine (toolchainLibDir, "libgcc.a")); - libs.Add (Path.Combine (androidLibPath, "libc.so")); - libs.Add (Path.Combine (androidLibPath, "libm.so")); - - ldFlags = $"\\\"{string.Join("\\\";\\\"", libs)}\\\""; - } - - string ldName = String.Empty; - if (EnableLLVM) { - ldName = ndk.GetToolPath (NdkToolKind.Linker, arch, level); - if (!String.IsNullOrEmpty (ldName)) { - ldName = Path.GetFileName (ldName); - if (ldName.IndexOf ('-') >= 0) { - ldName = ldName.Substring (ldName.LastIndexOf ("-") + 1); - } - } - } else { - ldName = "ld"; - } - foreach (var assembly in ResolvedAssemblies) { string outputFile = Path.Combine(outdir, string.Format ("libaot-{0}.so", Path.GetFileName (assembly.ItemSpec))); @@ -232,20 +138,13 @@ IEnumerable GetAotConfigs (NdkTools ndk) Path.GetFileName (assembly.ItemSpec))); string tempDir = Path.Combine (outdir, Path.GetFileName (assembly.ItemSpec)); - if (!Directory.Exists (tempDir)) - Directory.CreateDirectory (tempDir); - - var aotOptions = GetAotOptions (outdir, mtriple, toolPrefix); - aotOptions.Add ($"outfile={outputFile}"); - aotOptions.Add ($"llvm-path={SdkBinDirectory}"); - aotOptions.Add ($"temp-path={tempDir}"); - - if (!String.IsNullOrEmpty (ldName)) { - // MUST be before `ld-flags`, otherwise Mono fails to parse it on Windows - aotOptions.Add ($"ld-name={ldName}"); - } + Directory.CreateDirectory (tempDir); - aotOptions.Add ($"ld-flags={ldFlags}"); + var aotOptions = GetAotOptions (ndk, arch, level, outdir, mtriple, toolPrefix); + // NOTE: ordering seems to matter on Windows + aotOptions.Insert (0, $"outfile={outputFile}"); + aotOptions.Insert (0, $"llvm-path={SdkBinDirectory}"); + aotOptions.Insert (0, $"temp-path={tempDir}"); // we need to quote the entire --aot arguments here to make sure it is parsed // on windows as one argument. Otherwise it will be split up into multiple diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/GetAotArguments.cs b/src/Xamarin.Android.Build.Tasks/Tasks/GetAotArguments.cs index 7fcbc5299be..9e15a17aac1 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/GetAotArguments.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/GetAotArguments.cs @@ -1,7 +1,9 @@ using System; using System.Collections.Generic; using System.IO; +using System.Linq; using System.Threading.Tasks; +using Java.Interop.Tools.Diagnostics; using Microsoft.Android.Build.Tasks; using Microsoft.Build.Framework; using Xamarin.Android.Tools; @@ -48,13 +50,15 @@ public class GetAotArguments : AndroidAsyncTask public ITaskItem [] Profiles { get; set; } + public bool UsingAndroidNETSdk { get; set; } + public string AotAdditionalArguments { get; set; } [Output] public string Arguments { get; set; } [Output] - public string LLVMPath { get; set; } + public string OutputDirectory { get; set; } protected AotMode AotMode; protected SequencePointsMode SequencePointsMode; @@ -135,11 +139,10 @@ public override Task RunTaskAsync () } (_, string outdir, string mtriple, AndroidTargetArch arch) = GetAbiSettings (abi); - string toolPrefix = GetToolPrefix (ndk, arch, out _); + string toolPrefix = GetToolPrefix (ndk, arch, out int level); - Arguments = string.Join (",", GetAotOptions (outdir, mtriple, toolPrefix)); - if (EnableLLVM) - LLVMPath = Path.GetDirectoryName (toolPrefix); + Arguments = string.Join (",", GetAotOptions (ndk, arch, level, outdir, mtriple, toolPrefix)); + OutputDirectory = outdir; return Task.CompletedTask; } @@ -245,7 +248,7 @@ int GetNdkApiLevel (NdkTools ndk, AndroidTargetArch arch) /// /// Returns a list of parameters to pass to the --aot switch /// - protected List GetAotOptions (string outdir, string mtriple, string toolPrefix) + protected List GetAotOptions (NdkTools ndk, AndroidTargetArch arch, int level, string outdir, string mtriple, string toolPrefix) { List aotOptions = new List (); @@ -266,7 +269,117 @@ protected List GetAotOptions (string outdir, string mtriple, string tool aotOptions.Add ("asmwriter"); aotOptions.Add ($"mtriple={mtriple}"); aotOptions.Add ($"tool-prefix={toolPrefix}"); + + string ldName; + if (EnableLLVM) { + ldName = ndk.GetToolPath (NdkToolKind.Linker, arch, level); + if (!string.IsNullOrEmpty (ldName)) { + ldName = Path.GetFileName (ldName); + if (ldName.IndexOf ('-') >= 0) { + ldName = ldName.Substring (ldName.LastIndexOf ("-") + 1); + } + } + } else { + ldName = "ld"; + } + string ldFlags = GetLdFlags (ndk, arch, level, toolPrefix); + + // MUST be before `ld-flags`, otherwise Mono fails to parse it on Windows + if (!string.IsNullOrEmpty (ldName)) { + aotOptions.Add ($"ld-name={ldName}"); + } + if (!string.IsNullOrEmpty (ldFlags)) { + aotOptions.Add ($"ld-flags={ldFlags}"); + } + return aotOptions; } + + string GetLdFlags(NdkTools ndk, AndroidTargetArch arch, int level, string toolPrefix) + { + var toolchainPath = toolPrefix.Substring (0, toolPrefix.LastIndexOf (Path.DirectorySeparatorChar)); + var ldFlags = string.Empty; + if (EnableLLVM) { + if (string.IsNullOrEmpty (AndroidNdkDirectory)) { + return null; + } + + string androidLibPath = string.Empty; + try { + androidLibPath = ndk.GetDirectoryPath (NdkToolchainDir.PlatformLib, arch, level); + } catch (InvalidOperationException ex) { + Diagnostic.Error (5101, ex.Message); + } + + string toolchainLibDir; + if (ndk.UsesClang) + toolchainLibDir = GetNdkToolchainLibraryDir (ndk, toolchainPath, arch); + else + toolchainLibDir = GetNdkToolchainLibraryDir (ndk, toolchainPath); + + var libs = new List (); + if (ndk.UsesClang) { + libs.Add ($"-L{toolchainLibDir.TrimEnd ('\\')}"); + libs.Add ($"-L{androidLibPath.TrimEnd ('\\')}"); + + if (arch == AndroidTargetArch.Arm) { + // Needed for -lunwind to work + string compilerLibDir = Path.Combine (toolchainPath, "..", "sysroot", "usr", "lib", ndk.GetArchDirName (arch)); + libs.Add ($"-L{compilerLibDir.TrimEnd ('\\')}"); + } + } + + libs.Add (Path.Combine (toolchainLibDir, "libgcc.a")); + libs.Add (Path.Combine (androidLibPath, "libc.so")); + libs.Add (Path.Combine (androidLibPath, "libm.so")); + + if (UsingAndroidNETSdk) { + // NOTE: in .NET 6+ use space for the delimiter and escape spaces in paths + var escaped = libs.Select (l => l.Replace (" ", "\\ ")); + ldFlags = string.Join (" ", escaped); + } else { + ldFlags = $"\\\"{string.Join ("\\\";\\\"", libs)}\\\""; + } + } + return ldFlags; + } + + static string GetNdkToolchainLibraryDir (NdkTools ndk, string binDir, string archDir = null) + { + var baseDir = Path.GetFullPath (Path.Combine (binDir, "..")); + + string libDir = Path.Combine (baseDir, "lib", "gcc"); + if (!String.IsNullOrEmpty (archDir)) + libDir = Path.Combine (libDir, archDir); + + var gccLibDir = Directory.EnumerateDirectories (libDir).ToList (); + gccLibDir.Sort (); + + var libPath = gccLibDir.LastOrDefault (); + if (libPath == null) { + goto no_toolchain_error; + } + + if (ndk.UsesClang) + return libPath; + + gccLibDir = Directory.EnumerateDirectories (libPath).ToList (); + gccLibDir.Sort (); + + libPath = gccLibDir.LastOrDefault (); + if (libPath == null) { + goto no_toolchain_error; + } + + return libPath; + + no_toolchain_error: + throw new Exception ("Could not find a valid NDK compiler toolchain library path"); + } + + static string GetNdkToolchainLibraryDir (NdkTools ndk, string binDir, AndroidTargetArch arch) + { + return GetNdkToolchainLibraryDir (ndk, binDir, ndk.GetArchDirName (arch)); + } } } diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/AotTests.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/AotTests.cs index b0ea6906eb6..3ed2c53e192 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/AotTests.cs +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/AotTests.cs @@ -26,6 +26,10 @@ public void Setup () { if (!IsWindows) return; + // Use standard NDK directory for now + // See: https://github.com/dotnet/runtime/issues/56163 + if (Builder.UseDotNet) + return; var sdkPath = AndroidSdkPath; var ndkPath = AndroidNdkPath; @@ -45,6 +49,10 @@ public void TearDown () { if (!IsWindows) return; + // Use standard NDK directory for now + // See: https://github.com/dotnet/runtime/issues/56163 + if (Builder.UseDotNet) + return; Environment.SetEnvironmentVariable ("TEST_ANDROID_SDK_PATH", ""); Environment.SetEnvironmentVariable ("TEST_ANDROID_NDK_PATH", ""); Directory.Delete (SdkWithSpacesPath, recursive: true); @@ -150,8 +158,6 @@ public void BuildBasicApplicationReleaseProfiledAotWithoutDefaultProfile () [Category ("DotNetIgnore")] // Not currently working, see: https://github.com/dotnet/runtime/issues/56163 public void BuildAotApplicationAndÜmläüts (string supportedAbis, bool enableLLVM, bool expectedResult) { - AssertLLVMSupported (enableLLVM); - var path = Path.Combine ("temp", string.Format ("BuildAotApplication AndÜmläüts_{0}_{1}_{2}", supportedAbis, enableLLVM, expectedResult)); var proj = new XamarinAndroidApplicationProject () { IsRelease = true, @@ -230,8 +236,6 @@ public void BuildAotApplicationAndÜmläüts (string supportedAbis, bool enableL [Category ("DotNetIgnore")] // Not currently working, see: https://github.com/dotnet/runtime/issues/56163 public void BuildAotApplicationAndBundleAndÜmläüts (string supportedAbis, bool enableLLVM, bool expectedResult) { - AssertLLVMSupported (enableLLVM); - var path = Path.Combine ("temp", string.Format ("BuildAotApplicationAndBundle AndÜmläüts_{0}_{1}_{2}", supportedAbis, enableLLVM, expectedResult)); var proj = new XamarinAndroidApplicationProject () { IsRelease = true, diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Utilities/BaseTest.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Utilities/BaseTest.cs index f4073426fa3..980d0918fca 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Utilities/BaseTest.cs +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Utilities/BaseTest.cs @@ -205,13 +205,6 @@ protected static void AssertAotModeSupported (string aotMode) } } - protected static void AssertLLVMSupported (bool llvm) - { - if (Builder.UseDotNet && llvm) { - Assert.Ignore ($"EnableLLVM={llvm} is not yet supported in .NET 6+"); - } - } - protected static void AssertTargetFrameworkVersionSupported (string targetFrameworkVersion) { if (Builder.UseDotNet)