microsoft / MSBuildLocator

An API to locate MSBuild assemblies from an installed Visual Studio location. Use this to ensure that calling the MSBuild API will use the same toolset that a build from Visual Studio or msbuild.exe would.
Other
219 stars 83 forks source link

DotNetSdkLocationHelper.GetDotNetBasePaths Fails With Exception If Run in Net5.0 Context #160

Closed 7enderhead closed 2 years ago

7enderhead commented 2 years ago

Environment

Tested with Microsoft.Build.Locator versions 1.4.1 (released) and self-compiled 1.4.5-gf1cf5647d1 (see comment about instrumentation below).

I am on Linux Mint with several dotnet SDKs installed:

$ dotnet --info

.NET SDK (reflecting any global.json):
 Version:   6.0.101
 Commit:    ef49f6213a

Runtime Environment:
 OS Name:     linuxmint
 OS Version:  20.3
 OS Platform: Linux
 RID:         linux-x64
 Base Path:   /usr/share/dotnet/sdk/6.0.101/

Host (useful for support):
  Version: 6.0.1
  Commit:  3a25a7f1cc

.NET SDKs installed:
  2.1.818 [/usr/share/dotnet/sdk]
  5.0.404 [/usr/share/dotnet/sdk]
  6.0.101 [/usr/share/dotnet/sdk]

.NET runtimes installed:
  Microsoft.AspNetCore.All 2.1.30 [/usr/share/dotnet/shared/Microsoft.AspNetCore.All]
  Microsoft.AspNetCore.App 2.1.30 [/usr/share/dotnet/shared/Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 5.0.13 [/usr/share/dotnet/shared/Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 6.0.1 [/usr/share/dotnet/shared/Microsoft.AspNetCore.App]
  Microsoft.NETCore.App 2.1.30 [/usr/share/dotnet/shared/Microsoft.NETCore.App]
  Microsoft.NETCore.App 5.0.13 [/usr/share/dotnet/shared/Microsoft.NETCore.App]
  Microsoft.NETCore.App 6.0.1 [/usr/share/dotnet/shared/Microsoft.NETCore.App]

To install additional .NET runtimes or SDKs:
  https://aka.ms/dotnet-download

Steps to Reproduce

I want to run MSBuildLocator.RegisterDefaults(), which in turn will call DotNetSdkLocationHelper.GetDotNetBasePaths(...). In my setup, running this (with an instrumented version, because the original code silently swallows the occurring exception as per comment "this means no dotnet is installed"), leads to an "No such file or directory" exception during the starting of the dotnet --info process if the invocation occurs from a .NET5 (console) application (TargetFramework net5.0 or netcoreapp5.0; everything fine from a net6.0 application):

MSBuildLocator: DotNetSdkLocationHelper GetDotNetBasePaths: error invoking process:
MSBuildLocator:   message: 'No such file or directory'
MSBuildLocator:   error code: '-2147467259'
MSBuildLocator:   native error code: '2'
MSBuildLocator:   source: 'System.Diagnostics.Process'
MSBuildLocator:   base exception: 'System.ComponentModel.Win32Exception (2): No such file or directory
   at System.Diagnostics.Process.ForkAndExecProcess(String filename, String[] argv, String[] envp, String cwd, Boolean redirectStdin, Boolean redirectStdout, Boolean redirectStderr, Boolean setCredentials, UInt32 userId, UInt32 groupId, UInt32[] groups, Int32& stdinFd, Int32& stdoutFd, Int32& stderrFd, Boolean usesTerminal, Boolean throwOnNoExec)
   at System.Diagnostics.Process.StartCore(ProcessStartInfo startInfo)
   at System.Diagnostics.Process.Start()
   at Microsoft.Build.Locator.DotNetSdkLocationHelper.GetDotNetBasePaths(String workingDirectory)+MoveNext()'

The given workingDirectory for GetDotNetBasePaths of course exists.

Expected Behaviour

invocation of dotnet --info works, resulting in parsing of installed dotnet SDKs.

Actual Behaviour

exception as described above occurs, is silently "swallowed", eventually leading to an System.InvalidOperationException on MSBuildLocator.RegisterDefaults(), complaining that no instances of MSBuild could be detected.

7enderhead commented 2 years ago

I have more information on this.

In my /usr/local/bin directory, there was an old leftover link dotnet to a (now removed old) snap installation of dotnet.

In .NET6, the dotnet command which is tried to be executed in Proces.ForkAndExecProcess(...) is /usr/share/dotnet/dotnet, which corresponds to the actual location, reachable by PATH and also hinted at via environment variable DOTNET_ROOT.

However, for .NET5 the resolved dotnet command path is /usr/local/bin/dotnet, the old wrong link.

Removing the old wrong link from /usr/local/bin solved the problem. Some slight nuance in resolving the pathname between .NET 5 and 6 seems to have caused the issue.

rainersigwald commented 2 years ago

Nice, thanks for following up! #111 should prevent further issues of this type when it's implemented.