runtime: source-build on unknown linux distros

For source-build we want to be able to build .NET using source-build on a system where the rid is not known to .NET.

We want this build to succeed, and the rid to be known to .NET.

For the build to succeed, we need to build using another rid which is known and compatible. I think this may be possible already (to some extent) by using the DOTNET_RUNTIME_ID envvar.

For the rid to be known to .NET, it needs to know its place in the graph.

Example pseudo build commands:

Build on Fedora 35 (rid derived from os-release is fedora.35):

./build.sh --build-rid linux --parent-rids fedora,linux

Build on RHEL 8 (rid derived from os-release is rhel.8):

./build.sh --build-rid linux --parent-rids linux

Build on CentOS 8 (rid derived from os-release is centos.8):

./build.sh --build-rid linux --parent-rids rhel.8,linux

Relates to https://github.com/NuGet/Home/issues/5862, https://github.com/dotnet/source-build/issues/297.

cc @ericstj @omajid @crummel

About this issue

  • Original URL
  • State: closed
  • Created 3 years ago
  • Comments: 28 (27 by maintainers)

Most upvoted comments

I may be mistaken. It looks like the SDK did the work to pull out the runtime.json, bundle it in the SDK and provide it to NuGet. Thanks @dsplaisted, @nkolev92 https://github.com/NuGet/NuGet.Client/commit/04166a65cf687e1e62b756fd04385cf55c85863d https://github.com/dotnet/sdk/commit/27235895b381c762fe6597ceeb83b598d9012c2f

Assuming we flow the built content of Microsoft.NETCore.Platfroms from sourcebuild up through the SDK/installer then it looks like this should work. NuGet will “merge” the contents of the SDK’s runtimegraph with whatever is defined in packages. So even if someone added the public shipped platforms package it would still have your source-build defined RIDs.

The source-build user could specify it. It would be a single value.

This makes sense, we can easily add the ability to allow the source-build user to specify a new parent. I’ll add that to the current changes. I’m in the propcess of moving this over from dotnet/arcade to dotnet/runtime to make it easier to maintain. Next steps on my side are to finish this port and add it to the draft PR in dotnet runtime and move out of draft.

Is this the value you’d prefer to be the default?

It’s not clear for me what the differences are between these rids. When we build the source-build tarball, then the output packages would be for the rid of /etc/os-release.

I was pointing to the existing property reads from $([System.Runtime.InteropServices.RuntimeInformation]::RuntimeIdentifier) which should derive it’s value from /etc/os-release with an override of DOTNET_RUNTIME_ID.

Here’s what I’m imagining the interface with the user. During a source build:

  • Automatically include $([System.Runtime.InteropServices.RuntimeInformation]::RuntimeIdentifier) in RID graph
  • Automatically include PackageRID|OutputRID in RID graph
  • Both of above will be added to AdditionalRIDs property
  • When considering any unknown RID family, choose the parent based on single user-specified parent RID, lets call it AdditionalRIDsParent

Yeah, I’m actually preparing a draft PR right now. Should be available in a hour or so.

they infer the current OS’s RID

Infer was probably bad naming on my part: we infer the place in the graph but the RID is specified. There are already mechanisms today for determining what RID is being built. It can be specified or inferred. We leverage these rather than introducing anything new.

I’ve also added a property called InferRuntimeIdentifiers which can be use to add an arbitrary set of RIDs, where they belong, in the graph.

guess the parent RID

There is no guessing at parent, this follows the rules which are described in the checked in RuntimeGroups. So rather than let the caller specify a different hierarchy they add the new RID to the existing hierarchy where it belongs. As much as I can I’m trying to make it behave “as if” the change was checked into RuntimeGroups.props.

The above cases you describe should all work correctly. In those cases it looks like you’re trying to build the product as if it is a linux-<arch> build but then also add RIDs to the graph for some new version of a known distro. In those cases you would need to specify the InferRuntimeIdentifiers (which I think is behaving like the --parent-rids command). So InferRuntimeIdentifiers=centos.10 would add centos.10 RIDs to the graph as if the change was made here, inheriting from rhel: https://github.com/dotnet/runtime/blob/366cd23a82fc44ea2c613c36bd4bfdbf8c310e56/src/libraries/Microsoft.NETCore.Platforms/pkg/runtimeGroups.props#L51-L57

I think I’ll rename InferRuntimeIdentifiers to AddRuntimeIdentifiers. I’ll also refine some of the tests in arcade to better illustrate how this is working. I

Unfortunately, as packagers of source-build, we encounter this once every Fedora (or any other distro, I suspect) release. We build a package, at some point after our build, Fedora’s development branch changes it’s version (eg, 34 -> 35). We then have to use the last build to build the next one. Users shouldn’t get to see it - unless they are running the development branch - but we, packagers, will.

With what is proposed, both the first phase and second phase should work when the platform rid is not yet known. So I think this will work.

I don’t know how this would interact with the existing properties/parameters, and configurations. We need to figure that out.

When we use source-build there are two steps:

  • First https://github.com/dotnet/source-build is used on a system to generate a tarball. The rid may be not known to .NET so we want to be able to specify a compatible rid (SourceBuildRid).
  • Then that tarball is used on another system (TargetRid, e.g. fedora.32-x64) to generate a .NET installer for that system.

We would like the tarball to be usable on a range of target distros. So, the tarball would target something common (BuildRid, like linux-x64).

TargetRid can be a unknown rid to .NET. As part of the build, .NET needs to learn how that rid connects to known rids (TargetRidGraph, e.g. fedora.32 -> fedora -> linux).

For example. We run source-build on linux-x64 to generate a tarball that is usable on linux-arm64, that is used on fedora.32-arm64, with rid graph fedora.32 -> fedora -> linux, gives us these values:

SourceBuildRid=linux-x64
BuildRid=linux-arm64
TargetRid=fedora.32-arm64
TargetRidGrah=fedora,linux

Describe what needs to be specified, vs what is calculated from the system

TargetRid is calculated when building .NET. The other values can be specified.

Is cross-targeting relevant, or perhaps required?

We don’t have a need to generate cross-target tarballs. So SourceBuildRid = BuildRid for our use-cases. We do want the source-build tarball to be usable on multiple platforms (TargetRid is compatible with BuildRid).

@ericstj is it more clear?

cc @MichaelSimons @dleeapho @omajid

It would be good to understand if this is sufficient or if you would also need to modify the shared-framework’s deps file (where the RID fallbacks live) in the tool shared framework. Doing the latter is possible but grows the complexity of this.

If it doesn’t work already, probably we can pick up DOTNET_RUNTIME_ID in a few more places and avoid the complexity.