Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fill in gaps in shared runtime location logic (DOTNET_ROOT) #38462

Closed
tmat opened this issue Jun 26, 2020 · 17 comments
Closed

Fill in gaps in shared runtime location logic (DOTNET_ROOT) #38462

tmat opened this issue Jun 26, 2020 · 17 comments
Milestone

Comments

@tmat
Copy link
Member

tmat commented Jun 26, 2020

Scenario:

A test project is testing a product.exe built in the same repo.
The project that builds product.exe targets netcoreapp and uses shared framework.
The test uses Process APIs to launch product.exe process.

When the test runs on a machine that has the matching runtime installed globally, the test works without setting any env variables. However, when the same test runs on another machine that does not have the runtime installed globally it fails with error: "The required library hostfxr.dll could not be found. Exit code -2147450749."

This is because DOTNET_ROOT is not set for the child process.

Proposals

  1. If the test project targets netcoreapp it would be better to flow the current runtime path to the child process as a fallback runtime by default. This fallback path would only be used as the last resort - before reporting the above error. I believe it would address many common scenarios without the developer needing to change anything.

  2. Since [1] is not currently implemented the test currently needs to set DOTNET_ROOT. There doesn't seem to be an API that returns the path to the directory that contains dotnet.exe. So the ask is to provide an API that can be used to determine the path of the current runtime that DOTNET_ROOT would accept. RuntimeEnvironment.GetRuntimeDirectory() returns path to the shared runtime directory. A workaround then is to find a directory above this directory that contains dotnet.exe.

@Dotnet-GitSync-Bot
Copy link
Collaborator

I couldn't figure out the best area label to add to this issue. If you have write-permissions please help me learn by adding exactly one area label.

@Dotnet-GitSync-Bot Dotnet-GitSync-Bot added the untriaged New issue has not been triaged by the area owner label Jun 26, 2020
@ghost
Copy link

ghost commented Jun 27, 2020

Tagging subscribers to this area: @vitek-karas, @swaroop-sridhar
Notify danmosemsft if you want to be subscribed.

@jkotas
Copy link
Member

jkotas commented Jun 27, 2020

This is because DOTNET_ROOT is not set for the child process.

And is DOTNET_ROOT set for the parent process?

We are not doing anything with DOTNET_ROOT. If you set it in your environment, we will leave it set.

@tmat
Copy link
Member Author

tmat commented Jun 27, 2020

It is not set.

@richlander
Copy link
Member

I talked to @tmat yesterday about this and encouraged him to create this issue to allow for a broader conversation.

I think of this as the general problem where people use the product with non-standard install locations (private installs are the best example). Perhaps, all we need to do is write better docs to get people to set DOTNET_ROOT. I do this frequently on Linux and ARM machines. That's separate from this use case, however (since I'm just launching EXEs by themselves; there is no flow of one process to another).

We had a whole series of conversation on this, and I remember much of that detail. We came to the existing DOTNET_ROOT behavior and while we realized that there was some rough edges, we were unable to come up with a better approach. I'm still unable to do that.

I think missing an API that gives you the value you need for DOTNET_ROOT is a problem.

I think of this as similar to the space of multi-level lookup (MLL). I both appreciate and am frustrated by that feature. This is what proposal 1 is about. The idea is that you start with a fully qualified path to the dotnet executable. You don't need DOTNET_ROOT for that case. But if that command results in a call to a .NET EXE, then you have this problem. I'm wondering if we need a new CLI arg along the lines of --set-dotnet-root. It's an open question of whether that is better than what we have today. It seems like the next logical progression if we see enough value. That said, I'd want to consider how it interacts with MLL, It's easy to imagine a 5.0 private layout with a 3.1 global install, and a downstream launch (in the process chain) of a 3.1 EXE. This is the scenario we'd need to consider.

@jkotas
Copy link
Member

jkotas commented Jun 28, 2020

I think missing an API that gives you the value you need for DOTNET_ROOT is a problem.

Do you mean API that gives you the value you need for DOTNET_ROOT or the name of the currently executing dotnet.exe if there is one? I think the later one would make more sense. E.g. sys.executable in Python returns path to currently running python.exe, and empty string for "self-contained" python apps.

@richlander
Copy link
Member

richlander commented Jun 28, 2020

I mean one that would give the value you need for DOTNET_ROOT. This would be the parent directory of the dotnet executable.

From @tmat: RuntimeEnvironment.GetRuntimeDirectory() gives me C:\Program Files\dotnet\shared\Microsoft.NETCore.App\3.1.2\.

That isn't the currency required for DOTNET_ROOT. We want an API that will return C:\Program Files\dotnet or its analog.

@jkotas
Copy link
Member

jkotas commented Jun 28, 2020

I am not sure we want to be encouraging editing DOTNET_ROOT in the middle of the process chain. It comes with number of problems that you have listed, and the environment variable is not even always called DOTNET_ROOT - it is DOTNET_ROOT(x86) for Windows WoW.

Perhaps, all we need to do is write better docs to get people to set DOTNET_ROOT

+1

@vitek-karas
Copy link
Member

The issue seem very similar to dotnet/install-scripts#43 and dotnet/install-scripts#47 - as private installs are typically created via the install scripts.

@richlander
Copy link
Member

richlander commented Jun 28, 2020

DOTNET_ROOT(x86) ... Ouch, I didn't even know about that.

That's where --set-dotnet-root would be more compelling. That's purely a convenience approach. Probably best to start with better docs to help further elaborate the scenarios.

I've been aware for some time that this is a soft spot for us. I'm most interesting in the ad-hoc dev environments, but CI aligns well.

Are you compelled by that approach, @tmat?

@tmat
Copy link
Member Author

tmat commented Jun 29, 2020

We might just need a better documentation.

The test project in the above scenario was targeting net472 initially. DOTNET_ROOT has to be set by the test code in that case in order for the child process to find core runtime.

I switched the test project to netcoreapp3.1 and I thought DOTNET_ROOT still needs to be set. But it appears that the child process is able to find the core runtime even without this env variable being set. How does that work?

@richlander
Copy link
Member

richlander commented Jun 29, 2020

Is 3.1 installed globally on this machine?

set DOTNET_MULTILEVEL_LOOKUP to 0 and see what happens. I assume you are using Windows. If not, it doesn't matter, per my understanding.

@tmat
Copy link
Member Author

tmat commented Jun 29, 2020

It may or may not be. It's a CI machine. We want the tests to use the exact dotnet that invoked the test runner.

@tmat
Copy link
Member Author

tmat commented Jun 29, 2020

@vitek-karas
Copy link
Member

But it appears that the child process is able to find the core runtime even without this env variable being set.

Does it pick the right runtime (as in - the one from the repo you want)?
Is the DOTNET_ROOT not set, or it's just that your test code doesn't set it and it might be set by something else?

Ultimately to find out: set COREHOST_TRACE=1 and COREHOST_TRACEFILE=host_trace.txt when running the child process - and then collect (somehow) the host_trace.txt - that will contain all the details about why and where the host searched for things.

@tmat
Copy link
Member Author

tmat commented Jul 3, 2020

I switched the test project to netcoreapp3.1 and I thought DOTNET_ROOT still needs to be set. But it appears that the child process is able to find the core runtime even without this env variable being set. How does that work?

I take this back. The CI infra had a bug and actually did not run the tests properly. After fixing the issue the test behaves the same as when targeting net472 - that is, the child process fails to find dotnet runtime unless DOTNET_ROOT is set by the test process.

The proposals above are still relevant. The current workaround is:

if (Environment.GetEnvironmentVariable("DOTNET_ROOT") == null)
{
   var dir = RuntimeEnvironment.GetRuntimeDirectory();

   while (dir != null && !File.Exists(Path.Combine(dir, "dotnet.exe")))
   {
      dir = Path.GetDirectoryName(dir);
   }

   Environment.SetEnvironmentVariable("DOTNET_ROOT", dir);
}

@agocke agocke removed the untriaged New issue has not been triaged by the area owner label Jul 6, 2020
@agocke agocke added this to the 6.0.0 milestone Jul 6, 2020
@agocke agocke modified the milestones: 6.0.0, 7.0.0 Aug 2, 2021
@agocke agocke added this to AppModel Jul 13, 2022
@agocke agocke modified the milestones: 7.0.0, Future Jul 26, 2022
@jkotas
Copy link
Member

jkotas commented Jul 15, 2023

Resolving as duplicate of #88754 that has better description of the problem and discussion of the solutions.

@jkotas jkotas closed this as completed Jul 15, 2023
@ghost ghost locked as resolved and limited conversation to collaborators Aug 14, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
Archived in project
Development

No branches or pull requests

7 participants