in src/Microsoft.TestPlatform.CoreUtilities/Helpers/DotnetHostHelper.cs [121:279]
public bool TryGetDotnetPathByArchitecture(PlatformArchitecture targetArchitecture, out string muxerPath)
{
if (_processHelper.GetCurrentProcessArchitecture() == targetArchitecture)
{
string currentProcessFileName = _processHelper.GetCurrentProcessFileName();
if (Path.GetFileName(currentProcessFileName) != _muxerName)
{
EqtTrace.Verbose($"DotnetHostHelper.TryGetDotnetPathByArchitecture: Target architecture is the same as the current process architecture '{targetArchitecture}', but the current process is not a muxer: '{currentProcessFileName}'");
}
else
{
muxerPath = currentProcessFileName;
EqtTrace.Verbose($"DotnetHostHelper.TryGetDotnetPathByArchitecture: Target architecture is the same as the current process architecture '{targetArchitecture}', and the current process is a muxer, using that: '{muxerPath}'");
return true;
}
}
// We used similar approach as the runtime resolver.
// https://github.com/dotnet/runtime/blob/main/src/native/corehost/fxr_resolver.cpp#L55
bool isWinOs = _environment.OperatingSystem == PlatformOperatingSystem.Windows;
EqtTrace.Verbose($"DotnetHostHelper.TryGetDotnetPathByArchitecture: Searching for muxer named '{_muxerName}'");
// Try to search using env vars in the order
// DOTNET_ROOT_{arch}
// DOTNET_ROOT(x86) if X86 on Win (here we cannot check if current process is WOW64 because this is SDK process arch and not real host arch so it's irrelevant)
// "DOTNET_ROOT(x86) is used instead when running a 32-bit executable on a 64-bit OS."
// DOTNET_ROOT
string envKey = $"DOTNET_ROOT_{targetArchitecture.ToString().ToUpperInvariant()}";
// Try on arch specific env var
string envVar = _environmentVariableHelper.GetEnvironmentVariable(envKey);
// Try on non virtualized x86 var(should happen only on non-x86 architecture)
if ((envVar == null || !_fileHelper.DirectoryExists(envVar)) &&
targetArchitecture == PlatformArchitecture.X86 && _environment.OperatingSystem == PlatformOperatingSystem.Windows)
{
envKey = $"DOTNET_ROOT(x86)";
envVar = _environmentVariableHelper.GetEnvironmentVariable(envKey);
}
// Try on default DOTNET_ROOT
if (envVar == null || !_fileHelper.DirectoryExists(envVar))
{
envKey = "DOTNET_ROOT";
envVar = _environmentVariableHelper.GetEnvironmentVariable(envKey);
}
if (envVar != null)
{
// If directory specified by env vars does not exists, it's like env var doesn't exists as well.
if (!_fileHelper.DirectoryExists(envVar))
{
EqtTrace.Verbose($"DotnetHostHelper.TryGetDotnetPathByArchitecture: Folder specified by env variable does not exist: '{envVar}={envKey}'");
}
else
{
muxerPath = Path.Combine(envVar, _muxerName);
if (!_fileHelper.Exists(muxerPath))
{
// If environment variable was specified, and the directory it points at exists, but it does not contain a muxer, or the muxer is incompatible with the target architecture
// we stop the search to be compliant with the approach that apphost (compiled .NET executables) use to find the muxer.
EqtTrace.Verbose($"DotnetHostHelper.TryGetDotnetPathByArchitecture: Folder specified by env variable does not contain any muxer: '{envVar}={envKey}'");
muxerPath = null;
return false;
}
if (!IsValidArchitectureMuxer(targetArchitecture, muxerPath))
{
EqtTrace.Verbose($"DotnetHostHelper: Invalid muxer resolved using env var key '{envKey}' in '{envVar}'");
muxerPath = null;
return false;
}
EqtTrace.Verbose($"DotnetHostHelper.TryGetDotnetPathByArchitecture: Muxer compatible with '{targetArchitecture}' resolved from env variable '{envKey}' in '{muxerPath}'");
return true;
}
}
EqtTrace.Verbose($"DotnetHostHelper.TryGetDotnetPathByArchitecture: Muxer was not found using DOTNET_ROOT* env variables.");
// Try to search for global registration
muxerPath = isWinOs ? GetMuxerFromGlobalRegistrationWin(targetArchitecture) : GetMuxerFromGlobalRegistrationOnUnix(targetArchitecture);
if (muxerPath != null)
{
if (!_fileHelper.Exists(muxerPath))
{
// If muxer doesn't exists or it's wrong we stop the search
EqtTrace.Verbose($"DotnetHostHelper.TryGetDotnetPathByArchitecture: Muxer file not found for global registration '{muxerPath}'");
muxerPath = null;
return false;
}
if (!IsValidArchitectureMuxer(targetArchitecture, muxerPath))
{
// If muxer is wrong we stop the search
EqtTrace.Verbose($"DotnetHostHelper.TryGetDotnetPathByArchitecture: Muxer resolved using global registration is not compatible with the target architecture: '{muxerPath}'");
muxerPath = null;
return false;
}
EqtTrace.Verbose($"DotnetHostHelper.TryGetDotnetPathByArchitecture: Muxer compatible with '{targetArchitecture}' resolved from global registration: '{muxerPath}'");
return true;
}
EqtTrace.Verbose($"DotnetHostHelper.TryGetDotnetPathByArchitecture: Muxer not found using global registrations");
// Try searching in default installation location if it exists
if (isWinOs)
{
// If we're on x64/arm64 SDK and target is x86 we need to search on non virtualized windows folder
if ((_environment.Architecture == PlatformArchitecture.X64 || _environment.Architecture == PlatformArchitecture.ARM64) &&
targetArchitecture == PlatformArchitecture.X86)
{
muxerPath = Path.Combine(_environmentVariableHelper.GetEnvironmentVariable("ProgramFiles(x86)"), "dotnet", _muxerName);
}
else
{
// If we're on ARM and target is x64 we expect correct installation inside x64 folder
muxerPath = _environment.Architecture == PlatformArchitecture.ARM64 && targetArchitecture == PlatformArchitecture.X64
? Path.Combine(_environmentVariableHelper.GetEnvironmentVariable("ProgramFiles"), "dotnet", "x64", _muxerName)
: Path.Combine(_environmentVariableHelper.GetEnvironmentVariable("ProgramFiles"), "dotnet", _muxerName);
}
}
else
{
if (_environment.OperatingSystem == PlatformOperatingSystem.OSX)
{
// If we're on ARM and target is x64 we expect correct installation inside x64 folder
muxerPath = _environment.Architecture == PlatformArchitecture.ARM64 && targetArchitecture == PlatformArchitecture.X64
? Path.Combine("/usr/local/share/dotnet/x64", _muxerName)
: Path.Combine("/usr/local/share/dotnet", _muxerName);
}
else
{
muxerPath = Path.Combine("/usr/share/dotnet", _muxerName);
}
}
if (!_fileHelper.Exists(muxerPath))
{
// If muxer doesn't exists we stop the search
EqtTrace.Verbose($"DotnetHostHelper.TryGetDotnetPathByArchitecture: Muxer was not found in default installation location: '{muxerPath}'");
muxerPath = null;
return false;
}
if (!IsValidArchitectureMuxer(targetArchitecture, muxerPath))
{
// If muxer is wrong we stop the search
EqtTrace.Verbose($"DotnetHostHelper.TryGetDotnetPathByArchitecture: Muxer resolved in default installation path is not compatible with the target architecture: '{muxerPath}'");
muxerPath = null;
return false;
}
EqtTrace.Verbose($"DotnetHostHelper.TryGetDotnetPathByArchitecture: Muxer compatible with '{targetArchitecture}' resolved from default installation path: '{muxerPath}'");
return true;
}