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.
If I specify a RID of win7-x32
will my code also run on a 64 bit Windows OS?
If I specify a RID of win7
, what does it build, will it build the 32 bit version or the 64 bit version?
If I specify a RID of win7
, will my program run in Windows 8, 8.1, or 10?
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?
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?
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.
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.
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.
. NET Core and . NET 5+ releases have a single product version, that is, there is no separate CLR version.
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:
- 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.
- 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.
- 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
.
- 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.
- 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
.
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 forwin-x64
:win-x64
,win
,any
Note thatwin7
comes beforewin-x64
due to the import forwin7
appearing before the import forwin-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 thebin/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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With