Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What does the win/any runtime mean in .NET Core

I'm building a C# .NET core application and it is targeting the net452 framework. When I publish I can specify a runtime (--runtime), if I don't specify any runtime it uses win7-x64 (I assume that is because that is what my machine is running). However, I can also manually specify the runtime and it seems to accept any string I give it. However, the RID catalog seems to suggest both win as well as any are valid.

UPDATE: I don't have any good answers so I'm going to clarify my questions and add a bounty. I've also asked on the ASP.NET core forums but gotten no response.

  1. If I specify a RID of win7-x32 will my code also run on a 64 bit Windows OS?

  2. If I specify a RID of win7, what does it build, will it build the 32 bit version or the 64 bit version?

  3. If I specify a RID of win7, will my program run in Windows 8, 8.1, or 10?

  4. What does the any RID do? I understand how the portable deployment can be used on multiple platforms but how can the standalone deployment (built with a RID of any) work on Linux as well as Windows? Am I misunderstanding this RID?

  5. If I specify a RID of blah I expected an error. Instead my application was built in the bin/Release/blah directory. Did it simply default to some other runtime?

like image 800
Pace Avatar asked Jan 20 '17 14:01

Pace


People also ask

What does .NET Core runtime do?

NET Core Runtime is required to run an application and provides information about the install. To develop, build and publish an application will require an SDK.

What is runtime identifier?

RID is short for Runtime Identifier. RID values are used to identify target platforms where the application runs. They're used by . NET packages to represent platform-specific assets in NuGet packages. The following values are examples of RIDs: linux-x64 , ubuntu.

What is runtime package store?

For . NET Core 2.0, the runtime package store feature is used implicitly by an ASP.NET Core app when the app is deployed as a framework-dependent deployment app. The targets in Microsoft.

Does .NET Core use CLR?

. NET Core and . NET 5+ releases have a single product version, that is, there is no separate CLR version.


2 Answers

RIDs are used with .NET Core to resolve dependencies on packages. The root for this process of resolving dependencies is your project, which you explicitly tag with one or more RIDs. When building the project, you indicate which RID you are building against.

RIDs are defined in a forest of compatibility trees, where any node in a tree represents an execution environment that can support all of its children. Each RID is the root of such a tree.

Here is an example RID compatibility tree:

win10-x64 |- win10 |  `- win81 |     `- win8 |        `- win7 |           `- win |              `- any |                 `- base `- win81-x64    |- win81 (already included above)    `- win8-x64       |- win8 (already included above)       `- win7-x64          |- win7 (already included above)          `- win-x64             `- win (already included above) 

The full graph of RID compatibility trees is defined here:

https://github.com/dotnet/runtime/blob/master/src/libraries/pkg/Microsoft.NETCore.Platforms/runtime.json

A package can supply a different implementation for every RID if necessary. When building, if I have a dependency on that package, the build process will select the implementation closest to the root of the tree. If the tree doesn't contain any RIDs supplied by the package, then the build will fail.

There is a special kind of package called a "runtime package". Runtime packages contain native binaries that be directly loaded and executed by the host operating system. As such, these packages only supply implementations for concrete OS versions: "win7-x64", for instance, but not "win7" or "win-x64", and, say, "ubuntu.16.04-x64", but not "ubuntu.16.04", "ubuntu-x64" or "linux".

[Update: as of .NET Core 2.0, you can build for Linux-x64 to target "all" x64 versions of Linux with a single build. See https://blogs.msdn.microsoft.com/dotnet/2017/08/14/announcing-net-core-2-0/ ]

Runtime packages come into play when bundling stand-alone projects. With a stand-alone project, everything needed to run the project must be included in the build output. This means the build output must include a native binary as the entrypoint for the application. That native binary is supplied by the runtime package.

So, to address your questions:

  1. If I specify a RID of win7-x32 will my code also run on a 64 bit Windows OS?

Yes it will, but it will run in a 32-bit process. I have verified this with an app built & published from an Ubuntu dev VM and subsequently run on Windows 10 64-bit; if the app is published against win7-x32, then IntPtr.Size is 4, and if it is published against win7-x64, then IntPtr.Size is 8. It runs either way.

The win7-x32 runtime package includes a 32-bit EXE file that hosts the .NET Core runtime and then loads & runs your project, which is bundled alongside it in a DLL file with the same name.

  1. If I specify a RID of win7, what does it build, will it build the 32 bit version or the 64 bit version?

If you specify a RID of win7, it will try to find native binary builds tagged with that RID, or a compatible RID, but it won't find any. The build will fail, because there is no "win7" version of the main entrypoint EXE. You must specify either 32-bit or 64-bit (and it looks like all other platforms are 64-bit only).

I have tested this specific detail, and have found that:

  • The dotnet restore step does not fail, but also does not install a runtime for win7 (or win10).

  • The dotnet build step succeeds in compiling the test application, but then emits this error:

    Failed to make the following project runnable: helloworld (.NETCoreApp,Version=v1.1) reason: Expected coreclr library not found in package graph. Please try running dotnet restore again.

  1. If I specify a RID of win7, will my program run in Windows 8, 8.1, or 10?

Assuming you specify either win7-x86 or win7-x64, then yes. The win7-x86 or win7-x64 runtime package will supply an EXE entrypoint that is a 32-bit or 64-bit EXE, respectively, and those EXEs are native binaries that will run on any Windows version starting with Windows 7.

Note that there is no runtime package currently for Windows 8, Windows 8.1 or Windows 10 specifically. The compatibility graphs for newer Windows versions includes either win7-x86 or win7-x64, as appropriate, and so that particular runtime package ends up being used in the build, even if you target a newer RID such as win10-x64.

  1. What does the any RID do? I understand how the portable deployment can be used on multiple platforms but how can the standalone deployment (built with a RID of any) work on Linux as well as Windows? Am I misunderstanding this RID?

The any RID allows a package to supply an implementation for any RID further up the chain, because all other RIDs ultimately include any (and base) in their compatibility tree. Runtime packages, though, do not supply any implementation for any, and thus any cannot be used to build stand-alone packages.

  1. If I specify a RID of blah I expected an error. Instead my application was built in the bin/Release/blah directory. Did it simply default to some other runtime?

Your project must be configured with "type": "platform" in the dependency on Microsoft.NETCore.App. As such, no stand-alone package was built, and the resolution of supporting libraries is left to runtime, at which point the RID is supplied by the actual runtime you are using to run your app, rather than by your application's build configuration.

If your project is a library, then when you try to reference it from another project, you may encounter problems because your library is only supplying an implementation for the "blah" platform, which won't be in the compatibility tree for the RID the other project is building against. If your project is an application, then blah is being ignored.

If you reconfigure your project to produce a stand-alone package (by removing or commenting out the "type": "platform" line in project.json), you will find that it no longer builds, because it now has a dependency on the runtime packages, and there is no package for RID blah.

like image 86
Jonathan Gilbert Avatar answered Oct 15 '22 00:10

Jonathan Gilbert


I believe the official documentation linked to in the OP provided all the necessary information.

First things first

What are RIDs?

RID is short for Runtime IDentifier. RIDs are used to identify target operating systems where an application or asset (that is, assembly) will run.

It is important to note that RIDs are really opaque strings. This means that they have to match exactly for operations using them to work.

This was also quoted from GitHub

A RID is an opaque string that identifies a platform. RIDs have relationships to other RIDs by "importing" the other RID. In that way a RID is a directed graph of compatible RIDs.

Best RID Consider the partial RID-graph:

"any": {},  "win": {     "#import": [ "any" ] }, "win-x86": {     "#import": [ "win" ] }, "win-x64": {     "#import": [ "win" ] }, "win7": {     "#import": [ "win" ] }, "win7-x86": {     "#import": [ "win7", "win-x86" ] }, "win7-x64": {     "#import": [ "win7", "win-x64" ] } 

This can be visualized as a directed graph, as follows:

win7-x64    win7-x86    |   \   /    |    |   win7     |    |     |      | win-x64  |  win-x86       \  |  /         win          |         any 

As such, best RID, when evaluating for win7-x64 would be:win7-x64, win7, win-x64, win, any Similarly, when evaluating for win-x64: win-x64, win, any Note that win7 comes before win-x64 due to the import for win7 appearing before the import for win-x64 in document order.

That said, and referencing runtime.json on the CoreFX repo.

If you use this file, you will notice that some of the RIDs have an "#import" statement in them. These statements are compatibility statements. That means that a RID that has an imported RID in it can be a target for restoring packages for that RID.

Extracting only the relevant parts,

1) If I specify a RID of win7-x32 will my code also run on a 64 bit Windows OS?

"base": { },  "any": {     "#import": [ "base" ] }, ... "win": {     "#import": [ "any" ] }, ... "win7": {         "#import": [ "win" ]     }, "win7-x86": {     "#import": [ "win7", "win-x86" ] }, "win7-x64": {     "#import": [ "win7", "win-x64" ] }, ... 

2) If I specify a RID of win7, what does it build, will it build the 32 bit version or the 64 bit version?

It will build a common version that can run on both platforms. Refer to visualization above.

3) If I specify a RID of win7, will my program run in Windows 8, 8.1, or 10?

Yes. Based on the imports of the referenced versions.

"win8": {     "#import": [ "win7" ] }, "win8-x86": {     "#import": [ "win8", "win7-x86" ] }, "win8-x64": {     "#import": [ "win8", "win7-x64" ] }, "win8-arm": {     "#import": [ "win8" ] },  "win81": {     "#import": [ "win8" ] }, "win81-x86": {     "#import": [ "win81", "win8-x86" ] }, "win81-x64": {     "#import": [ "win81", "win8-x64" ] }, "win81-arm": {     "#import": [ "win81", "win8-arm" ] },  "win10": {     "#import": [ "win81" ] }, "win10-x86": {     "#import": [ "win10", "win81-x86" ] }, "win10-x64": {     "#import": [ "win10", "win81-x64" ] }, 

4) What does the any RID do?

It means that the build is compatible with any of the supported platforms and it can be a target for restoring packages for any RID.

5) If I specify a RID of blah I expected an error. Instead my application was built in the bin/Release/blah directory. Did it simply default to some other runtime?

Quoting form documentation:

All RIDs eventually map back to the root any RID.

And finally, again from documentation, take note

Although they look easy enough to use, there are some special things about RIDs that you have to keep in mind when working with them:

  • They are opaque strings and should be treated as black boxes
    • You should not construct RIDs programmatically
  • You need to use the RIDs that are already defined for the platform and this document shows that
  • The RIDs do need to be specific so don't assume anything from the actual RID value; please consult this document to determine which RID(s) you need for a given platform
like image 35
Nkosi Avatar answered Oct 15 '22 00:10

Nkosi