From 1b577aaddcc665fa435074f4d8407257a259613f Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Thu, 15 Jul 2021 08:23:23 +0200 Subject: [PATCH] Add support for NDK r23. NDK r23 removes GNU Binutils and so we need to switch to using our bundled copy of them. Additionally, the minimum API level supported by the NDK is now 19. --- .../xaprepare/Application/BuildInfo.cs | 5 ++- .../xaprepare/Application/MonoJitRuntime.cs | 2 +- .../xaprepare/Application/Utilities.cs | 23 ++++++++++ .../ConfigAndData/BuildAndroidPlatforms.cs | 8 ++-- .../Dependencies/AndroidToolchain.cs | 2 +- .../xaprepare/Steps/Step_Android_SDK_NDK.cs | 24 ++-------- external/xamarin-android-tools | 2 +- src/Xamarin.Android.Build.Tasks/Tasks/Aot.cs | 18 +++++--- .../Tasks/NdkUtilTests.cs | 2 +- .../Utilities/BaseTest.cs | 44 +++++++++++++++++++ .../Utilities/NdkTools/WithClangNoBinutils.cs | 7 +-- src/monodroid/CMakeLists.txt | 1 - .../MSBuildDeviceIntegration.csproj | 1 + 13 files changed, 100 insertions(+), 39 deletions(-) diff --git a/build-tools/xaprepare/xaprepare/Application/BuildInfo.cs b/build-tools/xaprepare/xaprepare/Application/BuildInfo.cs index 69b8aed2e48..67413577b9b 100644 --- a/build-tools/xaprepare/xaprepare/Application/BuildInfo.cs +++ b/build-tools/xaprepare/xaprepare/Application/BuildInfo.cs @@ -18,6 +18,7 @@ partial class BuildInfo : AppObject public string NDKVersionMajor { get; private set; } = String.Empty; public string NDKVersionMinor { get; private set; } = String.Empty; public string NDKVersionMicro { get; private set; } = String.Empty; + public string NDKVersionTag { get; private set; } = String.Empty; public string NDKMinimumApiAvailable { get; private set; } = String.Empty; public string VersionHash { get; private set; } = String.Empty; @@ -59,8 +60,7 @@ public bool GatherNDKInfo (Context context) string rev = parts [1].Trim (); NDKRevision = rev; - Version ver; - if (!Version.TryParse (rev, out ver)) { + if (!Utilities.ParseAndroidPkgRevision (rev, out Version? ver, out string tag)) { Log.ErrorLine ($"Unable to parse NDK revision '{rev}' as a valid version string"); return false; } @@ -68,6 +68,7 @@ public bool GatherNDKInfo (Context context) NDKVersionMajor = ver.Major.ToString (); NDKVersionMinor = ver.Minor.ToString (); NDKVersionMicro = ver.Build.ToString (); + NDKVersionTag = tag; break; } diff --git a/build-tools/xaprepare/xaprepare/Application/MonoJitRuntime.cs b/build-tools/xaprepare/xaprepare/Application/MonoJitRuntime.cs index 31d435f4bc6..4838e62647e 100644 --- a/build-tools/xaprepare/xaprepare/Application/MonoJitRuntime.cs +++ b/build-tools/xaprepare/xaprepare/Application/MonoJitRuntime.cs @@ -24,7 +24,7 @@ public override void Init (Context context) OutputMonoBtlsFilename = Configurables.Defaults.MonoRuntimeOutputMonoBtlsFilename; OutputMonoPosixHelperFilename = Configurables.Defaults.MonoRuntimeOutputMonoPosixHelperFilename; OutputProfilerFilename = Configurables.Defaults.MonoRuntimeOutputProfilerFilename; - Strip = Path.Combine (Configurables.Paths.AndroidToolchainBinDirectory, $"{Configurables.Defaults.AndroidToolchainPrefixes [Name]}-strip"); + Strip = Path.Combine (Configurables.Paths.AndroidToolchainBinDirectory, "llvm-strip"); } } } diff --git a/build-tools/xaprepare/xaprepare/Application/Utilities.cs b/build-tools/xaprepare/xaprepare/Application/Utilities.cs index d3573903d41..75ee6edec7f 100644 --- a/build-tools/xaprepare/xaprepare/Application/Utilities.cs +++ b/build-tools/xaprepare/xaprepare/Application/Utilities.cs @@ -29,6 +29,29 @@ static partial class Utilities public static readonly Encoding UTF8NoBOM = new UTF8Encoding (false); + public static bool ParseAndroidPkgRevision (string? v, out Version? version, out string? tag) + { + string? ver = v?.Trim (); + version = null; + tag = null; + if (String.IsNullOrEmpty (ver)) + return false; + + if (ver!.IndexOf ('.') < 0) + ver = $"{ver}.0"; + + int tagIdx = ver.IndexOf ('-'); + if (tagIdx >= 0) { + tag = ver.Substring (tagIdx + 1); + ver = ver.Substring (0, tagIdx - 1); + } + + if (Version.TryParse (ver, out version)) + return true; + + return false; + } + public static bool AbiChoiceChanged (Context context) { string cacheFile = Configurables.Paths.MonoRuntimesEnabledAbisCachePath; diff --git a/build-tools/xaprepare/xaprepare/ConfigAndData/BuildAndroidPlatforms.cs b/build-tools/xaprepare/xaprepare/ConfigAndData/BuildAndroidPlatforms.cs index 8a0e0b5356c..8ab741baae5 100644 --- a/build-tools/xaprepare/xaprepare/ConfigAndData/BuildAndroidPlatforms.cs +++ b/build-tools/xaprepare/xaprepare/ConfigAndData/BuildAndroidPlatforms.cs @@ -5,8 +5,8 @@ namespace Xamarin.Android.Prepare { class BuildAndroidPlatforms { - public const string AndroidNdkVersion = "22b"; - public const string AndroidNdkPkgRevision = "22.1.7171670"; + public const string AndroidNdkVersion = "23-beta6"; + public const string AndroidNdkPkgRevision = "23.0.7530507-beta6"; public static readonly List AllPlatforms = new List { new AndroidPlatform (apiName: "", apiLevel: 1, platformID: "1"), @@ -49,9 +49,9 @@ class BuildAndroidPlatforms public const string AndroidX86_64_NET6 = AbiNames.TargetJit.AndroidX86_64 + "_NET6"; public static readonly Dictionary NdkMinimumAPI = new Dictionary { - { AbiNames.TargetJit.AndroidArmV7a, 16 }, { AndroidArmV7a_NET6, 21 }, + { AbiNames.TargetJit.AndroidArmV7a, 19 }, { AndroidArmV7a_NET6, 21 }, { AbiNames.TargetJit.AndroidArmV8a, 21 }, { AndroidArmV8a_NET6, 21 }, - { AbiNames.TargetJit.AndroidX86, 16 }, { AndroidX86_NET6, 21 }, + { AbiNames.TargetJit.AndroidX86, 19 }, { AndroidX86_NET6, 21 }, { AbiNames.TargetJit.AndroidX86_64, 21 }, { AndroidX86_64_NET6, 21 }, }; } diff --git a/build-tools/xaprepare/xaprepare/ConfigAndData/Dependencies/AndroidToolchain.cs b/build-tools/xaprepare/xaprepare/ConfigAndData/Dependencies/AndroidToolchain.cs index 435ba3f65a4..dd50b3b8d68 100644 --- a/build-tools/xaprepare/xaprepare/ConfigAndData/Dependencies/AndroidToolchain.cs +++ b/build-tools/xaprepare/xaprepare/ConfigAndData/Dependencies/AndroidToolchain.cs @@ -69,7 +69,7 @@ public AndroidToolchain () new AndroidToolchainComponent ("docs-24_r01", destDir: "docs", pkgRevision: "1", dependencyType: AndroidToolchainComponentType.BuildDependency), new AndroidToolchainComponent ("android_m2repository_r47", destDir: Path.Combine ("extras", "android", "m2repository"), pkgRevision: "47.0.0", dependencyType: AndroidToolchainComponentType.BuildDependency), new AndroidToolchainComponent ($"x86_64-29_r07-{osTag}", destDir: Path.Combine ("system-images", "android-29", "default", "x86_64"), relativeUrl: new Uri ("sys-img/android/", UriKind.Relative), pkgRevision: "7", dependencyType: AndroidToolchainComponentType.EmulatorDependency), - new AndroidToolchainComponent ($"android-ndk-r{AndroidNdkVersion}-{osTag}-x86_64", destDir: AndroidNdkDirectory, pkgRevision: AndroidPkgRevision), + new AndroidToolchainComponent ($"android-ndk-r{AndroidNdkVersion}-{osTag}", destDir: AndroidNdkDirectory, pkgRevision: AndroidPkgRevision), new AndroidToolchainComponent ($"{XABuildToolsPackagePrefix}build-tools_r{XABuildToolsVersion}-{altOsTag}", destDir: Path.Combine ("build-tools", XABuildToolsFolder), isMultiVersion: true), new AndroidToolchainComponent ($"commandlinetools-{cltOsTag}-{CommandLineToolsVersion}", destDir: Path.Combine ("cmdline-tools", CommandLineToolsFolder), isMultiVersion: true), diff --git a/build-tools/xaprepare/xaprepare/Steps/Step_Android_SDK_NDK.cs b/build-tools/xaprepare/xaprepare/Steps/Step_Android_SDK_NDK.cs index 3f54716ab0e..51b54e9e2b3 100644 --- a/build-tools/xaprepare/xaprepare/Steps/Step_Android_SDK_NDK.cs +++ b/build-tools/xaprepare/xaprepare/Steps/Step_Android_SDK_NDK.cs @@ -307,37 +307,21 @@ bool IsInstalled (AndroidToolchainComponent component, string path, out bool mis return false; } - if (!ParseVersion (pkgRevision, out Version? pkgVer) || pkgVer == null) { + if (!Utilities.ParseAndroidPkgRevision (pkgRevision, out Version? pkgVer, out string pkgTag) || pkgVer == null) { Log.DebugLine ($"Failed to parse a valid version from Pkg.Revision ({pkgRevision}) for component '{component.Name}'. Component will be reinstalled."); return false; } - if (!ParseVersion (component.PkgRevision, out Version? expectedPkgVer) || expectedPkgVer == null) + if (!Utilities.ParseAndroidPkgRevision (component.PkgRevision, out Version? expectedPkgVer, out string expectedTag) || expectedPkgVer == null) throw new InvalidOperationException ($"Invalid expected package version for component '{component.Name}': {component.PkgRevision}"); - bool equal = pkgVer == expectedPkgVer; + bool equal = (pkgVer == expectedPkgVer) && (pkgTag == expectedTag); if (!equal) - Log.DebugLine ($"Installed version of '{component.Name}' ({pkgVer}) is different than the required one ({expectedPkgVer})"); + Log.DebugLine ($"Installed version of '{component.Name}' ({pkgRevision}) is different than the required one ({component.PkgRevision})"); return equal; } - bool ParseVersion (string? v, out Version? version) - { - string? ver = v?.Trim (); - version = null; - if (String.IsNullOrEmpty (ver)) - return false; - - if (ver!.IndexOf ('.') < 0) - ver = $"{ver}.0"; - - if (Version.TryParse (ver, out version)) - return true; - - return false; - } - bool IsNdk (AndroidToolchainComponent component) { return component.Name.StartsWith ("android-ndk", StringComparison.OrdinalIgnoreCase); diff --git a/external/xamarin-android-tools b/external/xamarin-android-tools index 623332da80e..02f7ae7de25 160000 --- a/external/xamarin-android-tools +++ b/external/xamarin-android-tools @@ -1 +1 @@ -Subproject commit 623332da80e1ff2e1a567258c8df8a2a87558aba +Subproject commit 02f7ae7de2504707c91870f66c007cce58a0118b diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/Aot.cs b/src/Xamarin.Android.Build.Tasks/Tasks/Aot.cs index 246fc8bd50a..d257a980371 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/Aot.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/Aot.cs @@ -349,14 +349,20 @@ IEnumerable GetAotConfigs (NdkTools ndk) } string toolchainLibDir; - if (ndk.UsesClang) - toolchainLibDir = GetNdkToolchainLibraryDir (ndk, toolchainPath, arch); - else + if (ndk.UsesClang) { + if (ndk.NoBinutils) { + toolchainLibDir = String.Empty; + } else { + toolchainLibDir = GetNdkToolchainLibraryDir (ndk, toolchainPath, arch); + } + } else toolchainLibDir = GetNdkToolchainLibraryDir (ndk, toolchainPath); var libs = new List(); if (ndk.UsesClang) { - libs.Add ($"-L{toolchainLibDir.TrimEnd ('\\')}"); + if (!String.IsNullOrEmpty (toolchainLibDir)) { + libs.Add ($"-L{toolchainLibDir.TrimEnd ('\\')}"); + } libs.Add ($"-L{androidLibPath.TrimEnd ('\\')}"); if (arch == AndroidTargetArch.Arm) { @@ -366,7 +372,9 @@ IEnumerable GetAotConfigs (NdkTools ndk) } } - libs.Add (Path.Combine (toolchainLibDir, "libgcc.a")); + if (!String.IsNullOrEmpty (toolchainLibDir)) { + libs.Add (Path.Combine (toolchainLibDir, "libgcc.a")); + } libs.Add (Path.Combine (androidLibPath, "libc.so")); libs.Add (Path.Combine (androidLibPath, "libm.so")); diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Tasks/NdkUtilTests.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Tasks/NdkUtilTests.cs index c1947f59a15..b4b55954d61 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Tasks/NdkUtilTests.cs +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Tasks/NdkUtilTests.cs @@ -41,7 +41,7 @@ public void TestNdkUtil () Assert.IsTrue (ndk.ValidateNdkPlatform (arch, enableLLVM: false)); Assert.AreEqual (0, errors.Count, "NdkTools.ValidateNdkPlatform should not have returned false."); int level = ndk.GetMinimumApiLevelFor (arch); - int expected = 16; + int expected = 19; Assert.AreEqual (expected, level, $"Min Api Level for {arch} should be {expected}."); var compilerNoQuotes = ndk.GetToolPath (NdkToolKind.CompilerC, arch, level); Assert.AreEqual (0, errors.Count, "NdkTools.GetToolPath should not have errored."); 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 2634ae85282..b094b509744 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 @@ -5,9 +5,11 @@ using System.Diagnostics; using System.IO; using System.Linq; +using System.Runtime.InteropServices; using System.Text; using System.Threading; using System.Xml.Linq; +using Xamarin.Android.Build; using Xamarin.Android.Tasks; using Xamarin.ProjectTools; using Microsoft.Android.Build.Tasks; @@ -22,6 +24,8 @@ public class BaseTest [SetUpFixture] public class SetUp { + const string BinutilsSubdir = "ndk"; + public static string DeviceAbi { get; private set; @@ -75,6 +79,46 @@ public void BeforeAllTests () } catch (Exception ex) { Console.Error.WriteLine ("Failed to determine whether there is Android target emulator or not: " + ex); } + + string hostNdkDir = GetHostBinutilsDir (); + string xabtDir = Path.GetDirectoryName (typeof (BuildApk).Assembly.Location); + string symlinkDir = Path.Combine (xabtDir, hostNdkDir); + + // If directory exists then it's either a valid symlink or a real dir, don't touch anything in such instance + if (Directory.Exists (symlinkDir)) { + return; + } + + // If a file exists and is a symlink, then it's probably a dangling link - recreate it + if (File.Exists (symlinkDir)) { + if (!SymbolicLink.IsPathSymlink (symlinkDir)) { + throw new InvalidOperationException ($"File named '{symlinkDir}' exists where a symbolic link to a directory should be."); + } + + File.Delete (symlinkDir); + } + + string binutilsDirFullPath = Path.Combine (XABuildPaths.PrefixDirectory, "lib", "xamarin.android", "xbuild", "Xamarin", "Android", hostNdkDir); + if (!SymbolicLink.Create (symlinkDir, binutilsDirFullPath)) { + throw new InvalidOperationException ($"Failed to create a symbolic link from '{symlinkDir}' to '{binutilsDirFullPath}'"); + } + } + + string GetHostBinutilsDir () + { + if (RuntimeInformation.IsOSPlatform (OSPlatform.Windows)) { + return BinutilsSubdir; + } + + if (RuntimeInformation.IsOSPlatform (OSPlatform.Linux)) { + return Path.Combine ("Linux", BinutilsSubdir); + } + + if (RuntimeInformation.IsOSPlatform (OSPlatform.OSX)) { + return Path.Combine ("Darwin", BinutilsSubdir); + } + + throw new InvalidOperationException ($"Unsupported OS"); } int GetSdkVersion () diff --git a/src/Xamarin.Android.Build.Tasks/Utilities/NdkTools/WithClangNoBinutils.cs b/src/Xamarin.Android.Build.Tasks/Utilities/NdkTools/WithClangNoBinutils.cs index c4b0bb98607..f8c0ff02b50 100644 --- a/src/Xamarin.Android.Build.Tasks/Utilities/NdkTools/WithClangNoBinutils.cs +++ b/src/Xamarin.Android.Build.Tasks/Utilities/NdkTools/WithClangNoBinutils.cs @@ -9,13 +9,13 @@ namespace Xamarin.Android.Tasks { class NdkToolsWithClangNoBinutils : NdkToolsWithClangNoPlatforms { + const string BinutilsSubdir = "ndk"; + public NdkToolsWithClangNoBinutils (string androidNdkPath, NdkVersion version, TaskLoggingHelper? log) : base (androidNdkPath, version, log) { NdkToolNames[NdkToolKind.Linker] = "ld"; NoBinutils = true; - - throw new NotSupportedException ($"NDK {Version} is not supported by this version of Xamarin.Android"); } public override string GetToolPath (NdkToolKind kind, AndroidTargetArch arch, int apiLevel) @@ -35,8 +35,9 @@ string GetEmbeddedToolPath (NdkToolKind kind, AndroidTargetArch arch) { string toolName = GetToolName (kind); string triple = GetArchTriple (arch); + string binutilsDir = Path.Combine (MonoAndroidHelper.GetOSBinPath (), "ndk"); - return $"[TODO]/{triple}-{toolName}"; + return GetExecutablePath (Path.Combine (binutilsDir, $"{triple}-{toolName}"), mustExist: true); } } } diff --git a/src/monodroid/CMakeLists.txt b/src/monodroid/CMakeLists.txt index da3391db750..9483fb0f8e0 100644 --- a/src/monodroid/CMakeLists.txt +++ b/src/monodroid/CMakeLists.txt @@ -279,7 +279,6 @@ endif() if(ANDROID) add_compile_definitions(HAVE_LZ4) add_compile_definitions(PLATFORM_ANDROID) - add_compile_definitions(__ANDROID_API__=${ANDROID_NATIVE_API_LEVEL}) if(ANDROID_ABI MATCHES "^(arm64-v8a|x86_64)") add_compile_definitions(ANDROID64) diff --git a/tests/MSBuildDeviceIntegration/MSBuildDeviceIntegration.csproj b/tests/MSBuildDeviceIntegration/MSBuildDeviceIntegration.csproj index 7ef8aa426da..9b0d371f0fe 100644 --- a/tests/MSBuildDeviceIntegration/MSBuildDeviceIntegration.csproj +++ b/tests/MSBuildDeviceIntegration/MSBuildDeviceIntegration.csproj @@ -15,6 +15,7 @@ Utilities\%(FileName).cs +