From d8d29919b6568045afca39a1f33c0d3fccc75b45 Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Fri, 22 Mar 2024 18:47:18 +0000 Subject: [PATCH] [NET8] Fix assembly count when satellite assemblies are present (#8822) Context: https://github.com/xamarin/xamarin-android/pull/8790 The old method of satellite assembly counting relied on the `RelativePath` MSBuild item metadata, which appears to have gone missing somewhere in .NET8+. Update the code to check for presence of the following metadata, in order given, to determine assembly's culture, if any: * `Culture` * `RelativePath` * `DestinationSubDirectory` Failure to count satellite assemblies can, and sometimes will, result in a segfault since we generate a number of native code arrays based on the assembly count and the runtime assumes that what the build told it is true. --- .../Tasks/GeneratePackageManagerJava.cs | 13 ++++++-- .../Utilities/MonoAndroidHelper.cs | 32 +++++++++++++++++++ 2 files changed, 42 insertions(+), 3 deletions(-) diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/GeneratePackageManagerJava.cs b/src/Xamarin.Android.Build.Tasks/Tasks/GeneratePackageManagerJava.cs index 670fcfe566e..e71d2880d74 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/GeneratePackageManagerJava.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/GeneratePackageManagerJava.cs @@ -262,9 +262,16 @@ void AddEnvironment () HashSet archAssemblyNames = null; HashSet uniqueAssemblyNames = new HashSet (StringComparer.OrdinalIgnoreCase); Action updateAssemblyCount = (ITaskItem assembly) => { - // We need to use the 'RelativePath' metadata, if found, because it will give us the correct path for satellite assemblies - with the culture in the path. - string? relativePath = assembly.GetMetadata ("RelativePath"); - string assemblyName = String.IsNullOrEmpty (relativePath) ? Path.GetFileName (assembly.ItemSpec) : relativePath; + string? culture = MonoAndroidHelper.GetAssemblyCulture (assembly); + string fileName = Path.GetFileName (assembly.ItemSpec); + string assemblyName; + + if (String.IsNullOrEmpty (culture)) { + assemblyName = fileName; + } else { + assemblyName = $"{culture}/{fileName}"; + } + if (!uniqueAssemblyNames.Contains (assemblyName)) { uniqueAssemblyNames.Add (assemblyName); } diff --git a/src/Xamarin.Android.Build.Tasks/Utilities/MonoAndroidHelper.cs b/src/Xamarin.Android.Build.Tasks/Utilities/MonoAndroidHelper.cs index 4efceda5141..fda719dd7a1 100644 --- a/src/Xamarin.Android.Build.Tasks/Utilities/MonoAndroidHelper.cs +++ b/src/Xamarin.Android.Build.Tasks/Utilities/MonoAndroidHelper.cs @@ -643,5 +643,37 @@ public static string GetNativeLibsRootDirectoryPath (string androidBinUtilsDirec string relPath = GetToolsRootDirectoryRelativePath (androidBinUtilsDirectory); return Path.GetFullPath (Path.Combine (androidBinUtilsDirectory, relPath, "lib")); } + + public static string? GetAssemblyCulture (ITaskItem assembly) + { + // The best option + string? culture = assembly.GetMetadata ("Culture"); + if (!String.IsNullOrEmpty (culture)) { + return TrimSlashes (culture); + } + + // ...slightly worse + culture = assembly.GetMetadata ("RelativePath"); + if (!String.IsNullOrEmpty (culture)) { + return TrimSlashes (Path.GetDirectoryName (culture)); + } + + // ...not ideal + culture = assembly.GetMetadata ("DestinationSubDirectory"); + if (!String.IsNullOrEmpty (culture)) { + return TrimSlashes (culture); + } + + return null; + + string? TrimSlashes (string? s) + { + if (String.IsNullOrEmpty (s)) { + return null; + } + + return s.TrimEnd ('/').TrimEnd ('\\'); + } + } } }