From 379b87473066d6ad671f3407b4044baba681a35c Mon Sep 17 00:00:00 2001 From: Jonathan Peppers Date: Thu, 3 Jun 2021 14:16:02 -0500 Subject: [PATCH 1/3] [BaseTasks] add ABI detection for RIDs Fixes: https://github.com/xamarin/xamarin-android/issues/5432 Two cases currently do not work in .NET 6: 1) An Android app project includes files such as: android-arm/libfoo.so android-arm64/libfoo.so android-x86/libfoo.so android-x64/libfoo.so It would be nice if users could use `$(RuntimeIdentifier)` names here. We can simply check if the directory name is a RID. 2) A NuGet package includes a native library from a path such as: packages/sqlitepclraw.lib.e_sqlite3.android/1.1.11/runtimes/android-arm64/native/libe_sqlite3.so In this case, there is no `%(RuntimeIdentifier)` item metadata on this native library. So we will have to check if the following is a RID: Directory.GetParent (lib.ItemSpec).Parent.Name I implemented these two cases as last resort to the existing logic. I think this will be fine for the behavior to be in "legacy" Xamarin.Android as well as .NET 6. I added tests for `AndroidRidAbiHelper`, since we had none before. --- .../AndroidRidAbiHelper.cs | 25 +++- .../AndroidRidAbiHelperTests.cs | 118 ++++++++++++++++++ 2 files changed, 138 insertions(+), 5 deletions(-) create mode 100644 tests/Microsoft.Android.Build.BaseTasks-Tests/AndroidRidAbiHelperTests.cs diff --git a/src/Microsoft.Android.Build.BaseTasks/AndroidRidAbiHelper.cs b/src/Microsoft.Android.Build.BaseTasks/AndroidRidAbiHelper.cs index 229d069..27d203c 100644 --- a/src/Microsoft.Android.Build.BaseTasks/AndroidRidAbiHelper.cs +++ b/src/Microsoft.Android.Build.BaseTasks/AndroidRidAbiHelper.cs @@ -19,13 +19,28 @@ public static class AndroidRidAbiHelper public static string GetNativeLibraryAbi (string lib) { // The topmost directory the .so file is contained within - var dir = Path.GetFileName (Path.GetDirectoryName (lib)).ToLowerInvariant (); - if (dir.StartsWith ("interpreter-", StringComparison.Ordinal)) { - dir = dir.Substring (12); + var dir = Directory.GetParent (lib); + var dirName = dir.Name; + if (dirName.StartsWith ("interpreter-", StringComparison.OrdinalIgnoreCase)) { + dirName = dirName.Substring (12); } - if (ValidAbis.Contains (dir)) { - return dir; + dirName = dirName.ToLowerInvariant (); + if (ValidAbis.Contains (dirName)) { + return dirName; } + + // Look for a directory with a RID as a name, such as: + // android-arm64/libfoo.so + var abi = RuntimeIdentifierToAbi (dirName); + if (!string.IsNullOrEmpty (abi)) + return abi; + + // Try one directory higher, such as: + // packages/sqlitepclraw.lib.e_sqlite3.android/1.1.11/runtimes/android-arm64/native/libe_sqlite3.so + abi = RuntimeIdentifierToAbi (dir.Parent.Name); + if (!string.IsNullOrEmpty (abi)) + return abi; + return null; } diff --git a/tests/Microsoft.Android.Build.BaseTasks-Tests/AndroidRidAbiHelperTests.cs b/tests/Microsoft.Android.Build.BaseTasks-Tests/AndroidRidAbiHelperTests.cs new file mode 100644 index 0000000..236d344 --- /dev/null +++ b/tests/Microsoft.Android.Build.BaseTasks-Tests/AndroidRidAbiHelperTests.cs @@ -0,0 +1,118 @@ +using System.Collections.Generic; +using Microsoft.Android.Build.Tasks; +using Microsoft.Build.Framework; +using Microsoft.Build.Utilities; +using NUnit.Framework; + +namespace Microsoft.Android.Build.BaseTasks.Tests +{ + [TestFixture] + public class AndroidRidAbiHelperTests + { + static object [] StringValueSource = new object [] { + new[] { + /* input */ "armeabi-v7a/libfoo.so", + /* expected */ "armeabi-v7a" + }, + new[] { + /* input */ "arm64-v8a/libfoo.so", + /* expected */ "arm64-v8a" + }, + new[] { + /* input */ "x86/libfoo.so", + /* expected */ "x86" + }, + new[] { + /* input */ "x86_64/libfoo.so", + /* expected */ "x86_64" + }, + new[] { + /* input */ "android-arm/libfoo.so", + /* expected */ "armeabi-v7a" + }, + new[] { + /* input */ "android-arm64/libfoo.so", + /* expected */ "arm64-v8a" + }, + new[] { + /* input */ "android-x86/libfoo.so", + /* expected */ "x86" + }, + new[] { + /* input */ "android-x64/libfoo.so", + /* expected */ "x86_64" + }, + new[] { + /* input */ "android-arm/native/libfoo.so", + /* expected */ "armeabi-v7a" + }, + new[] { + /* input */ "android-arm64/native/libfoo.so", + /* expected */ "arm64-v8a" + }, + new[] { + /* input */ "android-x86/native/libfoo.so", + /* expected */ "x86" + }, + new[] { + /* input */ "android-x64/native/libfoo.so", + /* expected */ "x86_64" + }, + new[] { + /* input */ "android.21-x64/native/libfoo.so", + /* expected */ "x86_64" + }, + new[] { + /* input */ "packages/sqlitepclraw.lib.e_sqlite3.android/1.1.11/runtimes/android-arm64/native/libe_sqlite3.so", + /* expected */ "arm64-v8a" + } + }; + + [Test] + [TestCaseSource (nameof (StringValueSource))] + public void StringValue (string input, string expected) + { + Assert.AreEqual (expected, AndroidRidAbiHelper.GetNativeLibraryAbi (input)); + } + + static object [] ITaskItemValueSource = new object [] { + new object [] { + /* input */ + new TaskItem("armeabi-v7a/libfoo.so"), + /* expected */ + "armeabi-v7a" + }, + new object [] { + /* input */ + new TaskItem("libfoo.so", new Dictionary { + { "Abi", "armeabi-v7a" } + }), + /* expected */ + "armeabi-v7a" + }, + new object [] { + /* input */ + new TaskItem("libfoo.so", new Dictionary { + { "RuntimeIdentifier", "android-arm" } + }), + /* expected */ + "armeabi-v7a" + }, + new object [] { + /* input */ + new TaskItem("libfoo.so", new Dictionary { + { "Link", "armeabi-v7a/libfoo.so" } + }), + /* expected */ + "armeabi-v7a" + }, + }; + + [Test] + [TestCaseSource (nameof (ITaskItemValueSource))] + public void ITaskItemValue (ITaskItem input, string expected) + { + Assert.AreEqual (expected, AndroidRidAbiHelper.GetNativeLibraryAbi (input)); + } + } +} From 7fc5d8d550e66ff55e84e4c92a1566814584b8ab Mon Sep 17 00:00:00 2001 From: Jonathan Pryor Date: Fri, 4 Jun 2021 16:06:29 -0400 Subject: [PATCH 2/3] Minor Fixes --- .../AndroidRidAbiHelper.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Microsoft.Android.Build.BaseTasks/AndroidRidAbiHelper.cs b/src/Microsoft.Android.Build.BaseTasks/AndroidRidAbiHelper.cs index 27d203c..3779567 100644 --- a/src/Microsoft.Android.Build.BaseTasks/AndroidRidAbiHelper.cs +++ b/src/Microsoft.Android.Build.BaseTasks/AndroidRidAbiHelper.cs @@ -20,11 +20,11 @@ public static string GetNativeLibraryAbi (string lib) { // The topmost directory the .so file is contained within var dir = Directory.GetParent (lib); - var dirName = dir.Name; - if (dirName.StartsWith ("interpreter-", StringComparison.OrdinalIgnoreCase)) { - dirName = dirName.Substring (12); + var dirName = dir.Name.ToLowerInvariant (); + if (dirName.StartsWith ("interpreter-", StringComparison.Ordinal)) { + dirName = dirName.Substring ("interpreter-".Length); } - dirName = dirName.ToLowerInvariant (); + dirName = dirName; if (ValidAbis.Contains (dirName)) { return dirName; } @@ -37,7 +37,7 @@ public static string GetNativeLibraryAbi (string lib) // Try one directory higher, such as: // packages/sqlitepclraw.lib.e_sqlite3.android/1.1.11/runtimes/android-arm64/native/libe_sqlite3.so - abi = RuntimeIdentifierToAbi (dir.Parent.Name); + abi = RuntimeIdentifierToAbi (dir.Parent.Name.ToLowerInvariant ()); if (!string.IsNullOrEmpty (abi)) return abi; From 9e550fc552d8f95d719008f3de9fd3a5050a5923 Mon Sep 17 00:00:00 2001 From: Jonathan Peppers Date: Fri, 4 Jun 2021 15:30:30 -0500 Subject: [PATCH 3/3] Support RID values in %(Link) item metadata --- .../AndroidRidAbiHelper.cs | 4 +-- .../AndroidRidAbiHelperTests.cs | 30 +++++++++++++++++-- 2 files changed, 28 insertions(+), 6 deletions(-) diff --git a/src/Microsoft.Android.Build.BaseTasks/AndroidRidAbiHelper.cs b/src/Microsoft.Android.Build.BaseTasks/AndroidRidAbiHelper.cs index 3779567..8e6cce4 100644 --- a/src/Microsoft.Android.Build.BaseTasks/AndroidRidAbiHelper.cs +++ b/src/Microsoft.Android.Build.BaseTasks/AndroidRidAbiHelper.cs @@ -24,7 +24,6 @@ public static string GetNativeLibraryAbi (string lib) if (dirName.StartsWith ("interpreter-", StringComparison.Ordinal)) { dirName = dirName.Substring ("interpreter-".Length); } - dirName = dirName; if (ValidAbis.Contains (dirName)) { return dirName; } @@ -56,8 +55,7 @@ public static string GetNativeLibraryAbi (ITaskItem lib) // First, try nominal "Link" path. var link = lib.GetMetadata ("Link"); if (!string.IsNullOrWhiteSpace (link)) { - var linkdirs = link.ToLowerInvariant ().Split ('/', '\\'); - lib_abi = ValidAbis.Where (p => linkdirs.Contains (p)).FirstOrDefault (); + lib_abi = GetNativeLibraryAbi (link); } // Check for a RuntimeIdentifier diff --git a/tests/Microsoft.Android.Build.BaseTasks-Tests/AndroidRidAbiHelperTests.cs b/tests/Microsoft.Android.Build.BaseTasks-Tests/AndroidRidAbiHelperTests.cs index 236d344..bb241cb 100644 --- a/tests/Microsoft.Android.Build.BaseTasks-Tests/AndroidRidAbiHelperTests.cs +++ b/tests/Microsoft.Android.Build.BaseTasks-Tests/AndroidRidAbiHelperTests.cs @@ -84,7 +84,7 @@ public void StringValue (string input, string expected) }, new object [] { /* input */ - new TaskItem("libfoo.so", new Dictionary { + new TaskItem("libabi.so", new Dictionary { { "Abi", "armeabi-v7a" } }), /* expected */ @@ -92,7 +92,7 @@ public void StringValue (string input, string expected) }, new object [] { /* input */ - new TaskItem("libfoo.so", new Dictionary { + new TaskItem("librid.so", new Dictionary { { "RuntimeIdentifier", "android-arm" } }), /* expected */ @@ -100,12 +100,36 @@ public void StringValue (string input, string expected) }, new object [] { /* input */ - new TaskItem("libfoo.so", new Dictionary { + new TaskItem("liblink.so", new Dictionary { { "Link", "armeabi-v7a/libfoo.so" } }), /* expected */ "armeabi-v7a" }, + new object [] { + /* input */ + new TaskItem("liblink.so", new Dictionary { + { "Link", "x86/libfoo.so" } + }), + /* expected */ + "x86" + }, + new object [] { + /* input */ + new TaskItem("liblink.so", new Dictionary { + { "Link", "x86_64/libfoo.so" } + }), + /* expected */ + "x86_64" + }, + new object [] { + /* input */ + new TaskItem("libridlink.so", new Dictionary { + { "Link", "android-arm/libfoo.so" } + }), + /* expected */ + "armeabi-v7a" + }, }; [Test]