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

List other architectures in dotnet --info #70403

Merged
merged 8 commits into from
Jun 14, 2022
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using System;
using System.IO;
using System.Runtime.InteropServices;
using Microsoft.DotNet.Cli.Build;
using Microsoft.DotNet.Cli.Build.Framework;
using Microsoft.DotNet.CoreSetup.Test;
using Microsoft.DotNet.CoreSetup.Test.HostActivation;
Expand Down Expand Up @@ -146,6 +147,44 @@ public void EnvironmentVariable_DotnetRootPathExistsButHasNoHost()
}
}

[Fact]
public void EnvironmentVariable_DotNetInfo_ListEnvironment()
{
var dotnet = new DotNetCli(sharedTestState.RepoDirectories.BuiltDotnet);

var command = dotnet.Exec("--info")
.CaptureStdOut();

var envVars = new (string Architecture, string Path)[] {
("arm64", "/arm64/dotnet/root"),
("x64", "/x64/dotnet/root"),
("x86", "/x86/dotnet/root")
};
foreach(var envVar in envVars)
{
command = command.DotNetRoot(envVar.Path, envVar.Architecture);
}

string dotnetRootNoArch = "/dotnet/root";
command = command.DotNetRoot(dotnetRootNoArch);

(string Architecture, string Path) unknownEnvVar = ("unknown", "/unknown/dotnet/root");
command = command.DotNetRoot(unknownEnvVar.Path, unknownEnvVar.Architecture);

var result = command.Execute();
result.Should().Pass()
.And.HaveStdOutContaining($"{Constants.DotnetRoot.EnvironmentVariable} environment variables:")
.And.HaveStdOutMatching($@"{Constants.DotnetRoot.EnvironmentVariable}\s*\[{dotnetRootNoArch}\]")
.And.NotHaveStdOutContaining($"{Constants.DotnetRoot.ArchitectureEnvironmentVariablePrefix}{unknownEnvVar.Architecture.ToUpper()}")
.And.NotHaveStdOutContaining($"[{unknownEnvVar.Path}]");

foreach ((string architecture, string path) in envVars)
{
result.Should()
.HaveStdOutMatching($@"{Constants.DotnetRoot.ArchitectureEnvironmentVariablePrefix}{architecture.ToUpper()}\s*\[{path}\]");
}
}

[Fact]
public void RegisteredInstallLocation_ArchSpecificLocationIsPickedFirst()
{
Expand Down Expand Up @@ -241,6 +280,46 @@ public void InstallLocationFile_MissingFile()
}
}

[Fact]
public void RegisteredInstallLocation_DotNetInfo_ListOtherArchitectures()
{
var dotnet = new DotNetCli(sharedTestState.RepoDirectories.BuiltDotnet);
using (var registeredInstallLocationOverride = new RegisteredInstallLocationOverride(dotnet.GreatestVersionHostFxrFilePath))
{
var installLocations = new (string, string)[] {
("arm64", "/arm64/install/path"),
("x64", "/x64/install/path"),
("x86", "/x86/install/path")
};
(string Architecture, string Path) unknownArchInstall = ("unknown", "/unknown/install/path");
registeredInstallLocationOverride.SetInstallLocation(installLocations);
registeredInstallLocationOverride.SetInstallLocation(unknownArchInstall);

var result = dotnet.Exec("--info")
.CaptureStdOut()
.ApplyRegisteredInstallLocationOverride(registeredInstallLocationOverride)
.Execute();

result.Should().Pass()
.And.HaveStdOutContaining("Other architectures found:")
.And.NotHaveStdOutContaining(unknownArchInstall.Architecture)
.And.NotHaveStdOutContaining($"[{unknownArchInstall.Path}]");

string pathOverride = OperatingSystem.IsWindows() // Host uses short form of base key for Windows
? registeredInstallLocationOverride.PathValueOverride.Replace(Microsoft.Win32.Registry.CurrentUser.Name, "HKCU")
: registeredInstallLocationOverride.PathValueOverride;
pathOverride = System.Text.RegularExpressions.Regex.Escape(pathOverride);
foreach ((string arch, string path) in installLocations)
{
if (arch == sharedTestState.RepoDirectories.BuildArchitecture)
continue;

result.Should()
.HaveStdOutMatching($@"{arch}\s*\[{path}\]\r?$\s*registered at \[{pathOverride}.*{arch}.*\]", System.Text.RegularExpressions.RegexOptions.Multiline);
}
}
}

public class SharedTestState : IDisposable
{
public string BaseDirectory { get; }
Expand Down
2 changes: 1 addition & 1 deletion src/native/corehost/apphost/apphost.windows.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ namespace
pal::string_t get_apphost_details_message()
{
pal::string_t msg = _X("Architecture: ");
msg.append(get_arch());
msg.append(get_current_arch_name());
msg.append(_X("\n")
_X("App host version: ") _STRINGIFY(COMMON_HOST_PKG_VER) _X("\n\n"));
return msg;
Expand Down
4 changes: 2 additions & 2 deletions src/native/corehost/corehost.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ void need_newer_framework_error(const pal::string_t& dotnet_root, const pal::str
_X("Download the .NET runtime:\n")
_X("%s&apphost_version=%s"),
host_path.c_str(),
get_arch(),
get_current_arch_name(),
_STRINGIFY(COMMON_HOST_PKG_VER),
dotnet_root.c_str(),
get_download_url().c_str(),
Expand Down Expand Up @@ -225,7 +225,7 @@ int exe_start(const int argc, const pal::char_t* argv[])
else
{
// An outdated hostfxr can only be found for framework-related apps.
trace::error(_X("The required library %s does not support single-file apps."), fxr.fxr_path().c_str());
trace::error(_X("The required library %s does not support single-file apps."), fxr.fxr_path().c_str());
need_newer_framework_error(fxr.dotnet_root(), host_path);
rc = StatusCode::FrameworkMissingFailure;
}
Expand Down
2 changes: 1 addition & 1 deletion src/native/corehost/deps_format.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ pal::string_t deps_json_t::get_current_rid(const rid_fallback_graph_t& rid_fallb
// We do the same even when the RID is empty.
if (currentRid.empty() || (rid_fallback_graph.count(currentRid) == 0))
{
currentRid = pal::get_current_os_fallback_rid() + pal::string_t(_X("-")) + get_arch();
currentRid = pal::get_current_os_fallback_rid() + pal::string_t(_X("-")) + get_current_arch_name();

trace::info(_X("Falling back to base HostRID: %s"), currentRid.c_str());
}
Expand Down
17 changes: 16 additions & 1 deletion src/native/corehost/fxr/command_line.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include "command_line.h"
#include <error_codes.h>
#include "framework_info.h"
#include "install_info.h"
#include <pal.h>
#include "sdk_info.h"
#include <trace.h>
Expand Down Expand Up @@ -284,7 +285,7 @@ void command_line::print_muxer_info(const pal::string_t &dotnet_root)
trace::println();
trace::println(_X("Host:"));
trace::println(_X(" Version: %s"), _STRINGIFY(HOST_FXR_PKG_VER));
trace::println(_X(" Architecture: %s"), get_arch());
trace::println(_X(" Architecture: %s"), get_current_arch_name());

pal::string_t commit = _STRINGIFY(REPO_COMMIT_HASH);
trace::println(_X(" Commit: %s"), commit.substr(0, 10).c_str());
Expand All @@ -303,6 +304,20 @@ void command_line::print_muxer_info(const pal::string_t &dotnet_root)
trace::println(_X(" No runtimes were found."));
}

trace::println();
trace::println(_X("Other architectures found:"));
if (!install_info::print_installs(_X(" "), /*skip_current_arch*/ true))
{
trace::println(_X(" None"));
}

trace::println();
trace::println(DOTNET_ROOT_ENV_VAR _X(" environment variables:"));
if (!install_info::print_environment(_X(" ")))
{
trace::println(_X(" Not set"));
}

trace::println();
trace::println(_X("Download .NET:"));
trace::println(_X(" %s"), DOTNET_CORE_DOWNLOAD_URL);
Expand Down
2 changes: 2 additions & 0 deletions src/native/corehost/fxr/files.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ list(APPEND SOURCES
${CMAKE_CURRENT_LIST_DIR}/fx_resolver.messages.cpp
${CMAKE_CURRENT_LIST_DIR}/framework_info.cpp
${CMAKE_CURRENT_LIST_DIR}/host_context.cpp
${CMAKE_CURRENT_LIST_DIR}/install_info.cpp
${CMAKE_CURRENT_LIST_DIR}/sdk_info.cpp
${CMAKE_CURRENT_LIST_DIR}/sdk_resolver.cpp
)
Expand All @@ -31,6 +32,7 @@ list(APPEND HEADERS
${CMAKE_CURRENT_LIST_DIR}/fx_resolver.h
${CMAKE_CURRENT_LIST_DIR}/framework_info.h
${CMAKE_CURRENT_LIST_DIR}/host_context.h
${CMAKE_CURRENT_LIST_DIR}/install_info.h
${CMAKE_CURRENT_LIST_DIR}/sdk_info.h
${CMAKE_CURRENT_LIST_DIR}/sdk_resolver.h
)
Expand Down
2 changes: 1 addition & 1 deletion src/native/corehost/fxr/fx_muxer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -245,7 +245,7 @@ void append_probe_realpath(const pal::string_t& path, std::vector<pal::string_t>

if (pos_placeholder != pal::string_t::npos)
{
pal::string_t segment = get_arch();
pal::string_t segment = get_current_arch_name();
segment.push_back(DIR_SEPARATOR);
segment.append(tfm);
probe_path.replace(pos_placeholder, placeholder.length(), segment);
Expand Down
2 changes: 1 addition & 1 deletion src/native/corehost/fxr/fx_resolver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -448,7 +448,7 @@ StatusCode fx_resolver_t::read_framework(
_X("App: %s\n")
_X("Architecture: %s"),
app_display_name != nullptr ? app_display_name : host_info.host_path.c_str(),
get_arch());
get_current_arch_name());
display_missing_framework_error(fx_name, new_effective_fx_ref.get_fx_version(), pal::string_t(), host_info.dotnet_root, disable_multilevel_lookup);
return FrameworkMissingFailure;
}
Expand Down
4 changes: 2 additions & 2 deletions src/native/corehost/fxr/fx_resolver.messages.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -113,11 +113,11 @@ void fx_resolver_t::display_missing_framework_error(
// Display the error message about missing FX.
if (fx_version.length())
{
trace::error(_X("Framework: '%s', version '%s' (%s)"), fx_name.c_str(), fx_version.c_str(), get_arch());
trace::error(_X("Framework: '%s', version '%s' (%s)"), fx_name.c_str(), fx_version.c_str(), get_current_arch_name());
}
else
{
trace::error(_X("Framework: '%s', (%s)"), fx_name.c_str(), get_arch());
trace::error(_X("Framework: '%s', (%s)"), fx_name.c_str(), get_current_arch_name());
}

trace::error(_X(".NET location: %s\n"), dotnet_root.c_str());
Expand Down
59 changes: 59 additions & 0 deletions src/native/corehost/fxr/install_info.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

#include "install_info.h"
#include "pal.h"
#include "trace.h"
#include "utils.h"

bool install_info::print_environment(const pal::char_t* leading_whitespace)
{
bool found_any = false;

const pal::char_t* fmt = _X("%s%-17s [%s]");
pal::string_t value;
if (pal::getenv(DOTNET_ROOT_ENV_VAR, &value))
{
found_any = true;
trace::println(fmt, leading_whitespace, DOTNET_ROOT_ENV_VAR, value.c_str());
}

for (uint32_t i = 0; i < static_cast<uint32_t>(pal::known_architecture::__last); ++i)
{
pal::string_t env_var = get_dotnet_root_env_var_for_arch(static_cast<pal::known_architecture>(i));
if (pal::getenv(env_var.c_str(), &value))
{
found_any = true;
trace::println(fmt, leading_whitespace, env_var.c_str(), value.c_str());
}
}

return found_any;
}

bool install_info::print_installs(const pal::char_t* leading_whitespace, bool skip_current_arch)
{
bool found_any = false;
for (uint32_t i = 0; i < static_cast<uint32_t>(pal::known_architecture::__last); ++i)
{
pal::known_architecture arch = static_cast<pal::known_architecture>(i);
if (skip_current_arch && arch == get_current_arch())
continue;

pal::string_t install_location;
bool is_registered = pal::get_dotnet_self_registered_dir_for_arch(arch, &install_location);
if (is_registered
|| (pal::get_default_installation_dir_for_arch(arch, &install_location) && pal::directory_exists(install_location)))
{
found_any = true;
remove_trailing_dir_separator(&install_location);
trace::println(_X("%s%-5s [%s]"), leading_whitespace, get_arch_name(arch), install_location.c_str());
if (is_registered)
{
trace::println(_X("%s registered at [%s]"), leading_whitespace, pal::get_dotnet_self_registered_config_location(arch).c_str());
}
}
}

return found_any;
}
15 changes: 15 additions & 0 deletions src/native/corehost/fxr/install_info.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

#ifndef __INSTALL_INFO_H__
#define __INSTALL_INFO_H__

#include "pal.h"

namespace install_info
{
bool print_environment(const pal::char_t* leading_whitespace);
bool print_installs(const pal::char_t* leading_whitespace, bool skip_current_arch);
};

#endif // __INSTALL_INFO_H__
4 changes: 2 additions & 2 deletions src/native/corehost/fxr_resolver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ bool fxr_resolver::try_get_path(const pal::string_t& root_path, pal::string_t* o
pal::get_default_installation_dir(&default_install_location);
}

pal::string_t self_registered_config_location = pal::get_dotnet_self_registered_config_location();
pal::string_t self_registered_config_location = pal::get_dotnet_self_registered_config_location(get_current_arch());
trace::verbose(_X("The required library %s could not be found. Searched with root path [%s], environment variable [%s], default install location [%s], self-registered config location [%s]"),
LIBFXR_NAME,
root_path.c_str(),
Expand All @@ -124,7 +124,7 @@ bool fxr_resolver::try_get_path(const pal::string_t& root_path, pal::string_t* o
_X("Download the .NET runtime:\n")
_X("%s&apphost_version=%s"),
host_path.c_str(),
get_arch(),
get_current_arch_name(),
_STRINGIFY(COMMON_HOST_PKG_VER),
get_download_url().c_str(),
_STRINGIFY(COMMON_HOST_PKG_VER));
Expand Down
25 changes: 22 additions & 3 deletions src/native/corehost/hostmisc/pal.h
Original file line number Diff line number Diff line change
Expand Up @@ -293,15 +293,34 @@ namespace pal
bool getenv(const char_t* name, string_t* recv);
bool get_default_servicing_directory(string_t* recv);

// Returns the globally registered install location (if any)
enum class known_architecture
{
arm,
arm64,
armv6,
loongarch64,
s390X,
x64,
x86,

__last // Sentinel value
};

// Returns the globally registered install location (if any) for the current architecture
bool get_dotnet_self_registered_dir(string_t* recv);

// Returns the globally registered install location (if any) for the specified architecture
bool get_dotnet_self_registered_dir_for_arch(known_architecture arch, string_t* recv);

// Returns name of the config location for global install registration (for example, registry key or file path)
string_t get_dotnet_self_registered_config_location();
string_t get_dotnet_self_registered_config_location(known_architecture arch);

// Returns the default install location for a given platform
// Returns the default install location for a given platform for the current architecture
bool get_default_installation_dir(string_t* recv);

// Returns the default install location for a given platform for the specified architecture
bool get_default_installation_dir_for_arch(known_architecture arch, string_t* recv);

// Returns the global locations to search for SDK/Frameworks - used when multi-level lookup is enabled
bool get_global_dotnet_dirs(std::vector<string_t>* recv);

Expand Down
Loading