Skip to content

Conversation

@jjonescz
Copy link
Member

@jjonescz jjonescz commented Oct 23, 2025

Fixes dotnet/msbuild#12669. Before the change to use csc apphost, we were searching for dotnet.exe either from DOTNET_HOST_PATH or PATH. With csc apphost (#80026) we regressed this by considering the dotnet host only from DOTNET_HOST_PATH (and passing that as DOTNET_ROOT to the apphost) - but that variable is not passed in MSBuilds older than 18.x (where the previous non-apphost implementation would work fine since it would fallback to finding dotnet.exe in PATH).

@jjonescz jjonescz marked this pull request as ready for review October 23, 2025 14:05
@jjonescz jjonescz requested a review from a team as a code owner October 23, 2025 14:05
@jjonescz
Copy link
Member Author

jjonescz commented Oct 27, 2025

@333fred @RikkiGibson @dotnet/roslyn-compiler for a second review, thanks. This fixes a regression.

internal static string? GetToolDotNetRoot()
{
if (GetDotNetHostPath() is { } dotNetHostPath)
var directoryName = Path.GetDirectoryName(GetDotNetPathOrDefault());
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like before we were looking specifically for the directory containing a suitable .NET runtime installation?

But now we are searching the path, and the dotnet we find on the PATH might be linked into a location like /usr/bin/dotnet. Is it fine to just return /usr/bin from this call?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But now we are searching the path, and the dotnet we find on the PATH might be linked into a location like /usr/bin/dotnet. Is it fine to just return /usr/bin from this call?

Good catch, that wouldn't work. I guess we can resolve symlinks first.

{
if (!returnFinalTarget) throw new NotSupportedException();

path = Path.GetFullPath(path);
Copy link
Member

@RikkiGibson RikkiGibson Oct 31, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a need for this method to work with relative paths?

I guess it's possible for a path coming from the environment (PATH, DOTNET_ROOT etc) to be relative..though that seems really weird, and likely to result in unpredictable behavior. I wonder if that is a condition we should log/throw/complain about, if it ever happens.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is probably no need by the current code, but this polyfill could be used in the future by others so it seems it should behave just like the BCL's equivalent.

But it seems CreateFileW would handle relative paths anyway so the GetFullPath call seems unnecessary, I will remove it.

@jjonescz
Copy link
Member Author

@jaredpar I added some non trivial symlink handling, can you take another look? or @333fred for another review, thanks.

internal static string GetDotNetPathOrDefault()
{
if (GetDotNetHostPath() is { } pathToDotNet)
if (Environment.GetEnvironmentVariable(DotNetHostPathEnvironmentName) is { Length: > 0 } pathToDotNet)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This PR effectively means we set DOTNET_ROOT for our apphost based on the following priority order:

  1. %DOTNET_HOST_PATH%
  2. %DOTNET_EXPERIMENTAL_HOST_PATH%
  3. First dotnet on %PATH%
  4. YOLO dotnet

The first two are definitely standard practice for tools inside the SDK. I'm not sure about (3) though. Essentially what is the appropriate way to invoke a tool when the .NET 10 SDK is loaded into MSBuild 17.x? @baronfel, @rainersigwald?

Copy link
Member Author

@jjonescz jjonescz Nov 3, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FWIW, it's equivalent to how we always found dotnet host for launching tools, this PR just fixes a recent regression where we stopped doing (3) when we introduced apphosts.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah I think this feels fine. @dsplaisted any concerns for finding-private-SDK-from-environment-variables?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FWIW, it's equivalent to how we always found dotnet host for launching tools, this PR just fixes a recent regression where we stopped doing (3) when we introduced apphosts.

Agree it's taking us back to the old state. At the same time there's been a lot of discussion on how should we be launching .NET based processes: both in the SDK and more generally. I'd rather us be part of the agreed on standard practice vs. deviating if possible.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds like Rainer thinks this is fine, I'm going to merge tomorrow unless there are other concerns

@jjonescz jjonescz merged commit 18e5d75 into dotnet:main Nov 5, 2025
24 checks passed
@jjonescz jjonescz deleted the dotnet-path branch November 5, 2025 14:36
@dotnet-policy-service dotnet-policy-service bot added this to the Next milestone Nov 5, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Known Issue: .NET 10.0.100-rc.2 can fail to launch the C# compiler when used in Visual Studio 2022

5 participants