add spec for corehost
This commit is contained in:
parent
0f6562df77
commit
1257b6d3b6
1 changed files with 119 additions and 0 deletions
119
Documentation/specs/corehost.md
Normal file
119
Documentation/specs/corehost.md
Normal file
|
@ -0,0 +1,119 @@
|
|||
# corehost runtime/assembly resolution
|
||||
|
||||
The shared host locates assemblies and native libraries using a combination of: Servicing Index, Files in the application folder (aka "app-local") and files from package caches.
|
||||
|
||||
## Definitions and Formats
|
||||
|
||||
### Terms/Notes
|
||||
|
||||
* The term "Library" (Title Case) is used throughout this document to refer to a NuGet Package. We use this term because it is used in the code to represent multiple things: Packages, Projects and Framework Assemblies are all types of "Library".
|
||||
* All of the assembly resolution here refers to setting up the default assembly load context for the runtime. Further dynamic loads (plugins, etc.) can still have custom resolution logic provided by using an `AssemblyLoadContext` in the managed code. Essentially, we are setting up the necessary assemblies to launch the `Program.Main` (and all the assemblies that are statically-referenced by that).
|
||||
|
||||
### Servicing Index
|
||||
|
||||
The servicing index is loaded when the `DOTNET_SERVICING` environment variable is non-empty. When this variable is non-empty, it points to a directory that will be the **Servicing Root**. There may be platform-specific default locations, to be determined later.
|
||||
|
||||
An index file is located at the path defined by `$DOTNET_SERVICING/servicing_index.txt`. In this file are a series of lines of one of the following formats:
|
||||
|
||||
```
|
||||
# Lines starting with a '#' and blank lines are ignored.
|
||||
|
||||
# Identifies an asset from a NuGet Package that has been serviced.
|
||||
package|[Package ID]|[Package Version]|[Original Asset Relative Path]=[New Asset Path, relative to Servicing Root]
|
||||
package|System.Threading.Thread|1.2.3.4|lib/dotnet5.4/System.Threading.Thread.dll=patches/abc123/System.Threading.Thread.dll
|
||||
|
||||
# TBD: Host/Runtime servicing entries.
|
||||
```
|
||||
|
||||
Paths in this file are **always** specified using `/`, even on Windows. They must be converted to platform-specific directory separators.
|
||||
|
||||
This index is loaded when needed during the Resolution Process (see below).
|
||||
|
||||
### Dependencies File
|
||||
|
||||
The `.deps` file is a file located alongside the native host. It is stored in a CSV format, with header, of the following format:
|
||||
|
||||
```
|
||||
LibraryType,LibraryName,LibraryVersion,LibraryHash,AssetType,AssetName,AssetRelativePath,AssetServicable
|
||||
"Package","Microsoft.CodeAnalysis.Common","1.2.0-beta-20151117-04","sha512-4O3f1iRswbWDz70AGTk0tBA1ivslJUuq37FSx4d0+ZuoBFxNO4oY7ReJgndOJYefaxeTMsCVHSVHJMYOJJphtQ==","runtime","Microsoft.CodeAnalysis","lib/portable-net45+win8/Microsoft.CodeAnalysis.dll","true"
|
||||
"Package","Microsoft.CodeAnalysis.Common","1.2.0-beta-20151117-04","sha512-4O3f1iRswbWDz70AGTk0tBA1ivslJUuq37FSx4d0+ZuoBFxNO4oY7ReJgndOJYefaxeTMsCVHSVHJMYOJJphtQ==","resources","Microsoft.CodeAnalysis","lib/portable-net45+win8/fr-FR/Microsoft.CodeAnalysis.resources.dll","false"
|
||||
```
|
||||
|
||||
Fields:
|
||||
|
||||
* `LibraryType` -> The type of Library that provides the Asset. Currently always `Package` (other Library types include Projects and Framework Assemblies but these aren't relevant to `corehost`)
|
||||
* `LibraryName` -> The name of the Library that provides the Asset. For a Package, this is the Package ID
|
||||
* `LibraryVersion` -> The version of the Library that provides the Asset. For a Package, this is the Package Version
|
||||
* `LibraryHash` -> The hash of the Library that provides the Asset. For a Package, this is a hash of the `.nupkg` file. The format is `[algorithm]-[base64-encoded hash]` where `[algorithm]` must always be `sha512` (in the current version)
|
||||
* `AssetType` -> The type of the Asset within the Library. `corehost` recognizes two types: `runtime` and `native`, representing Managed Assemblies and Native Libraries respectively. These names are designed to mirror the names in `project.lock.json`.
|
||||
* `AssetName` -> The base name of the Asset. This is generally just the file name, without the extension (also removing "sub-extensions" like `ni` for native images of managed assemblies)
|
||||
* `AssetRelativePath` -> The relative path to the Asset file within the root of the package in the packages cache. Entries for localized resources will have the culture specific folder as the last directory in the relative path (i.e. `fr-FR/Foo.resources.dll`). See "Satellite Assemblies" below for more details. As with the servicing file, paths in this file **always** use `/` as a directory separator.
|
||||
* `AssetServicable` -> Indicates if the asset is servicable. `true` indicates that it is servicable, `false` indicates that it is not
|
||||
|
||||
A few notes about the format:
|
||||
|
||||
* The current code does not include the header, this is being changed.
|
||||
* All fields MUST be quoted (for simplicity), even if they don't contain a ','
|
||||
|
||||
### Files in the application folder
|
||||
|
||||
Any file with the suffix `.dll` in the same folder as the managed application being loaded (the "Application Base") will be considered a viable assembly during the resolution process. The host **assumes** that the assembly's short name is the same as the file name with the `.dll` suffix removed (yes, this is not technically required by the CLR, but we assume it for use with this host).
|
||||
|
||||
### Files from package caches
|
||||
|
||||
Only assemblies listed in the dependencies file can be resolved from a package cache. To resolve those assemblies, two environment variables are used:
|
||||
|
||||
* `DOTNET_PACKAGES` - The primary package cache. If not set, defaults to `$HOME/.nuget/packages` on Unix or `%LOCALAPPDATA%\NuGet\Packages` (TBD) on Windows. **NOTE**: Currently the host uses different folders as we are still coordinating with NuGet to get the directories right (there are compat considerations). Currently we always use `$HOME/.dnx/packages`(Unix)/`%USERPROFILE%\.dnx\packages`(Win).
|
||||
* `DOTNET_PACKAGES_CACHE` - The secondary cache. This is used by shared hosters (such as Azure) to provide a cache of pre-downloaded common packages on a faster disk. If not set, it is not used.
|
||||
|
||||
Given the Package ID, Package Version, Package Hash and Asset Relative Path provided in the dependencies file, **and the assembly is not serviced** (see the full resolution algorithm below) resolution proceeds as follows (Unix-style paths will be used for convenience but these variables and paths all apply to Windows as well):
|
||||
|
||||
1. If `DOTNET_PACKAGES_CACHE` is non-empty, read the file `$DOTNET_PACKAGES_CACHE/[Package ID]/[Package Version]/[Package Id].[Package Version].nupkg.sha512` if present. If the file is present and the content matches the `[Package Hash]` value from the dependencies file. Use that location as the Package Root and go to 3
|
||||
2. Using `DOTNET_PACKAGES`, or it's default value, use `$DOTNET_PACKAGES/[Package ID]/[Package Version]` as the Package Root
|
||||
3. Concatenate the Package Root and the Asset Relative Path. This is the path to the asset (managed assembly or native library).
|
||||
|
||||
## Assembly Resolution
|
||||
|
||||
During host start-up, the host identifies if a `.deps` file is present and loads it. It also scans the files located in the Application Base and determines the assembly name for each (using the file name). It builds a set of assembly names to be loaded by the union of the assembly names listed in `.deps` file and the assemblies located in the Application Base.
|
||||
|
||||
A `.deps` file is **not** required to successfully launch an application, but without it, all the dependent assemblies must be located within the same folder as the application. Also, since servicing is performed on the basis of packages, an application without a `.deps` file cannot use the servicing index to override the location of assemblies.
|
||||
|
||||
Given the set of assembly names, the host performs the following resolution. In some steps, the Package ID/Version/Relative Path data is required. This is only available if the assembly was listed in the deps file. If the assembly comes from the app-local folder, these resolution steps are skipped.
|
||||
|
||||
1. If there is an entry in the servicing index for the Package ID/Version/Relative Path associated with the assembly, the Servicing Root is concatenated with the New Asset Path from the index and used as the Assembly Path. This occurs **even if the assembly is also located app-local**, as long as it is also in the `.deps` file.
|
||||
2. If there is a file in the Application Base with the file name `[AssemblyName].dll`, `[AssemblyName].ni.dll`, `[AssemblyName].exe`, or `[AssemblyName].ni.exe` (in that order), it its full path is used as the Assembly Path
|
||||
3. The Assembly Path is resolved out of the Package Caches using the algorithm above (in 'Files from package caches').
|
||||
|
||||
A similar process is used to produce a list of Native Library Paths. Native libraries are listed in the `.deps` file (marked with a special `native` type token) and searched in the same way as managed assemblies (Servicing, then app-local, then package caches). The main exception is that the app-local file extensions vary by platform (`.dll` on Windows, `.so` on Linux, `.dylib` on Mac OS X)
|
||||
|
||||
Once a the list of assemblies and native libraries is produced, the host will check for duplicates. If both an `.ni.dll`/`.ni.exe` image and a `.dll`/`.exe` assembly are found for an assembly, the native image will be preferred and the IL-only assembly will be removed. The presence of two different paths for the same assembly name will be considered an error. The managed assemblies are provided in the Trusted Platform Assemblies (TPA) list for the CoreCLR during startup. The folder paths for each native library are deduplicated and provided in the Native Search Paths list for the CoreCLR during startup.
|
||||
|
||||
**NOTE**: The CLR may add support for providing a similar structure as the TPA list for native libraries (i.e. a flat list of full file paths).
|
||||
|
||||
### Satellite Assemblies
|
||||
|
||||
Satellite Assemblies (assemblies containing only embedded resources used in place of the resources provided by an assembly) are detected by path convention in the host. The convention will be to look at the last two segments of the path (the file name and the immediate parent directory name). If the parent directory matches an [IETF Language Tag](https://en.wikipedia.org/wiki/IETF_language_tag) (or more specifically, a value usable in the Culture field for a CLR Assembly Name), then the assembly is considered culture-specific (for the culture specified in that folder name). Upon determining this, the host will place the culture-neutral assemblies on the TPA list and provide the directories containing the assemblies as Platform Resource Roots to the CLR to allow it to locate the assemblies.
|
||||
|
||||
## Runtime Resolution
|
||||
|
||||
Runtime resolution is controlled by two environment variables:
|
||||
|
||||
* `DOTNET_RUNTIME_SERVICING` -> Global override for runtime
|
||||
* `DOTNET_HOME` -> Default location for runtime
|
||||
|
||||
The runtime is located by searching the following paths in order, where `APP_BASE` refers to the directory containing the managed application assembly and `LIBCORECLR` refers to the platform-specific name for the CoreCLR library (`libcoreclr.so` on Unix, `libcoreclr.dylib` on Mac OS X, `coreclr.dll` on Windows). The first path that matches is used as the path to load the CoreCLR from.
|
||||
|
||||
* `$DOTNET_RUNTIME_SERVICING/runtime/coreclr/LIBCORECLR`
|
||||
* `APP_BASE/LIBCORECLR`
|
||||
* `$DOTNET_HOME/runtime/coreclr/LIBCORECLR`
|
||||
* On Unix:
|
||||
* `/usr/local/share/dotnet/runtime/coreclr/LIBCORECLR` [1]
|
||||
* `/usr/share/dotnet/runtime/coreclr/LIBCORECLR`
|
||||
* On Windows:
|
||||
* `%LocalAppData%\dotnet\runtime\coreclr\LIBCORECLR`
|
||||
* `%ProgramFiles%\dotnet\runtime\coreclr\LIBCORECLR` [2]
|
||||
|
||||
Notes:
|
||||
|
||||
1. The Unix paths should be this way but are reversed in the actual code. Generally `/usr/local` is considered to have higher precedence than `/usr`
|
||||
2. Not yet implemented.
|
Loading…
Reference in a new issue