Skip to content

Commit 1f9b29d

Browse files
committed
Add support for adding RIDs to RidGraph during build
1 parent 75206ed commit 1f9b29d

11 files changed

+1044
-53
lines changed

src/libraries/Microsoft.NETCore.Platforms/src/GenerateRuntimeGraph.cs

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,24 @@ public ITaskItem[] RuntimeGroups
5353
set;
5454
}
5555

56+
/// <summary>
57+
/// Additional runtime identifiers to add to the graph.
58+
/// </summary>
59+
public string[] AdditionalRuntimeIdentifiers
60+
{
61+
get;
62+
set;
63+
}
64+
65+
/// <summary>
66+
/// Parent RID to use for any unknown AdditionalRuntimeIdentifer.
67+
/// </summary>
68+
public string AdditionalRuntimeIdentifierParent
69+
{
70+
get;
71+
set;
72+
}
73+
5674
/// <summary>
5775
/// Optional source Runtime.json to use as a starting point when merging additional RuntimeGroups
5876
/// </summary>
@@ -134,7 +152,11 @@ public override bool Execute()
134152
runtimeGraph = new RuntimeGraph();
135153
}
136154

137-
foreach (var runtimeGroup in RuntimeGroups.NullAsEmpty().Select(i => new RuntimeGroup(i)))
155+
List<RuntimeGroup> runtimeGroups = RuntimeGroups.NullAsEmpty().Select(i => new RuntimeGroup(i)).ToList();
156+
157+
AddRuntimeIdentifiers(runtimeGroups);
158+
159+
foreach (var runtimeGroup in runtimeGroups)
138160
{
139161
runtimeGraph = SafeMerge(runtimeGraph, runtimeGroup);
140162
}
@@ -291,6 +313,21 @@ private void ValidateImports(RuntimeGraph runtimeGraph, IDictionary<string, stri
291313
}
292314
}
293315

316+
private void AddRuntimeIdentifiers(ICollection<RuntimeGroup> runtimeGroups)
317+
{
318+
if (AdditionalRuntimeIdentifiers == null || AdditionalRuntimeIdentifiers.Length == 0)
319+
{
320+
return;
321+
}
322+
323+
RuntimeGroupCollection runtimeGroupCollection = new RuntimeGroupCollection(runtimeGroups);
324+
325+
foreach (string additionalRuntimeIdentifier in AdditionalRuntimeIdentifiers)
326+
{
327+
runtimeGroupCollection.AddRuntimeIdentifier(additionalRuntimeIdentifier, AdditionalRuntimeIdentifierParent);
328+
}
329+
}
330+
294331
private static IDictionary<string, IEnumerable<string>> GetCompatibilityMap(RuntimeGraph graph)
295332
{
296333
Dictionary<string, IEnumerable<string>> compatibilityMap = new Dictionary<string, IEnumerable<string>>();

src/libraries/Microsoft.NETCore.Platforms/src/Microsoft.NETCore.Platforms.csproj

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<Project Sdk="Microsoft.NET.SDK">
1+
<Project Sdk="Microsoft.NET.SDK">
22
<!-- These are wrapper project files for packaging.-->
33
<PropertyGroup>
44
<TargetFrameworks>$(NetCoreAppToolCurrent);net472</TargetFrameworks>
@@ -14,6 +14,13 @@
1414
<PackageDescription>Provides runtime information required to resolve target framework, platform, and runtime specific implementations of .NETCore packages.</PackageDescription>
1515
</PropertyGroup>
1616

17+
<PropertyGroup Condition="'$(DotNetBuildFromSource)' == 'true'">
18+
<!-- When building from source, ensure the RID we're building for is part of the RID graph -->
19+
<AdditionalRuntimeIdentifiers>$(AdditionalRuntimeIdentifiers);$(OutputRID)</AdditionalRuntimeIdentifiers>
20+
<!-- Also ensure the RID we're bulding on is part of the RID graph, since this may be more specific -->
21+
<AdditionalRuntimeIdentifiers>$(AdditionalRuntimeIdentifiers);$([System.Runtime.InteropServices.RuntimeInformation]::RuntimeIdentifier)</AdditionalRuntimeIdentifiers>
22+
</PropertyGroup>
23+
1724
<ItemGroup Condition="'$(TargetFramework)' == 'net472'">
1825
<Compile Include="BuildTask.Desktop.cs" />
1926
<Compile Include="AssemblyResolver.cs" />
@@ -24,11 +31,14 @@
2431
<Compile Include="Extensions.cs" />
2532
<Compile Include="GenerateRuntimeGraph.cs" />
2633
<Compile Include="RID.cs" />
34+
<Compile Include="RuntimeGroupCollection.cs" />
2735
<Compile Include="RuntimeGroup.cs" />
36+
<Compile Include="RuntimeVersion.cs" />
2837
</ItemGroup>
2938

3039
<ItemGroup>
31-
<Content Include="runtime.json" PackagePath="/" />
40+
<Content Condition="'$(AdditionalRuntimeIdentifiers)' == ''" Include="runtime.json" PackagePath="/" />
41+
<Content Condition="'$(AdditionalRuntimeIdentifiers)' != ''" Include="$(IntermediateOutputPath)runtime.json" PackagePath="/" />
3242
<Content Include="_._" PackagePath="lib/netstandard1.0" />
3343
</ItemGroup>
3444

@@ -38,5 +48,14 @@
3848
<PackageReference Include="NuGet.ProjectModel" Version="$(RefOnlyNugetProjectModelVersion)" />
3949
</ItemGroup>
4050

51+
<Target Name="GenerateRuntimeJson" Condition="'$(AdditionalRuntimeIdentifiers)' != ''" BeforeTargets="Pack">
52+
<MakeDir Directories="$(IntermediateOutputPath)" />
53+
<GenerateRuntimeGraph RuntimeGroups="@(RuntimeGroupWithQualifiers)"
54+
AdditionalRuntimeIdentifiers="$(AdditionalRuntimeIdentifiers)"
55+
AdditionalRuntimeIdentifierParent="$(AdditionalRuntimeIdentifierParent)"
56+
RuntimeJson="$(IntermediateOutputPath)runtime.json"
57+
UpdateRuntimeFiles="True" />
58+
</Target>
59+
4160
<Import Project="runtimeGroups.props" />
4261
</Project>
Lines changed: 156 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,44 @@
11
// Licensed to the .NET Foundation under one or more agreements.
22
// The .NET Foundation licenses this file to you under the MIT license.
33

4+
using System;
5+
using System.Diagnostics;
46
using System.Text;
57

68
namespace Microsoft.NETCore.Platforms.BuildTasks
79
{
8-
internal class RID
10+
public class RID
911
{
12+
internal const char VersionDelimiter = '.';
13+
internal const char ArchitectureDelimiter = '-';
14+
internal const char QualifierDelimiter = '-';
15+
1016
public string BaseRID { get; set; }
11-
public string VersionDelimiter { get; set; }
12-
public string Version { get; set; }
13-
public string ArchitectureDelimiter { get; set; }
17+
public bool OmitVersionDelimiter { get; set; }
18+
public RuntimeVersion Version { get; set; }
1419
public string Architecture { get; set; }
15-
public string QualifierDelimiter { get; set; }
1620
public string Qualifier { get; set; }
1721

1822
public override string ToString()
1923
{
2024
StringBuilder builder = new StringBuilder(BaseRID);
2125

22-
if (HasVersion())
26+
if (HasVersion)
2327
{
24-
builder.Append(VersionDelimiter);
28+
if (!OmitVersionDelimiter)
29+
{
30+
builder.Append(VersionDelimiter);
31+
}
2532
builder.Append(Version);
2633
}
2734

28-
if (HasArchitecture())
35+
if (HasArchitecture)
2936
{
3037
builder.Append(ArchitectureDelimiter);
3138
builder.Append(Architecture);
3239
}
3340

34-
if (HasQualifier())
41+
if (HasQualifier)
3542
{
3643
builder.Append(QualifierDelimiter);
3744
builder.Append(Qualifier);
@@ -40,20 +47,153 @@ public override string ToString()
4047
return builder.ToString();
4148
}
4249

43-
public bool HasVersion()
50+
private enum RIDPart : int
51+
{
52+
Base = 0,
53+
Version,
54+
Architcture,
55+
Qualifier,
56+
Max = Qualifier
57+
}
58+
59+
public static RID Parse(string runtimeIdentifier)
60+
{
61+
string[] parts = new string[(int)RIDPart.Max + 1];
62+
bool omitVersionDelimiter = true;
63+
RIDPart parseState = RIDPart.Base;
64+
65+
int partStart = 0, partLength = 0;
66+
67+
// qualifier is indistinguishable from arch so we cannot distinguish it for parsing purposes
68+
Debug.Assert(ArchitectureDelimiter == QualifierDelimiter);
69+
70+
for (int i = 0; i < runtimeIdentifier.Length; i++)
71+
{
72+
char current = runtimeIdentifier[i];
73+
partLength = i - partStart;
74+
75+
switch (parseState)
76+
{
77+
case RIDPart.Base:
78+
// treat any number as the start of the version
79+
if (current == VersionDelimiter || (current >= '0' && current <= '9'))
80+
{
81+
SetPart();
82+
partStart = i;
83+
if (current == VersionDelimiter)
84+
{
85+
omitVersionDelimiter = false;
86+
partStart = i + 1;
87+
}
88+
parseState = RIDPart.Version;
89+
}
90+
// version might be omitted
91+
else if (current == ArchitectureDelimiter)
92+
{
93+
// ensure there's no version later in the string
94+
if (-1 != runtimeIdentifier.IndexOf(VersionDelimiter, i))
95+
{
96+
break;
97+
}
98+
SetPart();
99+
partStart = i + 1; // skip delimiter
100+
parseState = RIDPart.Architcture;
101+
}
102+
break;
103+
case RIDPart.Version:
104+
if (current == ArchitectureDelimiter)
105+
{
106+
SetPart();
107+
partStart = i + 1; // skip delimiter
108+
parseState = RIDPart.Architcture;
109+
}
110+
break;
111+
case RIDPart.Architcture:
112+
if (current == QualifierDelimiter)
113+
{
114+
SetPart();
115+
partStart = i + 1; // skip delimiter
116+
parseState = RIDPart.Qualifier;
117+
}
118+
break;
119+
default:
120+
break;
121+
}
122+
}
123+
124+
partLength = runtimeIdentifier.Length - partStart;
125+
if (partLength > 0)
126+
{
127+
SetPart();
128+
}
129+
130+
string GetPart(RIDPart part)
131+
{
132+
return parts[(int)part];
133+
}
134+
135+
void SetPart()
136+
{
137+
if (partLength == 0)
138+
{
139+
throw new ArgumentException($"unexpected delimiter at position {partStart} in {runtimeIdentifier}");
140+
}
141+
142+
parts[(int)parseState] = runtimeIdentifier.Substring(partStart, partLength);
143+
}
144+
145+
string version = GetPart(RIDPart.Version);
146+
147+
if (version == null)
148+
{
149+
omitVersionDelimiter = false;
150+
}
151+
152+
return new RID()
153+
{
154+
BaseRID = GetPart(RIDPart.Base),
155+
OmitVersionDelimiter = omitVersionDelimiter,
156+
Version = version == null ? null : new RuntimeVersion(version),
157+
Architecture = GetPart(RIDPart.Architcture),
158+
Qualifier = GetPart(RIDPart.Qualifier)
159+
};
160+
}
161+
162+
public bool HasVersion => Version != null;
163+
164+
public bool HasArchitecture => Architecture != null;
165+
166+
public bool HasQualifier => Qualifier != null;
167+
168+
public override bool Equals(object obj)
44169
{
45-
return Version != null;
170+
return Equals(obj as RID);
46171
}
47172

48-
public bool HasArchitecture()
173+
public bool Equals(RID obj)
49174
{
50-
return Architecture != null;
175+
return object.ReferenceEquals(obj, this) ||
176+
(!(obj is null) &&
177+
BaseRID == obj.BaseRID &&
178+
(Version == null || OmitVersionDelimiter == obj.OmitVersionDelimiter) &&
179+
Version == obj.Version &&
180+
Architecture == obj.Architecture &&
181+
Qualifier == obj.Qualifier);
182+
51183
}
52184

53-
public bool HasQualifier()
185+
public override int GetHashCode()
54186
{
55-
return Qualifier != null;
187+
#if NETFRAMEWORK
188+
return BaseRID.GetHashCode();
189+
#else
190+
HashCode hashCode = default;
191+
hashCode.Add(BaseRID);
192+
hashCode.Add(Version);
193+
hashCode.Add(Architecture);
194+
hashCode.Add(Qualifier);
195+
return hashCode.ToHashCode();
196+
#endif
56197
}
57198
}
58-
59199
}

0 commit comments

Comments
 (0)