Skip to content
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Merge branch 'main' into dev/grendel/fix-satellite-assembly-count
* main:
  LEGO: Merge pull request 8818
  Bump to dotnet/installer@b40c44502d 9.0.100-preview.3.24165.20 (#8817)
  Bump com.android.tools:r8 from 8.2.47 to 8.3.37 (#8816)
  [Mono.Android] Prevent NullPointerException in TranslateStackTrace (#8795)
  Localized file check-in by OneLocBuild Task (#8815)
  [Xamarin.Android.Build.Tasks] Make all assemblies RID-specific (#8478)
  Localized file check-in by OneLocBuild Task (#8813)
  [Xamarin.Android.Build.Tasks] %(AndroidAsset.AssetPack) Support (#8631)
  [runtime] Remove the last vestiges of desktop builds (#8810)
  [ci] Don't auto-retry APK test suites. (#8811)
  [Microsoft.Android.Templates] Update EN l10n template strings (#8808)
  Bump to xamarin/Java.Interop/main@651de42 (#8809)
  [Mono.Android] is now "trimming safe" (#8778)
  [Mono.Android] Fix missing enum issues that cause BG8800 warnings. (#8707)
  Bump external/Java.Interop from `3436a30` to `5bca8ad` (#8803)
  Bump to xamarin/monodroid@77124dc1 (#8804)
  Bump to dotnet/installer@e911f5c82c 9.0.100-preview.3.24161.2 (#8802)
  Bump to xamarin/Java.Interop/main@3436a30 (#8799)
  [templates] Remove redundant "template" from display name. (#8773)
  • Loading branch information
grendello committed Mar 20, 2024
commit 399b941eb267ece87d0d249f077fd4d80f2f13e7
103 changes: 103 additions & 0 deletions src/Xamarin.Android.Build.Tasks/Utilities/MonoAndroidHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -616,5 +616,108 @@ public static string GetNativeLibsRootDirectoryPath (string androidBinUtilsDirec
return s.TrimEnd ('/').TrimEnd ('\\');
}
}

/// <summary>
/// Process a collection of assembly `ITaskItem` objects, splitting it on the assembly architecture (<see cref="GetTargetArch"/>) while, at the same time, ignoring
/// all assemblies which are **not** in the <paramref name="supportedAbis"/> collection. If necessary, the selection can be further controlled by passing a qualifier
/// function in <paramref name="shouldSkip"/> which returns `true` if the assembly passed to it should be **skipped**.
///
/// This method is necessary because sometimes our tasks will be given assemblies for more architectures than indicated as supported in their `SupportedAbis` properties.
/// One such example is the `AotTests.BuildAMassiveApp` test, which passes around a set of assemblies for all the supported architectures, but it supports only two ABIs
/// via the `SupportedAbis` property.
/// </summary>
public static Dictionary<AndroidTargetArch, Dictionary<string, ITaskItem>> GetPerArchAssemblies (IEnumerable<ITaskItem> input, ICollection<string> supportedAbis, bool validate, Func<ITaskItem, bool>? shouldSkip = null)
{
var supportedTargetArches = new HashSet<AndroidTargetArch> ();
foreach (string abi in supportedAbis) {
supportedTargetArches.Add (AbiToTargetArch (abi));
}

return GetPerArchAssemblies (
input,
supportedTargetArches,
validate,
shouldSkip
);
}

static Dictionary<AndroidTargetArch, Dictionary<string, ITaskItem>> GetPerArchAssemblies (IEnumerable<ITaskItem> input, HashSet<AndroidTargetArch> supportedTargetArches, bool validate, Func<ITaskItem, bool>? shouldSkip = null)
{
bool filterByTargetArches = supportedTargetArches.Count > 0;
var assembliesPerArch = new Dictionary<AndroidTargetArch, Dictionary<string, ITaskItem>> ();
foreach (ITaskItem assembly in input) {
if (shouldSkip != null && shouldSkip (assembly)) {
continue;
}

AndroidTargetArch arch = MonoAndroidHelper.GetTargetArch (assembly);
if (filterByTargetArches && !supportedTargetArches.Contains (arch)) {
continue;
}

if (!assembliesPerArch.TryGetValue (arch, out Dictionary<string, ITaskItem> assemblies)) {
assemblies = new Dictionary<string, ITaskItem> (StringComparer.OrdinalIgnoreCase);
assembliesPerArch.Add (arch, assemblies);
}

string name = Path.GetFileNameWithoutExtension (assembly.ItemSpec);
string? culture = assembly.GetMetadata ("Culture");
if (!String.IsNullOrEmpty (culture)) {
name = $"{culture}/{name}";
}
assemblies.Add (name, assembly);
}

// It's possible some assembly collections will be empty (e.g. `ResolvedUserAssemblies` as passed to the `GenerateJavaStubs` task), which
// isn't a problem and such empty collections should not be validated, as it will end in the "should never happen" exception below being
// thrown as a false negative.
if (assembliesPerArch.Count == 0 || !validate) {
return assembliesPerArch;
}

Dictionary<string, ITaskItem>? firstArchAssemblies = null;
AndroidTargetArch firstArch = AndroidTargetArch.None;
foreach (var kvp in assembliesPerArch) {
if (firstArchAssemblies == null) {
firstArchAssemblies = kvp.Value;
firstArch = kvp.Key;
continue;
}

EnsureDictionariesHaveTheSameEntries (firstArchAssemblies, kvp.Value, kvp.Key);
}

// Should "never" happen...
if (firstArch == AndroidTargetArch.None) {
throw new InvalidOperationException ("Internal error: no per-architecture assemblies found?");
}

return assembliesPerArch;

void EnsureDictionariesHaveTheSameEntries (Dictionary<string, ITaskItem> template, Dictionary<string, ITaskItem> dict, AndroidTargetArch arch)
{
if (dict.Count != template.Count) {
throw new InvalidOperationException ($"Internal error: architecture '{arch}' should have {template.Count} assemblies, however it has {dict.Count}");
}

foreach (var kvp in template) {
if (!dict.ContainsKey (kvp.Key)) {
throw new InvalidOperationException ($"Internal error: architecture '{arch}' does not have assembly '{kvp.Key}'");
}
}
}
}

internal static void DumpMarshalMethodsToConsole (string heading, IDictionary<string, IList<MarshalMethodEntry>> marshalMethods)
{
Console.WriteLine ();
Console.WriteLine ($"{heading}:");
foreach (var kvp in marshalMethods) {
Console.WriteLine ($" {kvp.Key}");
foreach (var method in kvp.Value) {
Console.WriteLine ($" {method.DeclaringType.FullName} {method.NativeCallback.FullName}");
}
}
}
}
}
You are viewing a condensed version of this merge commit. You can view the full changes here.