sdk: .NET Core executables fail if .NET Core is not installed in default location
Steps to reproduce
Download .NET Core CLI to $env:USERPROFILE/.dotnet/x64 and install a global tool
$env:PATH="$env:USERPROFILE/.dotnet/x64;$env:PATH"
dotnet-install.ps1 -Version 2.1.300-preview3-008646 -InstallDir $env:USERPROFILE/.dotnet/x64
dotnet-install.ps1 -Runtime aspnetcore -Version 2.1.0-preview2-final -InstallDir $env:USERPROFILE/.dotnet/x64
dotnet tool install -g dotnet-serve
dotnet-serve
Expected behavior
The generated shim dotnet-serve.exe should find and use the dotnet on PATH to launch the global tool.
Actual behavior
If no .NET Core is installed in C:\Program Files\dotnet
PS > dotnet-serve
A fatal error occurred, the required library hostfxr.dll could not be found.
If this is a self-contained application, that library should exist in [C:\Users\namc\.dotnet\tools\.store\dotnet-serve\0.3.0\dotnet-serve\0.3.0\tools\netcoreapp2.1\any\].
If this is a framework-dependent application, install the runtime in the default location [C:\Program Files\dotnet] or use the DOTNET_ROOT environment variable to specify the runtime location.
If .NET Core is installed in C:\Program Files\dotnet
, but doesn’t have the right shared framework version
PS> $env:COREHOST_TRACE=1
PS> dotnet-serve
Tracing enabled
--- Invoked apphost [version: 2.1.0-rc1-26419-02, commit hash: 515f580aa000600da03e81537396d2253b16fa12] main = {
C:\Users\namc\.dotnet\tools\dotnet-serve.exe
}
The managed DLL bound to this executable is: '.store\dotnet-serve\0.3.0\dotnet-serve\0.3.0\tools\netcoreapp2.1\any\dotnet-serve.dll'
Using default installation location [C:\Program Files\dotnet] as runtime location.
Reading fx resolver directory=[C:\Program Files\dotnet\host\fxr]
Considering fxr version=[2.0.5]...
Considering fxr version=[2.0.6]...
Considering fxr version=[2.0.7]...
Detected latest fxr version=[C:\Program Files\dotnet\host\fxr\2.0.7]...
Resolved fxr [C:\Program Files\dotnet\host\fxr\2.0.7\hostfxr.dll]...
Loaded library from C:\Program Files\dotnet\host\fxr\2.0.7\hostfxr.dll
Probed for and did not resolve library symbol ????????????
The required library C:\Program Files\dotnet\host\fxr\2.0.7\hostfxr.dll does not support relative app dll paths.
Environment data
dotnet --info
output:
.NET Core SDK (reflecting any global.json):
Version: 2.1.300-preview3-008646
Commit: 8e01912b36
Runtime Environment:
OS Name: Windows
OS Version: 10.0.16299
OS Platform: Windows
RID: win10-x64
Base Path: C:\Users\namc\.dotnet\x64\sdk\2.1.300-preview3-008646\
Host (useful for support):
Version: 2.1.0-rc1-26419-02
Commit: 515f580aa0
.NET Core SDKs installed:
2.1.4 [C:\Users\namc\.dotnet\x64\sdk]
2.1.100 [C:\Program Files\dotnet\sdk]
2.1.105 [C:\Users\namc\.dotnet\x64\sdk]
2.1.300-preview2-008530 [C:\Users\namc\.dotnet\x64\sdk]
2.1.300-preview3-008646 [C:\Users\namc\.dotnet\x64\sdk]
.NET Core runtimes installed:
Microsoft.AspNetCore.All 2.1.0-preview2-30478 [C:\Users\namc\.dotnet\x64\shared\Microsoft.AspNetCore.All]
Microsoft.AspNetCore.All 2.1.0-preview2-final [C:\Users\namc\.dotnet\x64\shared\Microsoft.AspNetCore.All]
Microsoft.AspNetCore.All 2.1.0-rc1-30613 [C:\Users\namc\.dotnet\x64\shared\Microsoft.AspNetCore.All]
Microsoft.AspNetCore.App 2.1.0-preview2-final [C:\Users\namc\.dotnet\x64\shared\Microsoft.AspNetCore.App]
Microsoft.AspNetCore.App 2.1.0-rc1-30613 [C:\Users\namc\.dotnet\x64\shared\Microsoft.AspNetCore.App]
Microsoft.NETCore.App 1.1.5 [C:\Users\namc\.dotnet\x64\shared\Microsoft.NETCore.App]
Microsoft.NETCore.App 2.0.7 [C:\Users\namc\.dotnet\x64\shared\Microsoft.NETCore.App]
Microsoft.NETCore.App 2.0.7 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
Microsoft.NETCore.App 2.1.0-preview2-26406-04 [C:\Users\namc\.dotnet\x64\shared\Microsoft.NETCore.App]
Microsoft.NETCore.App 2.1.0-rc1-26419-02 [C:\Users\namc\.dotnet\x64\shared\Microsoft.NETCore.App]
To install additional .NET Core runtimes or SDKs:
https://aka.ms/dotnet-download
About this issue
- Original URL
- State: closed
- Created 6 years ago
- Reactions: 14
- Comments: 52 (35 by maintainers)
Commits related to this issue
- Add a test for framework-dependent apphost Starting in .NET Core 3.0, `dotnet publish` can produce framework-dependent executibles instead of framework dependent dll files. But these can fail to work... — committed to omajid/dotnet-regular-tests by omajid 6 years ago
- Add a test for framework-dependent apphost Starting in .NET Core 3.0, `dotnet publish` can produce framework-dependent executibles instead of framework dependent dll files. But these can fail to work... — committed to omajid/dotnet-regular-tests by omajid 6 years ago
- Add a test for framework-dependent apphost Starting in .NET Core 3.0, `dotnet publish` can produce framework-dependent executibles instead of framework dependent dll files. But these can fail to work... — committed to redhat-developer/dotnet-regular-tests by omajid 6 years ago
- disable osx CI the azure agent doesnt set DOTNET_ROOT and global tools doesnt work ref https://github.com/Microsoft/azure-pipelines-image-generation/issues/531 ref https://github.com/dotnet/cli/issu... — committed to jet/falanx by enricosada 6 years ago
- Set up CI with Azure Pipelines (#86) Set up CI with Azure Pipelines, replace Travis and Appveyor The OSX CI is not added because the azure agent for OSX doesnt set DOTNET_ROOT and global tools doe... — committed to jet/falanx by azure-pipelines[bot] 6 years ago
- Set up CI with Azure Pipelines (#86) Set up CI with Azure Pipelines, replace Travis and Appveyor The OSX CI is not added because the azure agent for OSX doesnt set DOTNET_ROOT and global tools doe... — committed to jet/falanx by azure-pipelines[bot] 6 years ago
- wtf: try workaround for dotnet-cli bug ref: https://github.com/dotnet/cli/issues/9114 — committed to giulioungaretti/QuantumPlatform by giulioungaretti 5 years ago
- wtf: try workaround for dotnet-cli bug ref: https://github.com/dotnet/cli/issues/9114 — committed to giulioungaretti/QuantumPlatform by giulioungaretti 5 years ago
- fix: try workaround for dotnet-cli bug ref: https://github.com/dotnet/cli/issues/9114 — committed to giulioungaretti/QuantumPlatform by giulioungaretti 5 years ago
- added workaround for https://github.com/dotnet/cli/issues/9114 — committed to Aaronontheweb/akka.net by Aaronontheweb 5 years ago
- integrated Incrementalist into build pipeline (#3788) * integrated Incrementalist into build pipeline * added workaround for https://github.com/dotnet/cli/issues/9114 * added option to skip bui... — committed to akkadotnet/akka.net by Aaronontheweb 5 years ago
- integrated Incrementalist into build pipeline (#3788) * integrated Incrementalist into build pipeline * added workaround for https://github.com/dotnet/cli/issues/9114 * added option to skip bui... — committed to madmonkey/akka.net by Aaronontheweb 5 years ago
- integrated Incrementalist into build pipeline (#3788) * integrated Incrementalist into build pipeline * added workaround for https://github.com/dotnet/cli/issues/9114 * added option to skip bui... — committed to Aaronontheweb/akka.net by Aaronontheweb 5 years ago
This is by design and the decision we made on the host taking many different things in consideration. I believe the dotnet install message will guide you to setting DOTNET_ROOT if your dotnet is not installed in the default location.
Independent of implementation, a user expects this to work:
This finds dotnet on PATH and determines DOTNET_ROOT based on that:
For those using the snap package, the
libhostfxr.so
error can be fixed as follows.Complete configuration for Ubuntu development: /etc/profile.d/04-dotnet-cli-tools.sh
My concern about this design is that the error message is not clear when there are some .NET Core runtime installations in C:\Program Files\dotnet, but not the right ones for the global tool. How would a user ever figure this out from this?
On Linux this is implemented in user-space. For example, corefx implementation is here: https://github.com/dotnet/corefx/blob/9bfa3bd511a6a2152de8192332b0e439917e65e0/src/System.Diagnostics.Process/src/System/Diagnostics/Process.Unix.cs#L480-L498
A lot of things get probed (executable on PATH, libraries on LD_LIBRARY_PATH, …) and we don’t perceive slowness. The earlier on PATH, the sooner the match.
Using data from PATH is as secure as using data from DOTNET_ROOT.
For the reasons explained by @natemcmaster my preferred order is DOTNET_ROOT, PATH probing, hard-coded path
For source-build, we want to be able to set the hard-coded path. If path probing is implemented, we can rely on that for now. If there is no path probing, we need to make the hard-coded path a setting that can be specified from source-build.
@richlander
Probing %PATH% for dotnet.exe is not intuitive and somewhat error-prone as we can’t exactly duplicate what the OS does. That’s why we added %DOTNET_ROOT%
as a user who just supports dev teams I can’t express how much confusion and frustration dotnet CLI causes. There’s so much mess. We use the dotnet install scripts (https://docs.microsoft.com/en-us/dotnet/core/tools/dotnet-install-script) on Linux and making this all work with multiple frameworks/cli versions is just a mess. Please improve so we don’t have to waste time getting seemingly simple things like “dotnet tool” to work.
as a note.
2.1.300-preview2
from unzippingPATH
in front (=> priority), likeset PATH=%CD%;%PATH%
dotnet tool install dotnet-serve --tool-path mybin
(install to specific dir)But both are broken, also direct run of the .exe:
at least the second should work. seetting
DOTNET_ROOT
fix that.the
dotnet
is found onPATH
correctlybut the
host\fxr\2.1.0-preview2-26406-04\hostfxr.dll
is not probed, so falling back to previous globally installedC:\Program Files\dotnet\host\fxr\2.0.6
A agree with what @tmds said. It was my expectation that after
dotnet tool install
,dotnet serve
would use the same dotnet used to install the tool. I think many users will expect this.To @eerhardt’s points:
I understand the engineering purity of this argument, but think there is another compelling point to consider. PATH probing is consistent with how the rest of the product behaves. Over the last few years, we have been teaching people that you can install .NET Core into a custom location. If you put it on PATH first, Visual Studio, VS Code, MSBuild.exe, and the command line will use that custom install location. The current behavior of global tools breaks from this pattern. And from what I’m hearing, the reasons for breaking from that pattern seem to be narrowly focused on what the apphost should do, not on the behavior of the .NET Core product as a whole.
I agree with you here. I would not expect dotnet-serve to find /path/to/dotnet. That said, I’m not asking this. I’m asking for PATH probing.
Let me be completely clear why this is so maddening to me. The majority of .NET Core tools today are written so they can be invoked as
dotnet <command>
(that’s a subject for another conversation, but it’s the reality of the current world.) If I haveC:\custom\dotnet.exe
first on PATH, when invokingdotnet <command>
, the “dotnet” used isC:\custom\dotnet.exe
, but the CLI will launch<command>
part in a new context that ignoresC:\custom\
. If nothing else, please setDOTNET_ROOT
from the CLI to the current location so any subprocesses launched by the CLI will resolve to the same dotnet.exe.I just want to add an anecdote I encountered that caused me a huge amount of confusion, and no amount of
dotnet install
docs helped because I never randotnet install
.I work at a bank and we don’t have admin access to our machines. To not have to deal with the pain that it is getting someone to install .net core 3.0 for me I downloaded the binaries, placed them in
c:\users\<name>\dotnet
, and added that to my path. I have been successfully doing .net core 2.2 and 3.0 development that way for a while (due to Rider not needing admin to install).However, I downloaded Linqpad6 (which is a .net core 3.0 application) and it would not run. Running the executable would do absolutely nothing, and trying to
dotnet Linqpad6.exe
would give an error abouthostpolicy.dll
not being found (and no mention of any environment variables).After a back and forth with the Linqpad dev I ended up doing a really round about testing that finally gave me the error above about the
DOTNET_ROOT
environment variable not being set. Setting this fixed all my issues.So my point is, this has the potential to really cause confusion for downloaded .net core precompiled binaries and it’s actually very hard to find out that the solution is
DOTNET_ROOT
.At a minimum I believe that if
DOTNET_ROOT
is not set then all executions ofdotnet
cli should give a warning about this not being set.I don’t consider one better than the other. I think of them as different scopes for different use-cases. I wish
--global
was named--user
(… naming is hard).One of the key side-by-side promises of .NET Core was that you could just run an executable from a folder and add things to the PATH, it would be very nice if global tools would follow this approach.
If the PATH was probed as a last resort fallback then it may not be a breaking change after 2.1.300 and could maybe be done for 2.1.400? It would only enable things that would not have worked before anyway and wouldn’t break things that used to work before.
Possible solution: the apphost should automatically default DOTNET_ROOT to the first dotnet.exe on PATH.
Try changing this line to include
readlink
, which follow the symlink to the actual location of dotnet.@eerhardt what do you think about this order then: DOTNET_ROOT, hard-coded path, PATH probing.
I am so lucky to have the awesome people happened to use Ubuntu 18.04 & Snap just as I did. God knows how much time I could spend more on this after a simple automatic update.
had the same issue while creating a dockerfile for node + pwsh this helped me solvig the issue, so i will post my working result for everyone 😃
thx alot
You know GitHub let’s you transfer issues instead of just copying to a new one, right?
Installing a local tool and running it passes on Linux-based
microsoft/dotnet
docker images but fails on Hosted OSX agents from Azure Pipelines.The problem here is that on most systems,
dotnet
will be installed somewhere that would require administrative access (windows admin, superuser permission on *nix) to create directories in. It would also lead to users sharing their tools should they be installed in a global directory.@welkie the layout under DOTNET_ROOT should be like this. The directory that has the dotnet executable but not the symbol link
I’m comparing the gobal tools with npm tools. observations:
-g
for npm is independent of users, while-g
for dotnet installs into a user folder.npm
usenode
that is onPATH
@livarcocc @richlander if you are changing the design of this, please consider doing a https://github.com/dotnet/designs.
I filed the same issue for Linux: https://github.com/dotnet/core-setup/issues/4078. I have the same expectation as @natemcmaster:
dotnet
should be searched on PATH. For source-build Red Hat, Fedora and CentOS,dotnet
is not installed at the ‘default’ location. So tools fail out-of-the-box 😕CC @eerhardt @dleeapho @omajid
An alternative solution (https://github.com/dotnet/core-setup/issues/4078#issuecomment-384653329) is to allow source-build to specify the ‘default’ location. That would fix the source-build case, but not @natemcmaster’s case. This would still require setting DOTNET_ROOT. Perhaps we can use this fallback order: DOTNET_ROOT, PATH probing, hard-coded path.
A pseudo Unix implementation for finding the root via PATH:
Can you elaborate? It seems like it would be a better user experience, but want to know why you would rather not.
I was expecting this PATH lookup behavior because it’s one we depend on to make Visual Studio work SDKs installed into user-locations. It’s also one less variable that we have to set to make CI builds work well. We already have a handful, and the list seems to be ever growing.