From 3de7e8824482470cc9cc7114743d0374c7f714f3 Mon Sep 17 00:00:00 2001 From: vitek-karas Date: Wed, 13 Mar 2019 06:16:50 -0700 Subject: [PATCH 1/9] Design proposal for install locations --- accepted/install-locations.md | 227 ++++++++++++++++++++++++++++++++++ 1 file changed, 227 insertions(+) create mode 100644 accepted/install-locations.md diff --git a/accepted/install-locations.md b/accepted/install-locations.md new file mode 100644 index 000000000..6357318fc --- /dev/null +++ b/accepted/install-locations.md @@ -0,0 +1,227 @@ +# Install location search for .NET Core + +.NET Core has several cases where it needs to search for the install location of the runtime and SDKs. This document described the proposed algorithm for how this search will be done on all the supported platforms. + +## .NET Core install layout +The content of a .NET Core install location always follows the same layout. The directory structure is the same on all platforms, file names may differ to conform with the platform specific requirements. (Below sample uses file names for Windows): +* `./dotnet.exe` - the "muxer" which is used to execute apps and issue dotnet CLI commands. +* `./host/fxr//hostfxr.dll` - this library contains all the logic to resolve framework references and select SDK. Regardless of application, the latest available version is used. +* `./shared` - contains shared frameworks. + * `./Microsoft.NETCore.App/` - the root framework which contains the .NET Core runtime. This framework contains `hostpolicy.dll` which is the entry point called by the `hostfxr` to run the app. Applications can choose which version to use. + * `.//` - any other shared framework. Applications can choose which version to use. +* `./sdk/` - only installed when .NET Core SDK is installed - contains the SDK tools. Users can choose which version to use. + + +## Installation types +.NET Core can be installed in several ways, each provides a different location and expected behavior. Each such location will contain the .NET Core install layout described above. + +### Global install to default location +This is the most common case where an installer installs the runtime (and potentially SDK) to a global default location accessible to everything on the system (and by all users). +* Windows + * 32-bit on 64-bit OS - `%ProgramFiles(x86)%\dotnet` + * Otherwise - `%ProgramFiles%\dotnet` +* Linux - the host searches in `/usr/share/dotnet` as a fallback, but the installer may pick a different default based on the requirements of the specific distro/configuration. In such case the install is effectively just like the global install to custom location described below. If correctly registered the host will search the custom location first. +* macOS - `/usr/local/share/dotnet` + +*This type of install is supported by .NET Core 2.2 and earlier.* + +### Global install to custom location +.NET Core is installed globally for the machine but into a non-default (custom) location. The location of the install is stored in platform specific configuration so that it can be found by everything on the system (and by all users). + +This type of install should effectively behave the same as install to the default location. Can be used to put .NET Core on a different drive to save space on the system drive, or to serve other purposes. + +*This type of install will for sure be supported by .NET Core 3.0 on Windows, other cases are not yet committed.* + +### Per-user install +.NET Core installation which is per-user, thus doesn't require admin/root access to the machine. Otherwise it should behave just like a global install, but only accessible to the user which installed it. + +There should be a default location specific for each platform - up for discussion. + +There would also be a platform specific way to store this location in some kind of configuration so that it can be found by all apps for the given user. + +*This type of install is not yet planned for any specific .NET Core release.* + +### Private install (also called x-copy install) +.NET Core is "installed" by simply creating the right layout on the disk with the right files, there's no system registration mechanism attached to it (typically called x-copy deployment). + +This can be used for +* Project-local .NET Core SDK/runtime (for example most dotnet repos use this) +* Experimentation + +As such it's actually desirable that creating such installation doesn't affect anything which didn't opt into using it. + +*This type of install is supported by .NET Core 2.2 and earlier.* + +### Self-contained apps +Technically speaking self-contained apps also "install" a private copy of the runtime, but they don't use the same layout and such installation is only usable by the app itself. So for the purposes of this document, self-contained apps are largely out of scope. + + +## Components +These are the components of .NET Core which must be aware of the install location: +* The host (muxer (`dotnet`), `apphost`, `comhost`, ...) - the host needs to be able to find the location to search for + * Latest version of `hostfxr` to use. + * Shared frameworks + * SDKs +* Installer - the installer needs to put the files into the right layout and register the install location with the system configuration (if applicable) +* Applications + * If the application is using the muxer (`dotnet`) it needs to be able to find it. This applies to tools like MSBuild or VS as well. + * Certain tools (installers, development tools) may need to determine if .NET Core is installed and which versions are available. + + +## Servicing considerations +The algorithm which determines where to search, is to some degree contained in all the components mentioned above. Changes to the algorithm (for example introduction of a new default location or new install type) need to be applied to all of these components. + +Unfortunately some of these components are hard to service: +* The muxer relies on the caller to locate it, then it's shared by all versions installed in any given location. Updating it is troublesome as it typically require a system reboot (may be in use by running applications). +* The `hostfxr` is relatively easy to service since the installer places a newer version side-by-side and relies on the host to pick the latest available version. The complexity comes from the fact that it has to work with all versions of the runtime/sdk. +* App-contained hosts (`apphost`, `comhost`, `ijwhost`, `nethost`) these are libraries which are shipped with the apps and thus fully owned/serviced by the app. They need to know how to find install locations to locate shared frameworks. + +The biggest problem is with the app-contained hosts which we can't service in any way. So introducing new install types or changing the default location can be breaking for apps using old hosts. + +The problem already exists since the `apphost` has been shipped in .NET Core 2.1 with support for framework dependent apps. Fortunately this feature is not widely used yet. + +In .NET Core 3.0 the situation will be very different. Framework dependent `apphost` is the default for apps. Scenarios requiring the other hosts are also likely to be relatively common (COM, IJW, native hosting). So the hosts which we ship with .NET Core 3.0 will be spread across all machines running .NET Core (not just development but production as well) without any ability to service them directly. + +This means that .NET Core 3.0 is the last chance to get the algorithms for install locations modified in "breaking ways". Future release will very likely have to be 100% backward compatible in this regard. + + +## Proposal for 3.0 + +### Globally registered install location :new: +This is by far the most common case and in 3.0 we want to provide a way to globally install to a custom location. The typical case will still be to install into the default location, but custom location should be possible. Either location should behave the same. + +To achieve this the install location must be recorded in some system-wide configuration in a fixed location which is well-known. + +* Windows - the installer will store the install location in 32-bit registry (for both 32-bit and 64-bit installations): + * `HKLM\SOFTWARE\dotnet\Setup\InstalledVersions\\InstallLocation` - where `` is one of the `x86`, `x64`, `arm` or `arm64`. + Note that this registry key is "redirected" that means that 32-bit processes see different copy of the key then 64bit processes. So it's important that both installers and the host access only the 32-bit view of the registry. +* Linux and macOS - the installer will store the install location in a text file + * `/etc/dotnet/install_location` - the file will contain a single line which is the path. + +The muxer (`dotnet.exe`) is registered on the system-wide `PATH` environment variable. + +### Per-user registered install location :new: +This will allow installs to per-user directories (no need for admin/root access). It's to be decided if we will actually create an installer which does this. Once installed the per-user install should take precedence over the global one, but otherwise should be available to all processes running under the respective user. + +To achieve this the install location must be recorded in some per-user configuration in a fixed location which is well-known. + +* Windows - the installer will store the install location in registry: + * `HKCU\SOFTWARE\dotnet\Setup\InstalledVersions\\InstallLocation` - where `` is one of the `x86`, `x64`, `arm` or `arm64`. + Note that this key is "shared" meaning both 32-bit and 64-bit processes see the same values. +* Linux and macOS - the installer will store the install location in a text file + * `$HOME/.dotnet/install_location` - the file will contain a single line which is the path. + +The muxer (`dotnet`) is registered on the per-user `PATH` environment variable and in such a way that it wins over any globally installed one. + +### Private install location +This allows users to install private copy of .NET Core into any directory. This copy should not be used by anything unless explicitly asked for. + +There is not installer for this scenario, these installs are produced by simply copying the right directory structure into a custom location. + +*This mechanism already exists in .NET Core 2.2.* + +If the muxer (`dotnet`) is used then it must be invoked directly from the private install location (it's not registered on `PATH` in any way). +If other hosts are used then the private install location must be specified in environment variable: +* `DOTNET_ROOT` +* `DOTNET_ROOT(x86)` for 32-bit process running on 64-bit Windows. + + +## Host behavior for 3.0 + +### `hostfxr` search +`dotnet` only looks right next to itself. + +All other hosts will search for the first location which exists in this order: +* the directory where the host resides (this is important mostly for `apphost` as self-contained apps will have the `hostfxr` in the same directory). +* `DOTNET_ROOT` (or `DOTNET_ROOT(x86)`) environment variable, in the `host/fxr/` subdirectory. +* :new: per-user registered install location, in the `/host/fxr/` subdirectory + * Windows - `HKCU\SOFTWARE\dotnet\Setup\InstalledVersions\\InstallLocation` + * Linux/macOS - `$HOME/.dotnet/install_location` +* :new: global registered install location, in the `/host/fxr/` subdirectory + **We've committed to support this on Windows for .NET Core 3.0** + * Windows - `HKLM\SOFTWARE\dotnet\Setup\InstalledVersions\\InstallLocation` (32-bit view) + * Linux/macOS - `/etc/dotnet/install_location` +* default global location, in the `/host/fxr/` subdirectory + * Windows (32-bit process on 64-bit Windows) - `%ProgramFiles(x86)%\dotnet` + * Windows (everything else) - `%ProgramFiles%\dotnet` + * Linux - `/usr/share/dotnet` + * macOS - `/usr/local/share/dotnet` + +In each case with the `` subdirectory, the latest available version as per SemVer 2.0 rules will be selected. Note that the algorithm picks the first location which exists, and only then looks for the `/host/fxr/` subdirectory, and if that doesn't exist, or the library is missing it will fail. + +### Framework and SDK search +All hosts use the same logic. + +Both framework and SDK search uses the same logic, the only difference is that frameworks are in the `share` subdirectory, while SDKs are in the `sdk` subdirectory of the install location. +In both cases all locations listed below are searched and the complete list of all available SDKs/Frameworks is combined before making a choice which one will be used (based on version requirements). + +Search locations: +* the location of the `hostfxr` used. See the `hostfxr` search algorithm above. This means that `DOTNET_ROOT` has effect on framework and SDK search as well. +* If multi-level lookup is enabled (by default it is, can be disabled via `DOTNET_MULTILEVEL_LOOKUP=0` environment variable) + * :new: per-user registered install location + * Windows - `HKCU\SOFTWARE\dotnet\Setup\InstalledVersions\\InstallLocation` + * Linux/macOS - `$HOME/.dotnet/install_location` + * :new: global registered install location + **We've committed to support this on Windows for .NET Core 3.0** + * Windows - `HKLM\SOFTWARE\dotnet\Setup\InstalledVersions\\InstallLocation` (32-bit view) + * Linux/macOS - `/etc/dotnet/install_location` + * default global location, in the `/host/fxr/` subdirectory + * Windows (32-bit process on 64-bit Windows) - `%ProgramFiles(x86)%\dotnet` + * Windows (everything else) - `%ProgramFiles%\dotnet` + * :new: Linux - `/usr/share/dotnet` + * :new: macOS - `/usr/local/share/dotnet` + +*Note: The above means that on Linux/macOS in 2.2 the multi-level lookup was effectively non-functional, as there were no search paths for it. Part of the 3.0 changes is to change that and make Linux/macOS work similarly to Windows in this case as well.* + + +## Open questions + +### Support for per-user installation +So far there's no support for per-user installation. It would make sense to add support for this as we may need it in the future. For example VS Code per-user installation can't install .NET Core and thus .NET Core doesn't work in it out of the box. A system wide install of .NET Core is required and has to be done as a separate step which requires admin/root access. + +If there's at least some sense of future scenarios for this we should add the support for this into the hosts. As we won't get a chance to really update the algorithms in the hosts due to servicing problems described above. + +We can not ship any installers like this in .NET Core 3.0, just have support for it in the hosts. Later on when we get the scenario we can ship a new installer and everything will just work. + +#### Default location for per-user installation +If we decide to provide per-user installation it should have a good default location. +* Windows - `%HOMEPATH%\.dotnet\` is probably the best. `%HOMEPATH%\.dotnet` already exists and is used for example for global tools and NuGet fallback cache. +* Linux - `$HOME/.dotnet` probably. The location already exists and stores global tools. +* macOS - `$HOME/.dotnet` (or whatever is the equivalent where we store global tools). + +Note that the host would not look for the default per-user location, it would solely rely on the registration mechanism described above, so the default per-user location is really only a convenience feature of the installer. + + +### Make muxer less special +As mentioned above, the muxer has certain specific behavior: +* It only looks next to itself when searching for `hostfxr`. +* It ignores `DOTNET_ROOT` environment variable. + +#### Framework and SDK search +I think the muxer should use `DOTNET_ROOT` to resolve frameworks and SDKs just like all the other hosts (the actual implementation mechanism aside). The current discrepancy is simply unexpected and makes certain scenarios unnecessarily complex (for example VS can't really use private installs because of this, since it always uses the muxer from path). + +In itself this change has no real downside. It has a small potential for being breaking: If an application uses the muxer and also has the `DOTNET_ROOT` set, previously the environment variable would be ignored and thus the app would only find frameworks/SDKs in the global locations. After the change to muxer, the muxer would suddenly also find frameworks/SDKs in the custom location. +* For frameworks this is very little risk. The only observable change would be to an app which for example requires framework version `2.0.0`, but the machine only has `2.1.0` in the global location. If the custom location in `DOTNET_ROOT` would have for example `2.0.1` then after the change the app would start using the private `2.0.1` instead. In theory this is for the better as that framework better fulfills the app requirements. +* For SDKs this is of a slightly higher risk. If the custom location in `DOTNET_ROOT` contains SDK with higher version than that available in global location, the default selection would be the higher version from the custom location. If the app uses the SDK to create new applications this might also change the TFM of the created apps. SDKs should be backward compatible though, so the newer SDK should work fine on older apps anyway. + +#### `hostfxr` search +Where the muxer should search for `hostfxr` is a more complicated issue. +As of 2.2 only the location right next to the muxer is considered. This effectively means that `hostfxr` should always be equal or newer version than the muxer itself. + +Note that search for `hostfxr` only looks for first available location. Unlike frameworks/SDKs which search all available locations at once. So for `hostfxr` the algorithm will not find the absolute highest version from all locations, only the highest version from the first available location. + +If the muxer doesn't change and only uses `hostfxr` next to itself: +* Combined with multi-level lookup and the above suggested support for `DOTNET_ROOT` would mean that potentially lower version `hostfxr` will try to work with higher version frameworks, and specifically higher version `hostpolicy`. This is a case which already exists in 2.2, but is probably not very common. It introduces strict backward compatibility requirements on `hostpolicy` interface. We already treat both `hostfxr` and `hostpolicy` APIs as public and thus needing backward compat behavior, this just makes it a bit more demanding. +* Due to the above, potential new features supported by higher versions would not be available in this scenario as the `hostfxr` would not support those. + +If the muxer changes then the question is how much: +* Currently we only support using muxer which has `hostfxr` next to itself, otherwise it always fails. With the change that would no longer be absolutely necessary. +* It can use the exact same algorithm as `apphost` uses, which would make it consistent, but it would expand the current behavior quite a bit (not only `DOTNET_ROOT` but also globally registered locations would be considered). +* Alternatively it could only use `DOTNET_ROOT` and its location (`DOTNET_ROOT` would need to be preferred for it to make a difference). +* Another consideration is reacting to multi-level lookup in `hostfxr` search as well. This would unify the probing logic for `hostfxr` with that for frameworks and SDKs. This is the only option which would effectively guarantee the usage of highest available version of `hostfxr` and thus effectively remove the problem of using older `hostfxr` with newer `hostpolicy`. + +Looking for recommendations. + + +### Describe targeting packs +In .NET Core 3.0 aside from the shared frameworks (which are effectively also runtime packs) there's also the notion of targeting packs. The document might mention them, where they live and if the installation types have any effect on their behavior. \ No newline at end of file From 0abcd4fccf1b6d54747e97f846c38b52d6e6527b Mon Sep 17 00:00:00 2001 From: vitek-karas Date: Wed, 13 Mar 2019 15:41:56 -0700 Subject: [PATCH 2/9] PR feedback - more to come --- accepted/install-locations.md | 34 ++++++++++++++++++++++++---------- 1 file changed, 24 insertions(+), 10 deletions(-) diff --git a/accepted/install-locations.md b/accepted/install-locations.md index 6357318fc..d8e0f076d 100644 --- a/accepted/install-locations.md +++ b/accepted/install-locations.md @@ -23,14 +23,25 @@ This is the most common case where an installer installs the runtime (and potent * Linux - the host searches in `/usr/share/dotnet` as a fallback, but the installer may pick a different default based on the requirements of the specific distro/configuration. In such case the install is effectively just like the global install to custom location described below. If correctly registered the host will search the custom location first. * macOS - `/usr/local/share/dotnet` -*This type of install is supported by .NET Core 2.2 and earlier.* +Typically the muxer from this install is registered to be readily accessible without specifying full path. The exact mechanism is platform specific, for example on Windows this means that the muxer is added to the `PATH`. + +*This type of install is supported on all versions of .NET Core.* ### Global install to custom location .NET Core is installed globally for the machine but into a non-default (custom) location. The location of the install is stored in platform specific configuration so that it can be found by everything on the system (and by all users). This type of install should effectively behave the same as install to the default location. Can be used to put .NET Core on a different drive to save space on the system drive, or to serve other purposes. +Typically the muxer from this install is registered to be readily accessible without specifying full path. The exact mechanism is platform specific, for example on Windows this means that the muxer is added to the `PATH`. + +Installer behavior: +* There can only be one globally registered location. +* The installer should query the system for existing .NET Core global installs. If it finds any, it should only install to the already registered location, it should not install to a new location. + +*Custom install locations are supported for .NET Core 3.0 on Windows, other cases are not yet committed.* -*This type of install will for sure be supported by .NET Core 3.0 on Windows, other cases are not yet committed.* +Global installs (both default or custom location) are registered in a well know location: +* Windows - registry `HKLM\SOFTWARE\dotnet\Setup\InstalledVersions\\InstallLocation` (32-bit view only) +* Linux/macOS - file `/etc/dotnet/install_location.conf` ### Per-user install .NET Core installation which is per-user, thus doesn't require admin/root access to the machine. Otherwise it should behave just like a global install, but only accessible to the user which installed it. @@ -45,12 +56,13 @@ There would also be a platform specific way to store this location in some kind .NET Core is "installed" by simply creating the right layout on the disk with the right files, there's no system registration mechanism attached to it (typically called x-copy deployment). This can be used for -* Project-local .NET Core SDK/runtime (for example most dotnet repos use this) +* Project-local .NET Core SDK/runtime. Most typically used to have a stable environment for build and related tools to run with - regardless of what is available on the machine. (For example almost all dotnet repos use this approach.) * Experimentation As such it's actually desirable that creating such installation doesn't affect anything which didn't opt into using it. +Using this install must be intentional/explicit, either by using full path to invoke the muxer or by setting environment variable (`DOTNET_ROOT`). -*This type of install is supported by .NET Core 2.2 and earlier.* +*This type of install is supported on all versions of .NET Core.* ### Self-contained apps Technically speaking self-contained apps also "install" a private copy of the runtime, but they don't use the same layout and such installation is only usable by the app itself. So for the purposes of this document, self-contained apps are largely out of scope. @@ -78,9 +90,9 @@ Unfortunately some of these components are hard to service: The biggest problem is with the app-contained hosts which we can't service in any way. So introducing new install types or changing the default location can be breaking for apps using old hosts. -The problem already exists since the `apphost` has been shipped in .NET Core 2.1 with support for framework dependent apps. Fortunately this feature is not widely used yet. +The problem already exists since the `apphost` has been shipped in .NET Core 2.2 with support for framework dependent apps. The feature is used only occasionally. The most common case is probably dotnet global tools (`dotnet tool install -g `) which create framework dependent `apphost` for each installed tool. -In .NET Core 3.0 the situation will be very different. Framework dependent `apphost` is the default for apps. Scenarios requiring the other hosts are also likely to be relatively common (COM, IJW, native hosting). So the hosts which we ship with .NET Core 3.0 will be spread across all machines running .NET Core (not just development but production as well) without any ability to service them directly. +In .NET Core 3.0 framework dependent apps use an `apphost` by default, which makes this case far more prevalent. Scenarios requiring the other hosts are also likely to be relatively common (COM, IJW, native hosting). So the hosts which we ship with .NET Core 3.0 will be spread across all machines running .NET Core (not just development but production as well) without any ability to service them directly. This means that .NET Core 3.0 is the last chance to get the algorithms for install locations modified in "breaking ways". Future release will very likely have to be 100% backward compatible in this regard. @@ -96,9 +108,9 @@ To achieve this the install location must be recorded in some system-wide config * `HKLM\SOFTWARE\dotnet\Setup\InstalledVersions\\InstallLocation` - where `` is one of the `x86`, `x64`, `arm` or `arm64`. Note that this registry key is "redirected" that means that 32-bit processes see different copy of the key then 64bit processes. So it's important that both installers and the host access only the 32-bit view of the registry. * Linux and macOS - the installer will store the install location in a text file - * `/etc/dotnet/install_location` - the file will contain a single line which is the path. + * `/etc/dotnet/install_location.conf` - the file will contain a single line which is the path. -The muxer (`dotnet.exe`) is registered on the system-wide `PATH` environment variable. +The muxer is registered on the system in such a way that it is readily accessible without providing full path to it. The exact mechanism is platform specific and outside of the scope of this document. (For example on Windows it's added to `PATH`) ### Per-user registered install location :new: This will allow installs to per-user directories (no need for admin/root access). It's to be decided if we will actually create an installer which does this. Once installed the per-user install should take precedence over the global one, but otherwise should be available to all processes running under the respective user. @@ -157,7 +169,7 @@ In both cases all locations listed below are searched and the complete list of a Search locations: * the location of the `hostfxr` used. See the `hostfxr` search algorithm above. This means that `DOTNET_ROOT` has effect on framework and SDK search as well. -* If multi-level lookup is enabled (by default it is, can be disabled via `DOTNET_MULTILEVEL_LOOKUP=0` environment variable) +* If multi-level lookup is enabled (by default it is, can be disabled via `DOTNET_MULTILEVEL_LOOKUP=0` environment variable), then the following locations are searched as well: * :new: per-user registered install location * Windows - `HKCU\SOFTWARE\dotnet\Setup\InstalledVersions\\InstallLocation` * Linux/macOS - `$HOME/.dotnet/install_location` @@ -170,8 +182,10 @@ Search locations: * Windows (everything else) - `%ProgramFiles%\dotnet` * :new: Linux - `/usr/share/dotnet` * :new: macOS - `/usr/local/share/dotnet` +* Else multi-level lookup is disabled, no other search locations are considered. -*Note: The above means that on Linux/macOS in 2.2 the multi-level lookup was effectively non-functional, as there were no search paths for it. Part of the 3.0 changes is to change that and make Linux/macOS work similarly to Windows in this case as well.* +*Note: The above means that on Linux/macOS in 2.2 the multi-level lookup was effectively non-functional, as there were no search paths for it. Part of the 3.0 changes is to change that and make Linux/macOS work similarly to Windows in this case as well.* +*Note: The multi-level lookup feature in its current form seems to be rather confusing and there are discussions around phasing it out. See dotnet/core-setup#3606. If there's no change in that area in .NET Core 3.0 we should do what's proposed here as it makes all platforms consistent.* ## Open questions From 235764cd90d72f26fdc6eec9cd64229cff9db48c Mon Sep 17 00:00:00 2001 From: Vitek Karas Date: Thu, 14 Mar 2019 04:39:13 -0700 Subject: [PATCH 3/9] Remove per-user install --- accepted/install-locations.md | 75 +++++++++++------------------------ 1 file changed, 24 insertions(+), 51 deletions(-) diff --git a/accepted/install-locations.md b/accepted/install-locations.md index d8e0f076d..588f9b0a4 100644 --- a/accepted/install-locations.md +++ b/accepted/install-locations.md @@ -43,17 +43,8 @@ Global installs (both default or custom location) are registered in a well know * Windows - registry `HKLM\SOFTWARE\dotnet\Setup\InstalledVersions\\InstallLocation` (32-bit view only) * Linux/macOS - file `/etc/dotnet/install_location.conf` -### Per-user install -.NET Core installation which is per-user, thus doesn't require admin/root access to the machine. Otherwise it should behave just like a global install, but only accessible to the user which installed it. - -There should be a default location specific for each platform - up for discussion. - -There would also be a platform specific way to store this location in some kind of configuration so that it can be found by all apps for the given user. - -*This type of install is not yet planned for any specific .NET Core release.* - ### Private install (also called x-copy install) -.NET Core is "installed" by simply creating the right layout on the disk with the right files, there's no system registration mechanism attached to it (typically called x-copy deployment). +.NET Core is "installed" by simply creating the right layout on the disk with the right files, there's no system registration mechanism attached to it (typically called x-copy deployment). The most common way is to unzip a build into a directory. This can be used for * Project-local .NET Core SDK/runtime. Most typically used to have a stable environment for build and related tools to run with - regardless of what is available on the machine. (For example almost all dotnet repos use this approach.) @@ -100,9 +91,11 @@ This means that .NET Core 3.0 is the last chance to get the algorithms for insta ## Proposal for 3.0 ### Globally registered install location :new: -This is by far the most common case and in 3.0 we want to provide a way to globally install to a custom location. The typical case will still be to install into the default location, but custom location should be possible. Either location should behave the same. +This is by far the most common case and in 3.0 we want to provide a way to globally install to a custom location. The typical case will still be to install into the default location, but custom location should be possible. Either location should behave the same and which one is used is solely decision of the installer. -To achieve this the install location must be recorded in some system-wide configuration in a fixed location which is well-known. +Note that the installer should try to avoid creating two global locations as only one can be registered. So if there is already some version installed it should only add to that location and create a new one. The only way to get two global locations should be to first install 3.0 into custom location and then install 2.* which always installs to the default location. + +To achieve the desired behavior the install location must be recorded in some system-wide configuration in a fixed location which is well-known. * Windows - the installer will store the install location in 32-bit registry (for both 32-bit and 64-bit installations): * `HKLM\SOFTWARE\dotnet\Setup\InstalledVersions\\InstallLocation` - where `` is one of the `x86`, `x64`, `arm` or `arm64`. @@ -112,31 +105,18 @@ To achieve this the install location must be recorded in some system-wide config The muxer is registered on the system in such a way that it is readily accessible without providing full path to it. The exact mechanism is platform specific and outside of the scope of this document. (For example on Windows it's added to `PATH`) -### Per-user registered install location :new: -This will allow installs to per-user directories (no need for admin/root access). It's to be decided if we will actually create an installer which does this. Once installed the per-user install should take precedence over the global one, but otherwise should be available to all processes running under the respective user. - -To achieve this the install location must be recorded in some per-user configuration in a fixed location which is well-known. - -* Windows - the installer will store the install location in registry: - * `HKCU\SOFTWARE\dotnet\Setup\InstalledVersions\\InstallLocation` - where `` is one of the `x86`, `x64`, `arm` or `arm64`. - Note that this key is "shared" meaning both 32-bit and 64-bit processes see the same values. -* Linux and macOS - the installer will store the install location in a text file - * `$HOME/.dotnet/install_location` - the file will contain a single line which is the path. - -The muxer (`dotnet`) is registered on the per-user `PATH` environment variable and in such a way that it wins over any globally installed one. - ### Private install location This allows users to install private copy of .NET Core into any directory. This copy should not be used by anything unless explicitly asked for. There is not installer for this scenario, these installs are produced by simply copying the right directory structure into a custom location. -*This mechanism already exists in .NET Core 2.2.* - If the muxer (`dotnet`) is used then it must be invoked directly from the private install location (it's not registered on `PATH` in any way). If other hosts are used then the private install location must be specified in environment variable: * `DOTNET_ROOT` * `DOTNET_ROOT(x86)` for 32-bit process running on 64-bit Windows. +*Note: this type of install is supported in all versions of .NET Core and there are no changes proposed to how it's created and used.* + ## Host behavior for 3.0 @@ -146,9 +126,6 @@ If other hosts are used then the private install location must be specified in e All other hosts will search for the first location which exists in this order: * the directory where the host resides (this is important mostly for `apphost` as self-contained apps will have the `hostfxr` in the same directory). * `DOTNET_ROOT` (or `DOTNET_ROOT(x86)`) environment variable, in the `host/fxr/` subdirectory. -* :new: per-user registered install location, in the `/host/fxr/` subdirectory - * Windows - `HKCU\SOFTWARE\dotnet\Setup\InstalledVersions\\InstallLocation` - * Linux/macOS - `$HOME/.dotnet/install_location` * :new: global registered install location, in the `/host/fxr/` subdirectory **We've committed to support this on Windows for .NET Core 3.0** * Windows - `HKLM\SOFTWARE\dotnet\Setup\InstalledVersions\\InstallLocation` (32-bit view) @@ -161,6 +138,8 @@ All other hosts will search for the first location which exists in this order: In each case with the `` subdirectory, the latest available version as per SemVer 2.0 rules will be selected. Note that the algorithm picks the first location which exists, and only then looks for the `/host/fxr/` subdirectory, and if that doesn't exist, or the library is missing it will fail. +The reason for including the default global location is so that 3.0 host can find 2.* installs since those are not registered in the system. All 3.0 and higher installs should be registered. + ### Framework and SDK search All hosts use the same logic. @@ -168,11 +147,9 @@ Both framework and SDK search uses the same logic, the only difference is that f In both cases all locations listed below are searched and the complete list of all available SDKs/Frameworks is combined before making a choice which one will be used (based on version requirements). Search locations: -* the location of the `hostfxr` used. See the `hostfxr` search algorithm above. This means that `DOTNET_ROOT` has effect on framework and SDK search as well. +* the location of the `hostfxr` used. See the `hostfxr` search algorithm above. This means that `DOTNET_ROOT` has effect on framework and SDK search as well since the `hostfxr` search will consider it. +*If the `hostfxr` is found in the `DOTNET_ROOT` location (should happen pretty much always when the variable is non-empty), then that location will be part of the search locations for frameworks/SDKs.* * If multi-level lookup is enabled (by default it is, can be disabled via `DOTNET_MULTILEVEL_LOOKUP=0` environment variable), then the following locations are searched as well: - * :new: per-user registered install location - * Windows - `HKCU\SOFTWARE\dotnet\Setup\InstalledVersions\\InstallLocation` - * Linux/macOS - `$HOME/.dotnet/install_location` * :new: global registered install location **We've committed to support this on Windows for .NET Core 3.0** * Windows - `HKLM\SOFTWARE\dotnet\Setup\InstalledVersions\\InstallLocation` (32-bit view) @@ -184,28 +161,14 @@ Search locations: * :new: macOS - `/usr/local/share/dotnet` * Else multi-level lookup is disabled, no other search locations are considered. +The reason for including the default global location is so that 3.0 host can find 2.* installs since those are not registered in the system. All 3.0 and higher installs should be registered. + *Note: The above means that on Linux/macOS in 2.2 the multi-level lookup was effectively non-functional, as there were no search paths for it. Part of the 3.0 changes is to change that and make Linux/macOS work similarly to Windows in this case as well.* *Note: The multi-level lookup feature in its current form seems to be rather confusing and there are discussions around phasing it out. See dotnet/core-setup#3606. If there's no change in that area in .NET Core 3.0 we should do what's proposed here as it makes all platforms consistent.* ## Open questions -### Support for per-user installation -So far there's no support for per-user installation. It would make sense to add support for this as we may need it in the future. For example VS Code per-user installation can't install .NET Core and thus .NET Core doesn't work in it out of the box. A system wide install of .NET Core is required and has to be done as a separate step which requires admin/root access. - -If there's at least some sense of future scenarios for this we should add the support for this into the hosts. As we won't get a chance to really update the algorithms in the hosts due to servicing problems described above. - -We can not ship any installers like this in .NET Core 3.0, just have support for it in the hosts. Later on when we get the scenario we can ship a new installer and everything will just work. - -#### Default location for per-user installation -If we decide to provide per-user installation it should have a good default location. -* Windows - `%HOMEPATH%\.dotnet\` is probably the best. `%HOMEPATH%\.dotnet` already exists and is used for example for global tools and NuGet fallback cache. -* Linux - `$HOME/.dotnet` probably. The location already exists and stores global tools. -* macOS - `$HOME/.dotnet` (or whatever is the equivalent where we store global tools). - -Note that the host would not look for the default per-user location, it would solely rely on the registration mechanism described above, so the default per-user location is really only a convenience feature of the installer. - - ### Make muxer less special As mentioned above, the muxer has certain specific behavior: * It only looks next to itself when searching for `hostfxr`. @@ -238,4 +201,14 @@ Looking for recommendations. ### Describe targeting packs -In .NET Core 3.0 aside from the shared frameworks (which are effectively also runtime packs) there's also the notion of targeting packs. The document might mention them, where they live and if the installation types have any effect on their behavior. \ No newline at end of file +In .NET Core 3.0 aside from the shared frameworks (which are effectively also runtime packs) there's also the notion of targeting packs. The document might mention them, where they live and if the installation types have any effect on their behavior. + +### Support for per-user installation +This would in theory allow installation which would be registered in `PATH` (and similar mechanism) but would be per-user and thus not require admin/root rights to install. + +This approach has severe security implications though: +* The hosts would need to consider the per-use location during their search of `hostfxr` and frameworks/SDKs. +* As such it would be possible for malicious code to register per-user location without admin rights. +* Later on tool running under admin rights would consider the per-user location and allow loading code from effectively arbitrary location into the context of elevated process. + +As such there is no proposal to add any per-user installation type right now. \ No newline at end of file From 84cb9912b6be6fe65302fceb7d94402c58e5d81f Mon Sep 17 00:00:00 2001 From: Vitek Karas Date: Thu, 14 Mar 2019 04:43:56 -0700 Subject: [PATCH 4/9] Clarify difference in hostfxr and framework search --- accepted/install-locations.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/accepted/install-locations.md b/accepted/install-locations.md index 588f9b0a4..4c82d2a80 100644 --- a/accepted/install-locations.md +++ b/accepted/install-locations.md @@ -146,6 +146,8 @@ All hosts use the same logic. Both framework and SDK search uses the same logic, the only difference is that frameworks are in the `share` subdirectory, while SDKs are in the `sdk` subdirectory of the install location. In both cases all locations listed below are searched and the complete list of all available SDKs/Frameworks is combined before making a choice which one will be used (based on version requirements). +**Important:** There's a difference in search algorithm for `hostfxr` and for frameworks/SDKs. For `hostfxr` only the first available location is considered (and the highest version from that location is selected). For frameworks/SDKs **all** locations are considered and the best match for the requested version is selected from all those locations. + Search locations: * the location of the `hostfxr` used. See the `hostfxr` search algorithm above. This means that `DOTNET_ROOT` has effect on framework and SDK search as well since the `hostfxr` search will consider it. *If the `hostfxr` is found in the `DOTNET_ROOT` location (should happen pretty much always when the variable is non-empty), then that location will be part of the search locations for frameworks/SDKs.* From be73a80791477ce6f1bbd7b23a0df18c60fe4380 Mon Sep 17 00:00:00 2001 From: Vitek Karas Date: Thu, 21 Mar 2019 04:58:48 -0700 Subject: [PATCH 5/9] PR feedback and changes --- accepted/install-locations.md | 39 ++++++++++++++++++++++++++++------- 1 file changed, 31 insertions(+), 8 deletions(-) diff --git a/accepted/install-locations.md b/accepted/install-locations.md index 4c82d2a80..9687113f0 100644 --- a/accepted/install-locations.md +++ b/accepted/install-locations.md @@ -129,7 +129,7 @@ All other hosts will search for the first location which exists in this order: * :new: global registered install location, in the `/host/fxr/` subdirectory **We've committed to support this on Windows for .NET Core 3.0** * Windows - `HKLM\SOFTWARE\dotnet\Setup\InstalledVersions\\InstallLocation` (32-bit view) - * Linux/macOS - `/etc/dotnet/install_location` + * Linux/macOS - `/etc/dotnet/install_location.conf` * default global location, in the `/host/fxr/` subdirectory * Windows (32-bit process on 64-bit Windows) - `%ProgramFiles(x86)%\dotnet` * Windows (everything else) - `%ProgramFiles%\dotnet` @@ -153,25 +153,48 @@ Search locations: *If the `hostfxr` is found in the `DOTNET_ROOT` location (should happen pretty much always when the variable is non-empty), then that location will be part of the search locations for frameworks/SDKs.* * If multi-level lookup is enabled (by default it is, can be disabled via `DOTNET_MULTILEVEL_LOOKUP=0` environment variable), then the following locations are searched as well: * :new: global registered install location - **We've committed to support this on Windows for .NET Core 3.0** * Windows - `HKLM\SOFTWARE\dotnet\Setup\InstalledVersions\\InstallLocation` (32-bit view) - * Linux/macOS - `/etc/dotnet/install_location` + **We've committed to support this in .NET Core 3.0 (Windows)** + * None on Linux/macOS * default global location, in the `/host/fxr/` subdirectory * Windows (32-bit process on 64-bit Windows) - `%ProgramFiles(x86)%\dotnet` * Windows (everything else) - `%ProgramFiles%\dotnet` - * :new: Linux - `/usr/share/dotnet` - * :new: macOS - `/usr/local/share/dotnet` + * None on Linux/macOS * Else multi-level lookup is disabled, no other search locations are considered. The reason for including the default global location is so that 3.0 host can find 2.* installs since those are not registered in the system. All 3.0 and higher installs should be registered. -*Note: The above means that on Linux/macOS in 2.2 the multi-level lookup was effectively non-functional, as there were no search paths for it. Part of the 3.0 changes is to change that and make Linux/macOS work similarly to Windows in this case as well.* -*Note: The multi-level lookup feature in its current form seems to be rather confusing and there are discussions around phasing it out. See dotnet/core-setup#3606. If there's no change in that area in .NET Core 3.0 we should do what's proposed here as it makes all platforms consistent.* +*Note: As of .NET Core 2.2 Linux/macOS effectively doesn't support multi-level lookup as there are no additional search paths considered when it's turned on.* +The multi-level lookup feature is only useful for private installs (xcopy). Installs into global locations typically don't want/need multi-level lookup. Important scenarios: +* Muxer from global location - for example running `dotnet build`. This will already use the global location for framework/SDK search since it's the one next to the used `hostfxr`. Multi-level lookup in this case doesn't add any value. +* `apphost` relying on global location - this is basically the default case for .NET Core 3.0. Framework dependent `apphost` which loads `hostfxr` from global location. This case will also already use global location for framework/SDK search due to it using `hostfxr` from the global location. Multi-level lookup doesn't add any value. +* Muxer from a private install (xcopy) - typically running `dotnet` using full path. This will use `hostfxr` from the private install and thus will use the private install to search for frameworks/SDKs. Multi-level lookup in this case helps by also including global locations in the frameworks/SDKs search. Only needed if trying to run apps which require frameworks/SDKs not in the private install. +* `apphost` using private install through `DOTNET_ROOT`- similar to the above case of muxer from private install. In this case it's really only about framework search (`apphost` doesn't really support SDKs). Multi-level lookup can help in some special cases, but mostly is not desirable. -## Open questions +Open question: +**Should we include the global registered and global default location in framework/SDK search on Linux/macOS?** +These are only used when multi-level lookup is enabled. The entire multi-level lookup features in its current form seems to be rather confusing and there are discussions around phasing it out. See dotnet/core-setup#3606. +Possible options: +* Find a replacement solution which is better then multi-level lookup in its current form - dotnet/core-setup#3606. This is a separate discussion from this document. +* Leave Linux/macOS as-is - that is effectively not supporting multi-level lookup on these platforms. +* Enable multi-level on Linux/macOS in its current form - making it consistent with Windows. + +Proposal: +**Leave it as-is on Linux/macOS.** +Pros: +* Most important scenarios (as described above) will work just fine if we add the global locations into `hostfxr` search. The scenarios where multi-level lookup helps don't work on Linux/macOS today and we haven't got much feedback to enable it. +* Avoids extending the controversial multi-level lookup to Linux/macOS. Once we figure out the replacement story, that should be implemented on Linux/macOS, but there won't be any backward compat burden. + +Cons: +* Inconsistent behavior between Windows and Linux/macOS + +## Discussed questions ### Make muxer less special +Proposal is to leave muxer as is - don't use `DOTNET_ROOT` in it. + +Leaving the below as interesting discussion... As mentioned above, the muxer has certain specific behavior: * It only looks next to itself when searching for `hostfxr`. * It ignores `DOTNET_ROOT` environment variable. From f23f80a5e42f72b53a2f8b2120ab61cf70b67f6b Mon Sep 17 00:00:00 2001 From: vitek-karas Date: Mon, 1 Apr 2019 12:48:03 -0700 Subject: [PATCH 6/9] PR feedback changes Changed the format of the configuration file on Linux/macOS to use the `.ini` format. --- accepted/install-locations.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/accepted/install-locations.md b/accepted/install-locations.md index 9687113f0..358dc9d20 100644 --- a/accepted/install-locations.md +++ b/accepted/install-locations.md @@ -11,6 +11,7 @@ The content of a .NET Core install location always follows the same layout. The * `.//` - any other shared framework. Applications can choose which version to use. * `./sdk/` - only installed when .NET Core SDK is installed - contains the SDK tools. Users can choose which version to use. +Note that the above list is not complete, it only serves to point out interesting parts of the installation which are present in the directory. ## Installation types .NET Core can be installed in several ways, each provides a different location and expected behavior. Each such location will contain the .NET Core install layout described above. @@ -35,7 +36,8 @@ Typically the muxer from this install is registered to be readily accessible wit Installer behavior: * There can only be one globally registered location. -* The installer should query the system for existing .NET Core global installs. If it finds any, it should only install to the already registered location, it should not install to a new location. +* On Windows the installer will query the system for existing .NET Core global installs. If it finds any, it should only install to the already registered location. +* On Linux the distro builders will decide the location of the global install and write it into the globally registered location. *Custom install locations are supported for .NET Core 3.0 on Windows, other cases are not yet committed.* @@ -101,7 +103,7 @@ To achieve the desired behavior the install location must be recorded in some sy * `HKLM\SOFTWARE\dotnet\Setup\InstalledVersions\\InstallLocation` - where `` is one of the `x86`, `x64`, `arm` or `arm64`. Note that this registry key is "redirected" that means that 32-bit processes see different copy of the key then 64bit processes. So it's important that both installers and the host access only the 32-bit view of the registry. * Linux and macOS - the installer will store the install location in a text file - * `/etc/dotnet/install_location.conf` - the file will contain a single line which is the path. + * `/etc/dotnet/install.conf` - The file will be in the `.ini` [format](https://en.wikipedia.org/wiki/INI_file). In it the key `InstallLocation` (in no section) will contain the path to the global location. The host will have a simplistic parser for this file, which will only support empty lines, comment lines (starts with #) and the one key/value pair. Any additional keys will be ignored. The host will trim any spaces around the equal sign and then treat the rest of the line after the equal sign as the install location path (no quotes or escaping). The muxer is registered on the system in such a way that it is readily accessible without providing full path to it. The exact mechanism is platform specific and outside of the scope of this document. (For example on Windows it's added to `PATH`) @@ -129,7 +131,7 @@ All other hosts will search for the first location which exists in this order: * :new: global registered install location, in the `/host/fxr/` subdirectory **We've committed to support this on Windows for .NET Core 3.0** * Windows - `HKLM\SOFTWARE\dotnet\Setup\InstalledVersions\\InstallLocation` (32-bit view) - * Linux/macOS - `/etc/dotnet/install_location.conf` + * Linux/macOS - `/etc/dotnet/install.conf` * default global location, in the `/host/fxr/` subdirectory * Windows (32-bit process on 64-bit Windows) - `%ProgramFiles(x86)%\dotnet` * Windows (everything else) - `%ProgramFiles%\dotnet` From db11433194feface3c220576edf833488288f38b Mon Sep 17 00:00:00 2001 From: vitek-karas Date: Tue, 9 Apr 2019 04:57:50 -0700 Subject: [PATCH 7/9] Fix the proposed configuration file name --- accepted/install-locations.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/accepted/install-locations.md b/accepted/install-locations.md index 358dc9d20..ed3a0fbe9 100644 --- a/accepted/install-locations.md +++ b/accepted/install-locations.md @@ -43,7 +43,7 @@ Installer behavior: Global installs (both default or custom location) are registered in a well know location: * Windows - registry `HKLM\SOFTWARE\dotnet\Setup\InstalledVersions\\InstallLocation` (32-bit view only) -* Linux/macOS - file `/etc/dotnet/install_location.conf` +* Linux/macOS - file `/etc/dotnet/install.conf` ### Private install (also called x-copy install) .NET Core is "installed" by simply creating the right layout on the disk with the right files, there's no system registration mechanism attached to it (typically called x-copy deployment). The most common way is to unzip a build into a directory. From 30030abbd70c5b4fa04b6c44ecf4b406bc889715 Mon Sep 17 00:00:00 2001 From: Vitek Karas Date: Thu, 25 Apr 2019 05:38:43 -0700 Subject: [PATCH 8/9] Use install_location simple text file on Linux/mac PR feedback --- accepted/install-locations.md | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/accepted/install-locations.md b/accepted/install-locations.md index ed3a0fbe9..913e44f58 100644 --- a/accepted/install-locations.md +++ b/accepted/install-locations.md @@ -43,7 +43,7 @@ Installer behavior: Global installs (both default or custom location) are registered in a well know location: * Windows - registry `HKLM\SOFTWARE\dotnet\Setup\InstalledVersions\\InstallLocation` (32-bit view only) -* Linux/macOS - file `/etc/dotnet/install.conf` +* Linux/macOS - file `/etc/dotnet/install_location` ### Private install (also called x-copy install) .NET Core is "installed" by simply creating the right layout on the disk with the right files, there's no system registration mechanism attached to it (typically called x-copy deployment). The most common way is to unzip a build into a directory. @@ -103,7 +103,7 @@ To achieve the desired behavior the install location must be recorded in some sy * `HKLM\SOFTWARE\dotnet\Setup\InstalledVersions\\InstallLocation` - where `` is one of the `x86`, `x64`, `arm` or `arm64`. Note that this registry key is "redirected" that means that 32-bit processes see different copy of the key then 64bit processes. So it's important that both installers and the host access only the 32-bit view of the registry. * Linux and macOS - the installer will store the install location in a text file - * `/etc/dotnet/install.conf` - The file will be in the `.ini` [format](https://en.wikipedia.org/wiki/INI_file). In it the key `InstallLocation` (in no section) will contain the path to the global location. The host will have a simplistic parser for this file, which will only support empty lines, comment lines (starts with #) and the one key/value pair. Any additional keys will be ignored. The host will trim any spaces around the equal sign and then treat the rest of the line after the equal sign as the install location path (no quotes or escaping). + * `/etc/dotnet/install_location` - a text file. The first line of the file specifies the install location path (no quotes or escaping). The muxer is registered on the system in such a way that it is readily accessible without providing full path to it. The exact mechanism is platform specific and outside of the scope of this document. (For example on Windows it's added to `PATH`) @@ -112,7 +112,7 @@ This allows users to install private copy of .NET Core into any directory. This There is not installer for this scenario, these installs are produced by simply copying the right directory structure into a custom location. -If the muxer (`dotnet`) is used then it must be invoked directly from the private install location (it's not registered on `PATH` in any way). +If the muxer (`dotnet`) is used then it must be invoked directly from the private install location (private install location is not registered in the `PATH` unless explicitly modified by the user). If other hosts are used then the private install location must be specified in environment variable: * `DOTNET_ROOT` * `DOTNET_ROOT(x86)` for 32-bit process running on 64-bit Windows. @@ -131,14 +131,14 @@ All other hosts will search for the first location which exists in this order: * :new: global registered install location, in the `/host/fxr/` subdirectory **We've committed to support this on Windows for .NET Core 3.0** * Windows - `HKLM\SOFTWARE\dotnet\Setup\InstalledVersions\\InstallLocation` (32-bit view) - * Linux/macOS - `/etc/dotnet/install.conf` -* default global location, in the `/host/fxr/` subdirectory + * Linux/macOS - `/etc/dotnet/install_location` +* default global location, in the `host/fxr/` subdirectory * Windows (32-bit process on 64-bit Windows) - `%ProgramFiles(x86)%\dotnet` * Windows (everything else) - `%ProgramFiles%\dotnet` * Linux - `/usr/share/dotnet` * macOS - `/usr/local/share/dotnet` -In each case with the `` subdirectory, the latest available version as per SemVer 2.0 rules will be selected. Note that the algorithm picks the first location which exists, and only then looks for the `/host/fxr/` subdirectory, and if that doesn't exist, or the library is missing it will fail. +In each case with the `` subdirectory, the latest available version as per SemVer 2.0 rules will be selected. Note that the algorithm picks the first location which exists, and only then looks for the `host/fxr/` subdirectory, and if that doesn't exist, or the library is missing it will fail. The reason for including the default global location is so that 3.0 host can find 2.* installs since those are not registered in the system. All 3.0 and higher installs should be registered. @@ -168,7 +168,8 @@ The reason for including the default global location is so that 3.0 host can fin *Note: As of .NET Core 2.2 Linux/macOS effectively doesn't support multi-level lookup as there are no additional search paths considered when it's turned on.* -The multi-level lookup feature is only useful for private installs (xcopy). Installs into global locations typically don't want/need multi-level lookup. Important scenarios: +The multi-level lookup feature is typically useful for private installs (xcopy). If there's only one global install location then apps which use it don't need the multi-level lookup functionality. +Important scenarios: * Muxer from global location - for example running `dotnet build`. This will already use the global location for framework/SDK search since it's the one next to the used `hostfxr`. Multi-level lookup in this case doesn't add any value. * `apphost` relying on global location - this is basically the default case for .NET Core 3.0. Framework dependent `apphost` which loads `hostfxr` from global location. This case will also already use global location for framework/SDK search due to it using `hostfxr` from the global location. Multi-level lookup doesn't add any value. * Muxer from a private install (xcopy) - typically running `dotnet` using full path. This will use `hostfxr` from the private install and thus will use the private install to search for frameworks/SDKs. Multi-level lookup in this case helps by also including global locations in the frameworks/SDKs search. Only needed if trying to run apps which require frameworks/SDKs not in the private install. @@ -224,11 +225,13 @@ If the muxer changes then the question is how much: * Alternatively it could only use `DOTNET_ROOT` and its location (`DOTNET_ROOT` would need to be preferred for it to make a difference). * Another consideration is reacting to multi-level lookup in `hostfxr` search as well. This would unify the probing logic for `hostfxr` with that for frameworks and SDKs. This is the only option which would effectively guarantee the usage of highest available version of `hostfxr` and thus effectively remove the problem of using older `hostfxr` with newer `hostpolicy`. -Looking for recommendations. +There are also security implications of allowing to search for `hostfxr` (or the frameworks) in custom locations. The muxer `dotnet.exe` is typically installed in a trusted location (like `Program Files`). If there are ways to modify its behavior to load `hostfxr` or frameworks from "untrusted" location, it can lead to security issues. So supporting `DOTNET_ROOT` in `dotnet.exe` would mean it's possible to tell `dotnet.exe` to load the `hostfxr` from any location by simply setting an environment variable. + +The outcome for 3.0 is to not modify the `dotnet.exe` in how it searches for `hostfxr`. The only modification will be to `apphost` and other custom hosts. ### Describe targeting packs -In .NET Core 3.0 aside from the shared frameworks (which are effectively also runtime packs) there's also the notion of targeting packs. The document might mention them, where they live and if the installation types have any effect on their behavior. +In .NET Core 3.0 aside from the shared frameworks (which are effectively also runtime packs) there's also the notion of targeting packs. Currently this document doesn't describe where they are installed and how they are found. ### Support for per-user installation This would in theory allow installation which would be registered in `PATH` (and similar mechanism) but would be per-user and thus not require admin/root rights to install. From e27cf7269d6eea32c955f064ee370e6235cfbf75 Mon Sep 17 00:00:00 2001 From: Vitek Karas Date: Thu, 2 May 2019 02:27:39 -0700 Subject: [PATCH 9/9] Fix a typo in folder name --- accepted/install-locations.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/accepted/install-locations.md b/accepted/install-locations.md index 913e44f58..4effd38b5 100644 --- a/accepted/install-locations.md +++ b/accepted/install-locations.md @@ -145,7 +145,7 @@ The reason for including the default global location is so that 3.0 host can fin ### Framework and SDK search All hosts use the same logic. -Both framework and SDK search uses the same logic, the only difference is that frameworks are in the `share` subdirectory, while SDKs are in the `sdk` subdirectory of the install location. +Both framework and SDK search uses the same logic, the only difference is that frameworks are in the `shared` subdirectory, while SDKs are in the `sdk` subdirectory of the install location. In both cases all locations listed below are searched and the complete list of all available SDKs/Frameworks is combined before making a choice which one will be used (based on version requirements). **Important:** There's a difference in search algorithm for `hostfxr` and for frameworks/SDKs. For `hostfxr` only the first available location is considered (and the highest version from that location is selected). For frameworks/SDKs **all** locations are considered and the best match for the requested version is selected from all those locations. @@ -241,4 +241,4 @@ This approach has severe security implications though: * As such it would be possible for malicious code to register per-user location without admin rights. * Later on tool running under admin rights would consider the per-user location and allow loading code from effectively arbitrary location into the context of elevated process. -As such there is no proposal to add any per-user installation type right now. \ No newline at end of file +As such there is no proposal to add any per-user installation type right now.