Skip to content

Question about supporting runtime packs for "parent" RIDs #24077

Open
@pjcollins

Description

@pjcollins

The Android (32) workload currently ships four runtime packs, one for each Android architecture:

  • Microsoft.Android.Runtime.32.android-arm
  • Microsoft.Android.Runtime.32.android-arm64
  • Microsoft.Android.Runtime.32.android-x86
  • Microsoft.Android.Runtime.32.android-x64

In order to reduce our installation footprint we have a desire to introduce a new runtime pack for managed assemblies that are not architecture specific, but are still only intended to be used with the parent android RID. Right now these managed assemblies are duplicated in all four packs mentioned above. Ideally, we would move the non-architecture specific assemblies into a new pack:

  • Microsoft.Android.Runtime.32.android

I tried to get this to work by adding a second RuntimePackNamePatterns value to the KnownFrameworkReference we declare:

<KnownFrameworkReference
    Include="Microsoft.Android"
    TargetFramework="net6.0"
    RuntimeFrameworkName="Microsoft.Android"
    LatestRuntimeFrameworkVersion="**FromWorkload**"
    TargetingPackName="Microsoft.Android.Ref.32"
    TargetingPackVersion="**FromWorkload**"
-   RuntimePackNamePatterns="Microsoft.Android.Runtime.32.**RID**"
+   RuntimePackNamePatterns="Microsoft.Android.Runtime.32.android;Microsoft.Android.Runtime.32.**RID**"
    RuntimePackRuntimeIdentifiers="android-arm;android-arm64;android-x86;android-x64"
    Profile="Android"
/>

The ProcessFrameworkReferences task handles this approach, but the ResolveFrameworkReferences task breaks as it only allows for a 1:1 relationship between runtime pack and framework reference:

Microsoft.NET.Sdk.FrameworkReferenceResolution.targets(326,5): error MSB4018: System.ArgumentException: An item with the same key has already been added. Key: Microsoft.Android

I'm wondering how risky or big of a breaking change it would be to change the RuntimePack* metadata on ResolvedFrameworkReferences, and do something like this instead:

--- a/src/Tasks/Microsoft.NET.Build.Tasks/ResolveFrameworkReferences.cs
+++ b/src/Tasks/Microsoft.NET.Build.Tasks/ResolveFrameworkReferences.cs
@@ -26,7 +26,6 @@ protected override void ExecuteCore()
             }

             var resolvedTargetingPacks = ResolvedTargetingPacks.ToDictionary(tp => tp.ItemSpec, StringComparer.OrdinalIgnoreCase);
-            var resolvedRuntimePacks = ResolvedRuntimePacks.ToDictionary(rp => rp.GetMetadata(MetadataKeys.FrameworkName), StringComparer.OrdinalIgnoreCase);

             var resolvedFrameworkReferences = new List<TaskItem>(FrameworkReferences.Length);

@@ -48,12 +47,11 @@ protected override void ExecuteCore()
                 resolvedFrameworkReference.SetMetadata("TargetingPackVersion", targetingPack.GetMetadata(MetadataKeys.NuGetPackageVersion));
                 resolvedFrameworkReference.SetMetadata("Profile", targetingPack.GetMetadata("Profile"));

-                ITaskItem runtimePack;
-                if (resolvedRuntimePacks.TryGetValue(frameworkReference.ItemSpec, out runtimePack))
-                {
-                    resolvedFrameworkReference.SetMetadata("RuntimePackPath", runtimePack.GetMetadata(MetadataKeys.PackageDirectory));
-                    resolvedFrameworkReference.SetMetadata("RuntimePackName", runtimePack.GetMetadata(MetadataKeys.NuGetPackageId));
-                    resolvedFrameworkReference.SetMetadata("RuntimePackVersion", runtimePack.GetMetadata(MetadataKeys.NuGetPackageVersion));
+                var matchingPacks = ResolvedRuntimePacks.Where(rp => rp.GetMetadata(MetadataKeys.FrameworkName).Equals(frameworkReference.ItemSpec, StringComparison.OrdinalIgnoreCase));
+                if (matchingPacks.Any()) {
+                    resolvedFrameworkReference.SetMetadata("RuntimePackPath", string.Join (";", matchingPacks.Select (mp => mp.GetMetadata(MetadataKeys.PackageDirectory))));
+                    resolvedFrameworkReference.SetMetadata("RuntimePackName", string.Join (";", matchingPacks.Select (mp => mp.GetMetadata(MetadataKeys.NuGetPackageId))));
+                    resolvedFrameworkReference.SetMetadata("RuntimePackVersion", string.Join (";", matchingPacks.Select (mp => mp.GetMetadata(MetadataKeys.NuGetPackageVersion))));
                 }

                 resolvedFrameworkReferences.Add(resolvedFrameworkReference);

We may also want to update the metadata names, but that might cause more breakage. These changes would produce ; separated RuntimePack* metadata values, for example:

RuntimePackName = Microsoft.Android.Runtime.32.android;Microsoft.Android.Runtime.32.android-x64

These changes to ResolveFrameworkReferences appear to work as needed for the Android use case. I've also got something working on the workload side by introducing a new FrameworkReference for Android, but I am not convinced that this FrameworkReference addition is the most sane or desirable approach.

Maybe there are other approaches that would support a "generic RID" runtime pack that I am not considering?

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions