Skip to content

Commit 9d86427

Browse files
committed
Resolve comments and spelling
1 parent 9e803af commit 9d86427

File tree

2 files changed

+43
-45
lines changed

2 files changed

+43
-45
lines changed

.markdownlint.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
"MD003": { "style": "atx" },
44
"MD004": false,
55
"MD007": { "indent": 4 },
6-
"MD013": { "tables": false, "code_blocks": false },
6+
"MD013": false,
77
"MD026": false,
88
"no-hard-tabs": false
99
}

accepted/2022/simplify-rid-model.md

Lines changed: 42 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,9 @@ Date: April 2022
66

77
## Context
88

9-
RIDs are (for the most part) modelled as a graph of [target triplet](https://wiki.osdev.org/Target_Triplet) symbols that describe legal combinations of operating system, chip architecture, and C-runtime, including an extensive fallback scheme. This graph is codified in [`runtime.json`](https://github.com/dotnet/runtime/blob/main/src/libraries/Microsoft.NETCore.Platforms/src/runtime.json), which is describes the RID catalog. It is a massive (database in a) file. That's a lot of data to reason about, hard to edit correctly, and a bear to maintain.
9+
RIDs are (for the most part) modelled as a graph of [target triplet](https://wiki.osdev.org/Target_Triplet) symbols that describe legal combinations of operating system, chip architecture, and C-runtime, including an extensive fallback scheme. This graph is codified in [`runtime.json`](https://github.com/dotnet/runtime/blob/313982dff3457c8291e8b88cd99785f6920319f0/src/libraries/Microsoft.NETCore.Platforms/src/runtime.json), which we refer to as the RID catalog. It is a massive (database in a) file. That's a lot of data to reason about, hard to edit correctly, and a bear to maintain.
1010

11-
Note: `runtimes.json` is a generated file, from [runtimeGroups.props](https://github.com/dotnet/runtime/blob/main/src/libraries/Microsoft.NETCore.Platforms/src/runtimeGroups.props).
11+
Note: `runtimes.json` is a generated file, from [runtimeGroups.props](https://github.com/dotnet/runtime/blob/2042eb2a56112539bf9e0b9538972fdd84e381a0/src/libraries/Microsoft.NETCore.Platforms/src/runtimeGroups.props).
1212

1313
Examples of triplets today are:
1414

@@ -30,9 +30,9 @@ RIDs can be thought of as making statements about native code, specifically:
3030
- I offer code of this RID.
3131
- I request code of this RID.
3232

33-
Often times, the RIDs being offered and asked for do not match (in terms of the actual string) but are compatible. The role of `runtimes.json` is determining whether two RIDs are compatible (and best-match). That's done via a graph walk of the nodes in that file.
33+
Often times, the RIDs being offered and asked for do not match (in terms of the actual string) but are compatible. The `runtimes.json` file describes compatibility relationships between RIDs, making it possible to mechanically make best-match decisions. That's done via a graph walk of the nodes in that file.
3434

35-
The current system is unnecessarily complex, expensive to maintain, makes it difficult to manage community needs, and costly/fragile at runtime. More simply, it is useful, but significantly overshoots our needs.
35+
The current system is unnecessarily complex, expensive to maintain, makes it difficult to manage community needs, and costly/fragile at runtime. It is useful, but significantly overshoots our needs.
3636

3737
Note: RIDs are almost entirely oriented around calling native code. However, the domain is broader, more generally oriented on native interop and calling [Foreign Function Interfaces (FFI)](https://en.wikipedia.org/wiki/Foreign_function_interface), including matching the environment. For example, we'd still likely need to use RIDs for interacting with another managed platform like Java, possibly with the use of native code or not.
3838

@@ -56,22 +56,28 @@ The following are the biggest problems we see:
5656

5757
## General approach
5858

59+
Plan:
60+
5961
- Ensure `runtimes.json` is correct.
6062
- Freeze `runtimes.json`.
61-
- New RIDs will only be added for [interchange between different distributions of .NET](https://github.com/dotnet/designs/pull/260#discussion_r843009872), which isn't expected.
62-
- Continue to use `runtimes.json` for all NuGet scenarios.
6363
- Disable using `runtimes.json` for all host scenarios, by default (starting with a TBD .NET version).
64-
- Enable a host compatibility mode that uses `runtimes.json` via MSBuild property (which writes to), `runtimeconfig.json`, and a host CLI argument.
6564
- Implement a new algorithmic host scheme for RID selection, enabled by default.
65+
- Each host is built with a hard-coded set of RIDs that it probes for, both triplets and singles.
66+
- The RID that `dotnet --info` returns will always match the first in this hard-coded set of RIDs.
6667

67-
The new scheme will be based on the following:
68+
Notes:
6869

69-
- Each host is built with a hard-coded set of RIDs that it probes for, both triplets and singles.
7070
- Each host is already built for a specific RID triple, so this change is an evolutionary change.
71-
- There are processor-agnostic managed-code scenarios where a RID single is relevant, like Windows-only code (for example, accessing the registry) that works the same x64, Arm64 and x86. The same is true for macOS and Linux.
72-
- The RID that `dotnet --info` returns will always match the first in this hard-coded set of RIDs.
71+
- There are processor-agnostic managed-code scenarios where a RID single is relevant, like Windows-only code (for example, accessing the registry) that works the same for x64, Arm64 and x86. The same is true for macOS and Linux.
72+
73+
Phasing-out measures:
74+
75+
- Enable a host compatibility mode that uses `runtimes.json` via MSBuild property (which writes to), `runtimeconfig.json`, and a host CLI argument.
76+
- Continue to use `runtimes.json` for NuGet scenarios.
7377

74-
Let's assume that an app is running on Alpine 3.16, the host will probe for the following RIDs:
78+
Let's test this new approach, in terms of hosting RID probing.
79+
80+
An app is running on Alpine 3.16:
7581

7682
- `linux-musl-x64`
7783
- `unix`
@@ -88,52 +94,46 @@ macOS would be similar:
8894

8995
Note: The abstract `unix` RID is used for macOS and Linux, instead of a concrete RID for those OSes.
9096

91-
Note: We may want to add `osx` to describe macOS-specific processor-agnostic managed code. If we find some scenarios that need it, we should add it.
92-
93-
Windows would similar:
97+
Windows would be similar:
9498

9599
- `win-x86`
96100
- `win`
97101

98-
Note: `win7` and `win10` also exist (as processor-specific and -agnostic). Ideally, we don't have to support those in the host-specific scheme, but we need to do some research on that.
99-
100102
Note: A mix of processor-specific RIDs are used above, purely to demonstrate the range of processor-types supported. Each operating system supports a variety of processor-types, and this is codified in their associated RIDs.
101103

102104
More generally, the host will probe for:
103105

104-
- This environment, RID triplet (OS-CRuntime-arch)
105-
- This environment, RID single (OS-only).
106+
- RID triplet (OS-CRuntime-arch)
107+
- RID single (OS-only).
106108

107-
The host will implement "first one wins" probing logic for selecting a RID-specific asset.
109+
The host will implement "first one wins" probing logic for selecting a RID-specific asset in apps with `runtimes` directories (portable apps).
108110

109-
This behavior only applies for portable apps. RID-specific apps will not probe for RID-specific assets.
111+
There are other RIDs in `runtimes.json` today, like `debian.11.x64`. This new scheme will not support those. The `runtimes.json` host compat feature will need to be used to support those, which is likely very uncommon. Even if they are quasi-common, we will likely still make this change and require some combination of the ecosystem to adapt and app developers to opt-in to the `runtimes.json` compat mode.
110112

111-
There are other RIDs in `runtimes.json` today. This new scheme will not support those. The `runtimes.json` host compat feature will need to be used to support those, which is likely very uncommon. Even if they are quasi-common, we will likely still make this change and require some combination of the ecosystem to adapt and app developers to opt-in to the `runtimes.json` compat mode.
113+
The host and `runtimes.json` must remain compatible. The RIDs known by the host must be a subset of `runtimes.json` RIDs.
112114

113-
The host and `runtimes.json` must remain compatible. The RIDs known by the host must be a subset of `runtimes.json` RIDs. We may need to update `runtimes.json` to ensure that the RIDs known by the host are present in that file.
115+
## Minimum CRT/libc version
114116

117+
This scheme doesn't explicitly define a CRT/libc version. On macOS and Windows, that's an implementation detail of the OS versions we support. On Linux, we will define a minimum CRT/libc version, per major .NET version.
115118

116-
## Minimum CRT/libc version
119+
See:
117120

118-
This scheme doesn't explicitly define a CRT/libc version. Instead, we will define a minimum CRT/libc version, per major .NET version. That minimum CRT/libc version will form a contract and should be documented, per .NET version. Practically, it defines the oldest OS version that you can run an app on, for a given .NET version.
121+
- https://github.com/dotnet/core/blob/main/release-notes/8.0/supported-os.md#linux-compatibility
122+
- https://github.com/dotnet/runtime/blob/main/docs/project/linux-build-methodology.md
119123

120124
For .NET 7 (for all supported architectures):
121125

122126
- For Windows, .NET will target the Windows 10 CRT.
123127
- For Linux with glibc, .NET will target CentOS 7 (with glibc version `2.17`).
124128
- For Linux with musl, .NET will target the oldest supported Alpine version.
125129

126-
Note: Source-build project will likely make different choices. For example, the IBM s390x project supports RHEL 8, not CentOS 7. glibc compatibility relationships are discussed later.
127-
128-
For .NET 8, we'll continue with the model. However, we will no longer be able to use [CentOS 7 (due to EOL)](https://wiki.centos.org/About/Product), but will need to adopt another distro that provides us with an old enough glibc version such that we can offer broad compatibility.
129-
130-
For .NET 9, we'll likely drop support for Windows 10 and instead target the Windows 11 CRT.
130+
Note: The source-build project will likely make different choices. For example, the IBM s390x project supports RHEL 8, not CentOS 7. glibc compatibility relationships are discussed later.
131131

132132
As part of investigating this topic, we noticed the [libc compatibility model that TensorFlow uses](https://github.com/tensorflow/tensorflow/blob/f3963e82f21c9d094503568699877655f9dac508/tensorflow/tools/ci_build/devtoolset/build_devtoolset.sh#L48-L57). That model enables the use of a modern OS with an artificially old libc. We also saw that Python folks are doing something similar with their [`manylinux` approach but with docker](https://github.com/pypa/manylinux).
133133

134-
This in turn made us realize that our [`build-tools-prereqs` Docker images](https://github.com/dotnet/dotnet-buildtools-prereqs-docker/blob/main/src/centos/7/Dockerfile) are very similar to the Python approach. We don't need a new contract like `manylinux2014` since we can rely on the contract changing with each major .NET version. We need augment our build-tools-prereq scheme to also include an old glibc version, once CentOS 7 is EOL.
134+
This in turn made us realize that our [`build-tools-prereqs` CentOS 7 Docker images](https://github.com/dotnet/dotnet-buildtools-prereqs-docker/blob/0ca583b11fc3fc618335bf9394d79daba6884739/src/centos/7/amd64/Dockerfile) are very similar to the Python approach. We don't need a new contract like `manylinux2014` since we can rely on the contract changing with each major .NET version. We need to augment our [dotnet-buildtools-prereqs-docker](https://github.com/dotnet/dotnet-buildtools-prereqs-docker) scheme to also include an old glibc version, once CentOS 7 is EOL.
135135

136-
The biggest difference with our `build-tools-prereqs` images is that they are not intended for others to use, while the `manylinux` images are intended as a general community artifact. There are two primary cases where extending the use of the `build-tools-prereqs` images would be useful: enabling others to produce a .NET build with the same compatibility reach, and enabling NuGet authors to build native dependencies with matching compatibility as the underlying runtime. Addressing that topic is outside the scope of this document. This context is included to help frame how the TensorFlow, Python, and .NET solutions compare, and to inspire future conversation.
136+
The biggest difference with our `build-tools-prereqs` images is that they are not intended for others to use, while the `manylinux` images are intended as a general community artifact. There are two primary cases where extending the use of the `build-tools-prereqs` images would be useful: enabling others to produce a .NET build with the same compatibility reach, and enabling NuGet authors to build native dependencies with matching compatibility as the underlying runtime. Addressing that topic is outside the scope of this document. This context is included to help frame how the TensorFlow, Python, and .NET solutions compare, and to inspire future conversation.
137137

138138
Note: It appears that some other folks have been [reacting to CentOS 7 not being a viable compilation target](https://gist.github.com/wagenet/35adca1a032cec2999d47b6c40aa45b1) for much longer.
139139

@@ -153,25 +153,23 @@ The following table describes RIDs supported by the .NET host. It is exhaustive,
153153
| unix | All Unix-based OSes (macOS and Linux), versions, and architecture builds. |
154154
| win | All Windows versions and architecture builds. |
155155
| linux-arm | All Linux glibc-based distros, for Arm32. |
156-
| linux-armv6| All Linux glibc-based distros, for Armv6. |
157156
| linux-arm64| All Linux glibc-based distros, for Arm64. |
158157
| linux-x64 | All Linux glibc-based distros, for x64. |
159158
| linux-x86 | All Linux glibc-based distros, x86. |
160159
| linux-musl-arm64| All Linux musl-based distros, for Arm64. |
161160
| linux-musl-x64 | All Linux musl-based distros, for x64. |
162-
| osx-arm64 | All macOS versions, for Arm64.
163-
| osx-x64 | All macOS versions, for x64.
161+
| osx-arm64 | All macOS versions, for Arm64. |
162+
| osx-x64 | All macOS versions, for x64. |
164163
| win-arm64 | All Windows versions, for Arm64. |
165164
| win-x64 | All Windows versions, for x64. |
166165
| win-x86 | All Windows versions, for x86. |
167166

168-
Note: `linux-armv6` may or may not be supported. It is added for completeness.
169-
170-
Note: Singles are for processor-agnostic managed code.
171-
172-
Note: All RIDs are subject to .NET support policy. For example, .NET 7 doesn't support Ubuntu 16.04. The `linux-x64` RID doesn't include that specificity.
167+
Notes:
173168

174-
Note: `osx` is used instead of `macOS` within the RID scheme. This design change may be a good opportunity to introduce `macOS`. It probably makes sense only to do that for Arm64.
169+
- Singles are for processor-agnostic managed code.
170+
- All RIDs in the context of a .NET version are subject to .NET support policy. For example, .NET 7 doesn't support Ubuntu 16.04. The `linux-x64` RID doesn't include that specificity.
171+
- `osx` is used instead of `macOS` within the RID scheme for historical reasons.
172+
- Other distributors of .NET may extend this table, for example, to include another OS family like `freebsd` or to include a Linux distro like `ubuntu`.
175173

176174
The following table describes RIDs supported only by `runtimes.json`. It is not exhaustive.
177175

@@ -194,15 +192,15 @@ Note: `runtimes.json` will be frozen, which means that RID schemes only supporte
194192

195193
## Source-build
196194

197-
A major design tenet of the RID system is maximizing portability of code. This is particularly true for Linux. That makes sense from the perspective of Microsoft wanting to make one build of .NET available across many Linux distros, separately for both glibc and musl. It makes less sense for distros themselves building .NET from source and publishing binaries to a distro package feed.
195+
A major design tenet of the RID system is maximizing portability of code. This is particularly true for Linux. That makes sense from the perspective of Microsoft wanting to make one build of .NET available across many Linux distros, separately for both glibc and musl. It makes less sense for distros building .NET from source and publishing binaries to a distro package feed.
198196

199197
We sometimes refer to `linux-x64` (and equally to `linux-arm64` and `linux-x86`) as the "portable Linux RID". As mentioned in the libc section, this RID establishes a wide glibc compatibility range. In addition, the RID also establishes broad compatibility across distros (and their associated versions) for .NET dependencies, like OpenSSL and ICU. The way this particular form of compatibility shows up is observable but is nuanced (and isn't explained here).
200198

201199
We'll use Red Hat as an example of an organization that builds .NET from source, to complete this discussion. They have raised concerns on [source-build not playing nicely with `linux-x64`](https://github.com/dotnet/runtime/pull/62942#issuecomment-1056942235).
202200

203201
For Red Hat, it makes sense to accept and support `linux-x64` NuGet assets, but not to produce or offer them. Instead, Red Hat would want to produce `rhel-x64` runtime pack assets. It's easiest to describe this design-point in terms of concrete scenarios.
204202

205-
**NuGet packages** -- NuGet authors will typically value breadth and efficiency. For example, a package like `SkiaSharp` might target `linux-x64`, but not `rhel-x64`. There is no technical reason for that package to include distro-specific assets. Also, if the author produced a `rhel-x64` asset, they would need to consider producing an `ubuntu-x64` and other similar assets for other distros, and that's not scalable. The expectation is that the `rhel-x64` .NET supports `linux-x64` NuGet assets, enabling NuGet authors to target a minimal set of RIDs.
203+
**NuGet packages** -- NuGet authors will typically value breadth and efficiency. For example, a package like `SkiaSharp` might target `linux-x64`, [but not `rhel-x64`. There is no technical reason for that package to include distro-specific assets. Also, if the author produced a `rhel-x64` asset, they would need to consider producing an `ubuntu-x64` and other similar assets for other distros, and that's not scalable. The expectation is that the `rhel-x64` .NET supports `linux-x64` NuGet assets, enabling NuGet authors to target a minimal set of RIDs.
206204

207205
**Runtime and host packs** -- The .NET SDK doesn't include all assets that are required for all scenarios, but instead relies on many assets being available on a NuGet feed (nuget.org or otherwise). That's a good design point for a variety of reasons. Runtime packs are a concrete scenario, which are used for building self-contained apps. Red Hat should be able to (A) build RHEL-specific runtime packages, (B) publish them to a feed of their choice, and (C) enable their users to download them by specifying a RHEL-specific RID as part of a typical .NET CLI workflow. RHEL-specific runtime packs would only be compatible with Red Hat Enterprise Linux family OSes. For example, the RHEL-specific runtime for RHEL 8 would only support the default OpenSSL version that is provided in the RHEL 8 package feed.
208206

@@ -212,7 +210,7 @@ For Red Hat, it makes sense to accept and support `linux-x64` NuGet assets, but
212210
- `linux-x64`
213211
- `unix`
214212

215-
A source-built RID (here `rhel.8-x64`) will typically be distro-specific and versioned. Red Hat would naturally want to build .NET specifically and separately for RHEL versions, like RHEL7 and RHEL 8, since the packages available in each of their versioned Red Hat package feeds will be different. There might be other differences to account for as well. An unversioned RID (like `rhel-x64`) would not enable that.
213+
A source-built RID (here `rhel.8-x64`) will typically be distro-specific and versioned. Red Hat would naturally want to build .NET specifically and separately for RHEL versions](https://github.com/dotnet/designs/pull/260#discussion_r843009872), like RHEL7 and RHEL 8, since the packages available in each of their versioned Red Hat package feeds will be different. There might be other differences to account for as well. An unversioned RID (like `rhel-x64`) would not enable that.
216214

217215
This means that we'll have two forms of RIDs:
218216

0 commit comments

Comments
 (0)