diff --git a/src/Microsoft.DotNet.Cli.Utils/CommandResolution/PackagedCommandSpecFactory.cs b/src/Microsoft.DotNet.Cli.Utils/CommandResolution/PackagedCommandSpecFactory.cs index 0fd1eb90e..106049425 100644 --- a/src/Microsoft.DotNet.Cli.Utils/CommandResolution/PackagedCommandSpecFactory.cs +++ b/src/Microsoft.DotNet.Cli.Utils/CommandResolution/PackagedCommandSpecFactory.cs @@ -107,46 +107,26 @@ namespace Microsoft.DotNet.Cli.Utils } arguments.Add("exec"); - - if (runtimeConfigPath != null) - { - arguments.Add("--runtimeconfig"); - arguments.Add(runtimeConfigPath); - } - - if (depsFilePath != null) - { - arguments.Add("--depsfile"); - arguments.Add(depsFilePath); - } - - arguments.Add("--additionalprobingpath"); - arguments.Add(nugetPackagesRoot); - - arguments.Add(commandPath); } else { host = CoreHost.HostExePath; - - arguments.Add(commandPath); - - if (runtimeConfigPath != null) - { - arguments.Add("--runtimeconfig"); - arguments.Add(runtimeConfigPath); - } - - if (depsFilePath != null) - { - arguments.Add("--depsfile"); - arguments.Add(depsFilePath); - } - - arguments.Add("--additionalprobingpath"); - arguments.Add(nugetPackagesRoot); + } + if (runtimeConfigPath != null) + { + arguments.Add("--runtimeconfig"); + arguments.Add(runtimeConfigPath); + } + if (depsFilePath != null) + { + arguments.Add("--depsfile"); + arguments.Add(depsFilePath); } + arguments.Add("--additionalprobingpath"); + arguments.Add(nugetPackagesRoot); + + arguments.Add(commandPath); arguments.AddRange(commandArguments); return CreateCommandSpec(host, arguments, commandResolutionStrategy); diff --git a/src/corehost/cli/args.cpp b/src/corehost/cli/args.cpp index 504edc77e..f7dc0b67b 100644 --- a/src/corehost/cli/args.cpp +++ b/src/corehost/cli/args.cpp @@ -18,8 +18,11 @@ arguments_t::arguments_t() : { } -bool parse_arguments(const pal::string_t& deps_path, const std::vector& probe_paths, host_mode_t mode, - const int argc, const pal::char_t* argv[], pal::string_t* runtime_config, arguments_t* arg_out) +bool parse_arguments( + const pal::string_t& deps_path, + const std::vector& probe_paths, + host_mode_t mode, + const int argc, const pal::char_t* argv[], arguments_t* arg_out) { arguments_t& args = *arg_out; // Get the full name of the application @@ -67,32 +70,9 @@ bool parse_arguments(const pal::string_t& deps_path, const std::vector> opts; - std::vector known_opts = { _X("--depsfile"), _X("--additionalprobingpath"), _X("--runtimeconfig") }; - int num_args = 0; - if (!parse_known_args(args.app_argc, args.app_argv, known_opts, &opts, &num_args)) + if (!deps_path.empty()) { - return false; - } - - args.app_argc -= num_args; - args.app_argv += num_args; - pal::string_t opts_deps_file = _X("--depsfile"); - pal::string_t opts_probe_path = _X("--additionalprobingpath"); - pal::string_t opts_runtime_config = _X("--runtimeconfig"); - pal::string_t deps_file = get_last_known_arg(opts, opts_deps_file, deps_path); - *runtime_config = get_last_known_arg(opts, opts_runtime_config, _X("")); - if (opts.count(opts_probe_path)) - { - for (const auto& str : opts[opts_probe_path]) - { - args.probe_paths.push_back(str); - } - } - - if (!deps_file.empty()) - { - args.deps_path = deps_file; + args.deps_path = deps_path; args.app_dir = get_directory(args.deps_path); } diff --git a/src/corehost/cli/args.h b/src/corehost/cli/args.h index 7870038b3..d854f9944 100644 --- a/src/corehost/cli/args.h +++ b/src/corehost/cli/args.h @@ -115,6 +115,6 @@ struct arguments_t } }; -bool parse_arguments(const pal::string_t& deps_path, const std::vector& probe_paths, host_mode_t mode, const int argc, const pal::char_t* argv[], pal::string_t* runtime_config, arguments_t* args); +bool parse_arguments(const pal::string_t& deps_path, const std::vector& probe_paths, host_mode_t mode, const int argc, const pal::char_t* argv[], arguments_t* args); #endif // ARGS_H diff --git a/src/corehost/cli/deps_resolver.cpp b/src/corehost/cli/deps_resolver.cpp index a336b774a..6370a2ad0 100644 --- a/src/corehost/cli/deps_resolver.cpp +++ b/src/corehost/cli/deps_resolver.cpp @@ -184,8 +184,7 @@ bool deps_resolver_t::try_roll_forward(const deps_entry_t& entry, } void deps_resolver_t::setup_probe_config( - const corehost_init_t* init, - const runtime_config_t& config, + const hostpolicy_init_t& init, const arguments_t& args) { if (pal::directory_exists(args.dotnet_extensions)) @@ -195,11 +194,11 @@ void deps_resolver_t::setup_probe_config( if (pal::directory_exists(ext_ni)) { // Servicing NI probe. - m_probes.push_back(probe_config_t::svc_ni(ext_ni, config.get_patch_roll_fwd(), config.get_prerelease_roll_fwd())); + m_probes.push_back(probe_config_t::svc_ni(ext_ni, init.patch_roll_forward, init.prerelease_roll_forward)); } // Servicing normal probe. - m_probes.push_back(probe_config_t::svc(args.dotnet_extensions, config.get_patch_roll_fwd(), config.get_prerelease_roll_fwd())); + m_probes.push_back(probe_config_t::svc(args.dotnet_extensions, init.patch_roll_forward, init.prerelease_roll_forward)); } if (pal::directory_exists(args.dotnet_packages_cache)) diff --git a/src/corehost/cli/deps_resolver.h b/src/corehost/cli/deps_resolver.h index ae225d412..759fbc56d 100644 --- a/src/corehost/cli/deps_resolver.h +++ b/src/corehost/cli/deps_resolver.h @@ -24,20 +24,20 @@ struct probe_paths_t class deps_resolver_t { public: - deps_resolver_t(const corehost_init_t* init, const runtime_config_t& config, const arguments_t& args) + deps_resolver_t(const hostpolicy_init_t& init, const arguments_t& args) // Important: FX dir should come from "init" than "config", // since the host could be launching from FX dir. - : m_fx_dir(init->fx_dir()) + : m_fx_dir(init.fx_dir) , m_app_dir(args.app_dir) , m_coreclr_index(-1) - , m_portable(config.get_portable()) + , m_portable(init.is_portable) , m_deps(nullptr) , m_fx_deps(nullptr) { m_deps_file = args.deps_path; if (m_portable) { - m_fx_deps_file = get_fx_deps(m_fx_dir, config.get_fx_name()); + m_fx_deps_file = get_fx_deps(m_fx_dir, init.fx_name); trace::verbose(_X("Using %s FX deps file"), m_fx_deps_file.c_str()); trace::verbose(_X("Using %s deps file"), m_deps_file.c_str()); m_fx_deps = std::unique_ptr(new deps_json_t(false, m_fx_deps_file)); @@ -49,14 +49,13 @@ public: } setup_additional_probes(args.probe_paths); - setup_probe_config(init, config, args); + setup_probe_config(init, args); } bool valid() { return m_deps->is_valid() && (!m_portable || m_fx_deps->is_valid()); } void setup_probe_config( - const corehost_init_t* init, - const runtime_config_t& config, + const hostpolicy_init_t& init, const arguments_t& args); void setup_additional_probes(const std::vector& probe_paths); diff --git a/src/corehost/cli/fxr/fx_muxer.cpp b/src/corehost/cli/fxr/fx_muxer.cpp index a078da49b..663a74513 100644 --- a/src/corehost/cli/fxr/fx_muxer.cpp +++ b/src/corehost/cli/fxr/fx_muxer.cpp @@ -254,18 +254,21 @@ int muxer_usage() return StatusCode::InvalidArgFailure; } -int fx_muxer_t::parse_args_and_execute(const pal::string_t& own_dir, int argoff, int argc, const pal::char_t* argv[], bool exec_mode, bool* is_an_app) +int fx_muxer_t::parse_args_and_execute( + const pal::string_t& own_dir, + const pal::string_t& own_dll, + int argoff, int argc, const pal::char_t* argv[], bool exec_mode, host_mode_t mode, bool* is_an_app) { *is_an_app = true; std::vector known_opts = { _X("--additionalprobingpath") }; - if (exec_mode) + if (exec_mode || mode == host_mode_t::split_fx || mode == host_mode_t::standalone) { known_opts.push_back(_X("--depsfile")); known_opts.push_back(_X("--runtimeconfig")); } - // Parse the known muxer arguments if any. + // Parse the known arguments if any. int num_parsed = 0; std::unordered_map> opts; if (!parse_known_args(argc - argoff, &argv[argoff], known_opts, &opts, &num_parsed)) @@ -273,41 +276,44 @@ int fx_muxer_t::parse_args_and_execute(const pal::string_t& own_dir, int argoff, trace::error(_X("Failed to parse supported arguments.")); return InvalidArgFailure; } - int cur_i = argoff + num_parsed; - if (cur_i >= argc) - { - return muxer_usage(); - } - pal::string_t app_candidate = argv[cur_i]; - bool is_app_runnable = ends_with(app_candidate, _X(".dll"), false) || ends_with(app_candidate, _X(".exe"), false); - - // If exec mode is on, then check we have a dll at this point - if (exec_mode) - { - if (!is_app_runnable) - { - trace::error(_X("dotnet exec needs a dll to execute. Try dotnet [--help]")); - return InvalidArgFailure; - } - } - // For non-exec, there is CLI invocation or app.dll execution after known args. - else - { - // Test if we have a real dll at this point. - if (!is_app_runnable) - { - // No we don't have a dll, this must be routed to the CLI. - *is_an_app = false; - return Success; - } - } - - // Transform dotnet [exec] [--additionalprobingpath path] [--depsfile file] dll [args] -> dotnet dll [args] - - std::vector vec_argv; const pal::char_t** new_argv = argv; int new_argc = argc; + std::vector vec_argv; + pal::string_t app_candidate = own_dll; + int cur_i = argoff + num_parsed; + if (mode != host_mode_t::standalone) + { + trace::verbose(_X("App not in standalone mode, so expecting more arguments...")); + if (cur_i >= argc) + { + return muxer_usage(); + } + + app_candidate = argv[cur_i]; + bool is_app_runnable = ends_with(app_candidate, _X(".dll"), false) || ends_with(app_candidate, _X(".exe"), false); + trace::verbose(_X("App %s runnable=[%d]"), app_candidate.c_str(), is_app_runnable); + // If exec mode is on, then check we have a dll at this point + if (exec_mode) + { + if (!is_app_runnable) + { + trace::error(_X("dotnet exec needs a dll to execute. Try dotnet [--help]")); + return InvalidArgFailure; + } + } + // For non-exec, non-standalone there is CLI invocation or app.dll execution after known args. + else + { + // Test if we have a real dll at this point. + if (!is_app_runnable) + { + // No we don't have a dll, this must be routed to the CLI. + *is_an_app = false; + return AppArgNotRunnable; + } + } + } if (cur_i != 1) { vec_argv.resize(argc - cur_i + 1, 0); // +1 for dotnet @@ -317,28 +323,36 @@ int fx_muxer_t::parse_args_and_execute(const pal::string_t& own_dir, int argoff, new_argc = vec_argv.size(); } + // Transform dotnet [exec] [--additionalprobingpath path] [--depsfile file] [dll] [args] -> dotnet [dll] [args] + return read_config_and_execute(own_dir, app_candidate, opts, new_argc, new_argv, mode); +} + +int fx_muxer_t::read_config_and_execute( + const pal::string_t& own_dir, + const pal::string_t& app_candidate, + const std::unordered_map>& opts, + int new_argc, const pal::char_t** new_argv, host_mode_t mode) +{ pal::string_t opts_deps_file = _X("--depsfile"); pal::string_t opts_probe_path = _X("--additionalprobingpath"); pal::string_t opts_runtime_config = _X("--runtimeconfig"); pal::string_t deps_file = get_last_known_arg(opts, opts_deps_file, _X("")); pal::string_t runtime_config = get_last_known_arg(opts, opts_runtime_config, _X("")); - std::vector probe_paths = opts.count(opts_probe_path) ? opts[opts_probe_path] : std::vector(); - - trace::verbose(_X("Current argv is %s"), app_candidate.c_str()); + std::vector probe_paths = opts.count(opts_probe_path) ? opts.find(opts_probe_path)->second : std::vector(); pal::string_t app_or_deps = deps_file.empty() ? app_candidate : deps_file; pal::string_t config_file, dev_config_file; - if(runtime_config.empty()) + if (runtime_config.empty()) { - trace::verbose(_X("Finding runtimeconfig.json from [%s]"), app_candidate.c_str()); - get_runtime_config_paths_from_app(app_candidate, &config_file, &dev_config_file); + trace::verbose(_X("App runtimeconfig.json from [%s]"), app_candidate.c_str()); + get_runtime_config_paths_from_app(app_candidate, &config_file, &dev_config_file); } else { - trace::verbose(_X("Finding runtimeconfig.json from [%s]"), runtime_config.c_str()); - get_runtime_config_paths_from_arg(runtime_config, &config_file, &dev_config_file); + trace::verbose(_X("Specified runtimeconfig.json from [%s]"), runtime_config.c_str()); + get_runtime_config_paths_from_arg(runtime_config, &config_file, &dev_config_file); } runtime_config_t config(config_file, dev_config_file); @@ -361,14 +375,19 @@ int fx_muxer_t::parse_args_and_execute(const pal::string_t& own_dir, int argoff, if (config.get_portable()) { trace::verbose(_X("Executing as a portable app as per config file [%s]"), config_file.c_str()); - pal::string_t fx_dir = resolve_fx_dir(own_dir, &config); - corehost_init_t init(deps_file, probe_paths, fx_dir, host_mode_t::muxer, &config); + pal::string_t fx_dir = (mode == host_mode_t::split_fx) ? own_dir : resolve_fx_dir(own_dir, &config); + corehost_init_t init(deps_file, probe_paths, fx_dir, mode, config); return execute_app(fx_dir, &init, new_argc, new_argv); } else { trace::verbose(_X("Executing as a standalone app as per config file [%s]"), config_file.c_str()); - pal::string_t impl_dir = get_directory(app_or_deps); + pal::string_t impl_dir; + if (!hostpolicy_exists_in_svc(&impl_dir)) + { + impl_dir = get_directory(app_or_deps); + } + trace::verbose(_X("The host impl directory before probing deps is [%s]"), impl_dir.c_str()); if (!library_exists_in_dir(impl_dir, LIBHOSTPOLICY_NAME, nullptr) && !probe_paths.empty() && !deps_file.empty()) { bool found = false; @@ -392,7 +411,7 @@ int fx_muxer_t::parse_args_and_execute(const pal::string_t& own_dir, int argoff, } impl_dir = get_directory(candidate); } - corehost_init_t init(deps_file, probe_paths, _X(""), host_mode_t::muxer, &config); + corehost_init_t init(deps_file, probe_paths, _X(""), mode, config); return execute_app(impl_dir, &init, new_argc, new_argv); } } @@ -400,13 +419,6 @@ int fx_muxer_t::parse_args_and_execute(const pal::string_t& own_dir, int argoff, /* static */ int fx_muxer_t::execute(const int argc, const pal::char_t* argv[]) { - trace::verbose(_X("--- Executing in muxer mode...")); - - if (argc <= 1) - { - return muxer_usage(); - } - pal::string_t own_path; // Get the full name of the application @@ -415,15 +427,40 @@ int fx_muxer_t::execute(const int argc, const pal::char_t* argv[]) trace::error(_X("Failed to locate current executable")); return StatusCode::LibHostCurExeFindFailure; } - auto own_dir = get_directory(own_path); + pal::string_t own_name = get_filename(own_path); + pal::string_t own_dir = get_directory(own_path); - bool is_an_app = false; - if (pal::strcasecmp(_X("exec"), argv[1]) == 0) + pal::string_t own_dll_filename = get_executable(own_name) + _X(".dll"); + pal::string_t own_dll = own_dir; + append_path(&own_dll, own_dll_filename.c_str()); + + trace::info(_X("Own DLL path=[%s]"), own_dll.c_str()); + auto mode = detect_operating_mode(own_dir, own_dll, own_name); + bool is_an_app = true; + if (mode == host_mode_t::split_fx) { - return parse_args_and_execute(own_dir, 2, argc, argv, true, &is_an_app); // arg offset 2 for dotnet, exec + trace::verbose(_X("--- Executing in split/FX mode...")); + return parse_args_and_execute(own_dir, own_dll, 1, argc, argv, false, host_mode_t::split_fx, &is_an_app); + } + if (mode == host_mode_t::standalone) + { + trace::verbose(_X("--- Executing in standalone mode...")); + return parse_args_and_execute(own_dir, own_dll, 1, argc, argv, false, host_mode_t::standalone, &is_an_app); } - int result = parse_args_and_execute(own_dir, 1, argc, argv, false, &is_an_app); // arg offset 1 for dotnet + trace::verbose(_X("--- Executing in muxer mode...")); + + if (argc <= 1) + { + return muxer_usage(); + } + + if (pal::strcasecmp(_X("exec"), argv[1]) == 0) + { + return parse_args_and_execute(own_dir, own_dll, 2, argc, argv, true, host_mode_t::muxer, &is_an_app); // arg offset 2 for dotnet, exec + } + + int result = parse_args_and_execute(own_dir, own_dll, 1, argc, argv, false, host_mode_t::muxer, &is_an_app); // arg offset 1 for dotnet if (is_an_app) { return result; @@ -452,6 +489,6 @@ int fx_muxer_t::execute(const int argc, const pal::char_t* argv[]) new_argv[1] = sdk_dotnet.c_str(); trace::verbose(_X("Using dotnet SDK dll=[%s]"), sdk_dotnet.c_str()); - return parse_args_and_execute(own_dir, 1, new_argv.size(), new_argv.data(), false, &is_an_app); + return parse_args_and_execute(own_dir, own_dll, 1, new_argv.size(), new_argv.data(), false, host_mode_t::muxer, &is_an_app); } diff --git a/src/corehost/cli/fxr/fx_muxer.h b/src/corehost/cli/fxr/fx_muxer.h index 0c2035bba..3815b8928 100644 --- a/src/corehost/cli/fxr/fx_muxer.h +++ b/src/corehost/cli/fxr/fx_muxer.h @@ -5,9 +5,11 @@ class corehost_init_t; class runtime_config_t; struct fx_ver_t; +#include "libhost.h" + int execute_app( const pal::string_t& impl_dll_dir, - const corehost_init_t* init, + corehost_init_t* init, const int argc, const pal::char_t* argv[]); @@ -16,7 +18,12 @@ class fx_muxer_t public: static int execute(const int argc, const pal::char_t* argv[]); private: - static int parse_args_and_execute(const pal::string_t& own_dir, int argoff, int argc, const pal::char_t* argv[], bool exec_mode, bool* can_execute); + static int read_config_and_execute( + const pal::string_t& own_dir, + const pal::string_t& app_candidate, + const std::unordered_map>& opts, + int new_argc, const pal::char_t** new_argv, host_mode_t mode); + static int parse_args_and_execute(const pal::string_t& own_dir, const pal::string_t& own_dll, int argoff, int argc, const pal::char_t* argv[], bool exec_mode, host_mode_t mode, bool* can_execute); static pal::string_t resolve_fx_dir(const pal::string_t& muxer_path, runtime_config_t* runtime); static pal::string_t resolve_cli_version(const pal::string_t& global); static bool resolve_sdk_dotnet_path(const pal::string_t& own_dir, pal::string_t* cli_sdk); diff --git a/src/corehost/cli/fxr/hostfxr.cpp b/src/corehost/cli/fxr/hostfxr.cpp index e1e427aad..db99b2807 100644 --- a/src/corehost/cli/fxr/hostfxr.cpp +++ b/src/corehost/cli/fxr/hostfxr.cpp @@ -11,7 +11,7 @@ #include "libhost.h" #include "runtime_config.h" -typedef int(*corehost_load_fn) (const corehost_init_t* init); +typedef int(*corehost_load_fn) (const host_interface_t* init); typedef int(*corehost_main_fn) (const int argc, const pal::char_t* argv[]); typedef int(*corehost_unload_fn) (); @@ -47,7 +47,7 @@ int load_host_library( int execute_app( const pal::string_t& impl_dll_dir, - const corehost_init_t* init, + corehost_init_t* init, const int argc, const pal::char_t* argv[]) { @@ -63,15 +63,16 @@ int execute_app( trace::error(_X("Could not load host policy library from [%s]"), impl_dll_dir.c_str()); if (init->fx_dir() == impl_dll_dir) { - pal::string_t name = init->runtime_config()->get_fx_name(); - pal::string_t version = init->runtime_config()->get_fx_version(); - trace::error(_X("This may be because the targeted framework [%s %s] was not found."), + pal::string_t name = init->fx_name(); + pal::string_t version = init->fx_version(); + trace::error(_X("This may be because the targeted framework [\"%s\": \"%s\"] was not found."), name.c_str(), version.c_str()); } return code; } - if ((code = host_load(init)) == 0) + const host_interface_t& intf = init->get_host_init_data(); + if ((code = host_load(&intf)) == 0) { code = host_main(argc, argv); (void)host_unload(); @@ -100,7 +101,7 @@ bool hostpolicy_exists_in_svc(pal::string_t* resolved_dir) { replace_char(&rel_dir, '/', DIR_SEPARATOR); } - + pal::string_t path = svc_dir; append_path(&path, _STRINGIFY(HOST_POLICY_PKG_NAME)); @@ -113,8 +114,8 @@ bool hostpolicy_exists_in_svc(pal::string_t* resolved_dir) { try_patch_roll_forward_in_dir(path, lib_ver, &max_ver); } - - + + append_path(&path, max_ver.c_str()); append_path(&path, rel_dir.c_str()); @@ -132,38 +133,7 @@ SHARED_API int hostfxr_main(const int argc, const pal::char_t* argv[]) { trace::setup(); - pal::string_t own_dir; - auto mode = detect_operating_mode(argc, argv, &own_dir); - - switch (mode) - { - case muxer: - { - trace::info(_X("Host operating in Muxer mode")); - fx_muxer_t muxer; - return muxer.execute(argc, argv); - } - - case split_fx: - { - trace::info(_X("Host operating in split mode; own dir=[%s]"), own_dir.c_str()); - corehost_init_t init(_X(""), std::vector(), own_dir, host_mode_t::split_fx, nullptr); - return execute_app(own_dir, &init, argc, argv); - } - - case standalone: - { - trace::info(_X("Host operating from standalone app dir %s"), own_dir.c_str()); - - pal::string_t svc_dir; - corehost_init_t init(_X(""), std::vector(), _X(""), host_mode_t::standalone, nullptr); - return execute_app( - hostpolicy_exists_in_svc(&svc_dir) ? svc_dir : own_dir, &init, argc, argv); - } - - default: - trace::error(_X("Unknown mode detected or could not resolve the mode.")); - return StatusCode::CoreHostResolveModeFailure; - } + fx_muxer_t muxer; + return muxer.execute(argc, argv); } diff --git a/src/corehost/cli/hostpolicy.cpp b/src/corehost/cli/hostpolicy.cpp index 145765f62..472a4445a 100644 --- a/src/corehost/cli/hostpolicy.cpp +++ b/src/corehost/cli/hostpolicy.cpp @@ -12,13 +12,12 @@ #include "libhost.h" #include "error_codes.h" +hostpolicy_init_t g_init; -corehost_init_t* g_init = nullptr; - -int run(const corehost_init_t* init, const runtime_config_t& config, const arguments_t& args) +int run(const arguments_t& args) { // Load the deps resolver - deps_resolver_t resolver(init, config, args); + deps_resolver_t resolver(g_init, args); if (!resolver.valid()) { @@ -82,15 +81,10 @@ int run(const corehost_init_t* init, const runtime_config_t& config, const argum deps.c_str(), }; - - std::vector cfg_keys; - std::vector cfg_values; - config.config_kv(&cfg_keys, &cfg_values); - - for (int i = 0; i < cfg_keys.size(); ++i) + for (int i = 0; i < g_init.cfg_keys.size(); ++i) { - property_keys.push_back(cfg_keys[i].c_str()); - property_values.push_back(cfg_values[i].c_str()); + property_keys.push_back(g_init.cfg_keys[i].c_str()); + property_values.push_back(g_init.cfg_values[i].c_str()); } size_t property_size = property_keys.size(); @@ -188,26 +182,20 @@ int run(const corehost_init_t* init, const runtime_config_t& config, const argum return exit_code; } -SHARED_API int corehost_load(corehost_init_t* init) +SHARED_API int corehost_load(host_interface_t* init) { - g_init = init; - trace::setup(); - - if (g_init->version() != corehost_init_t::s_version) + + if (!hostpolicy_init_t::init(init, &g_init)) { - trace::error(_X("Error loading hostpolicy %s; interface mismatch between hostpolicy [%d] and hostfxr [%d]"), - _STRINGIFY(HOST_POLICY_PKG_VER), corehost_init_t::s_version, g_init->version()); - trace::error(_X("Specifically, the structure of corehost_init_t has changed, do not know how to interpret it")); return StatusCode::LibHostInitFailure; } + return 0; } SHARED_API int corehost_main(const int argc, const pal::char_t* argv[]) { - assert(g_init); - if (trace::is_enabled()) { trace::info(_X("--- Invoked policy [%s/%s/%s] main = {"), @@ -221,9 +209,8 @@ SHARED_API int corehost_main(const int argc, const pal::char_t* argv[]) } trace::info(_X("}")); - trace::info(_X("Host mode: %d"), g_init->host_mode()); - trace::info(_X("Deps file: %s"), g_init->deps_file().c_str()); - for (const auto& probe : g_init->probe_paths()) + trace::info(_X("Deps file: %s"), g_init.deps_file.c_str()); + for (const auto& probe : g_init.probe_paths) { trace::info(_X("Additional probe dir: %s"), probe.c_str()); } @@ -231,8 +218,7 @@ SHARED_API int corehost_main(const int argc, const pal::char_t* argv[]) // Take care of arguments arguments_t args; - pal::string_t runtime_config; - if (!parse_arguments(g_init->deps_file(), g_init->probe_paths(), g_init->host_mode(), argc, argv, &runtime_config, &args)) + if (!parse_arguments(g_init.deps_file, g_init.probe_paths, g_init.host_mode, argc, argv, &args)) { return StatusCode::LibHostInvalidArgs; } @@ -241,36 +227,10 @@ SHARED_API int corehost_main(const int argc, const pal::char_t* argv[]) args.print(); } - if (g_init->runtime_config()) - { - return run(g_init, *g_init->runtime_config(), args); - } - else - { - pal::string_t config_file, dev_config_file; - if (runtime_config.empty()) - { - get_runtime_config_paths_from_app(args.managed_application, &config_file, &dev_config_file); - } - else - { - get_runtime_config_paths_from_arg(runtime_config, &config_file, &dev_config_file); - } - runtime_config_t config(config_file, dev_config_file); - - if (!config.is_valid()) - { - trace::error(_X("Invalid runtimeconfig.json [%s] [%s]"), config.get_path().c_str(), config.get_dev_path().c_str()); - return StatusCode::InvalidConfigFile; - } - // TODO: This is ugly. The whole runtime config/probe paths business should all be resolved by and come from the hostfxr.cpp. - args.probe_paths.insert(args.probe_paths.end(), config.get_probe_paths().begin(), config.get_probe_paths().end()); - return run(g_init, config, args); - } + return run(args); } SHARED_API int corehost_unload() { - g_init = nullptr; return 0; } diff --git a/src/corehost/cli/libhost.cpp b/src/corehost/cli/libhost.cpp index 63984952f..87e270490 100644 --- a/src/corehost/cli/libhost.cpp +++ b/src/corehost/cli/libhost.cpp @@ -22,7 +22,7 @@ void get_runtime_config_paths_from_app(const pal::string_t& app, pal::string_t* trace::verbose(_X("Runtime config is cfg=%s dev=%s"), json_path.c_str(), dev_json_path.c_str()); dev_cfg->assign(dev_json_path); - cfg -> assign(json_path); + cfg->assign(json_path); } void get_runtime_config_paths_from_arg(const pal::string_t& arg, pal::string_t* cfg, pal::string_t* dev_cfg) @@ -41,29 +41,11 @@ void get_runtime_config_paths_from_arg(const pal::string_t& arg, pal::string_t* trace::verbose(_X("Runtime config is cfg=%s dev=%s"), json_path.c_str(), dev_json_path.c_str()); dev_cfg->assign(dev_json_path); - cfg -> assign(json_path); + cfg->assign(json_path); } -host_mode_t detect_operating_mode(const int argc, const pal::char_t* argv[], pal::string_t* p_own_dir) +host_mode_t detect_operating_mode(const pal::string_t& own_dir, const pal::string_t& own_dll, const pal::string_t& own_name) { - pal::string_t own_path; - if (!pal::get_own_executable_path(&own_path) || !pal::realpath(&own_path)) - { - trace::error(_X("Failed to locate current executable")); - return host_mode_t::invalid; - } - - pal::string_t own_name = get_filename(own_path); - pal::string_t own_dir = get_directory(own_path); - if (p_own_dir) - { - p_own_dir->assign(own_dir); - } - - pal::string_t own_dll_filename = get_executable(own_name) + _X(".dll"); - pal::string_t own_dll = own_dir; - append_path(&own_dll, own_dll_filename.c_str()); - trace::info(_X("Own DLL path=[%s]"), own_dll.c_str()); if (coreclr_exists_in_dir(own_dir) || pal::file_exists(own_dll)) { pal::string_t own_deps_json = own_dir; @@ -117,7 +99,6 @@ void try_patch_roll_forward_in_dir(const pal::string_t& cur_dir, const fx_ver_t& } } - void try_prerelease_roll_forward_in_dir(const pal::string_t& cur_dir, const fx_ver_t& start_ver, pal::string_t* max_str) { pal::string_t path = cur_dir; diff --git a/src/corehost/cli/libhost.h b/src/corehost/cli/libhost.h index 389e21d57..ea2db1899 100644 --- a/src/corehost/cli/libhost.h +++ b/src/corehost/cli/libhost.h @@ -3,7 +3,9 @@ #ifndef __LIBHOST_H__ #define __LIBHOST_H__ - +#include +#include "trace.h" +#include "runtime_config.h" #include "fx_ver.h" enum host_mode_t @@ -17,51 +19,97 @@ enum host_mode_t class fx_ver_t; class runtime_config_t; +#define _HOST_INTERFACE_PACK 1 +#pragma pack(push, _HOST_INTERFACE_PACK) +struct strarr_t +{ + // DO NOT modify this struct. It is used in a layout + // dependent manner. Create another for your use. + size_t len; + const pal::char_t** arr; +}; + +struct host_interface_t +{ + size_t version_lo; // Just assign sizeof() to this field. + size_t version_hi; // Breaking changes to the layout -- increment HOST_INTERFACE_LAYOUT_VERSION + strarr_t config_keys; + strarr_t config_values; + const pal::char_t* fx_dir; + const pal::char_t* fx_name; + const pal::char_t* deps_file; + size_t is_portable; + strarr_t probe_paths; + size_t patch_roll_forward; + size_t prerelease_roll_forward; + size_t host_mode; + // !! WARNING / WARNING / WARNING / WARNING / WARNING / WARNING / WARNING / WARNING / WARNING + // !! 1. Only append to this structure to maintain compat. + // !! 2. Any nested structs should not use compiler specific padding (pack with _HOST_INTERFACE_PACK) + // !! 3. Do not take address of the fields of this struct or be prepared to deal with unaligned accesses. + // !! 4. Must be POD types; only use non-const size_t and pointer types; no access modifiers. + // !! 5. Do not reorder fields or change any existing field types. + // !! 6. Add static asserts for fields you add. +}; +#pragma pack(pop) +static_assert(_HOST_INTERFACE_PACK == 1, "Packing size should not be modified for back compat"); +static_assert(offsetof(host_interface_t, version_lo) == 0 * sizeof(size_t), "Struct offset breaks backwards compatibility"); +static_assert(offsetof(host_interface_t, version_hi) == 1 * sizeof(size_t), "Struct offset breaks backwards compatibility"); +static_assert(offsetof(host_interface_t, config_keys) == 2 * sizeof(size_t), "Struct offset breaks backwards compatibility"); +static_assert(offsetof(host_interface_t, config_values) == 4 * sizeof(size_t), "Struct offset breaks backwards compatibility"); +static_assert(offsetof(host_interface_t, fx_dir) == 6 * sizeof(size_t), "Struct offset breaks backwards compatibility"); +static_assert(offsetof(host_interface_t, fx_name) == 7 * sizeof(size_t), "Struct offset breaks backwards compatibility"); +static_assert(offsetof(host_interface_t, deps_file) == 8 * sizeof(size_t), "Struct offset breaks backwards compatibility"); +static_assert(offsetof(host_interface_t, is_portable) == 9 * sizeof(size_t), "Struct offset breaks backwards compatibility"); +static_assert(offsetof(host_interface_t, probe_paths) == 10 * sizeof(size_t), "Struct offset breaks backwards compatibility"); +static_assert(offsetof(host_interface_t, patch_roll_forward) == 12 * sizeof(size_t), "Struct offset breaks backwards compatibility"); +static_assert(offsetof(host_interface_t, prerelease_roll_forward) == 13 * sizeof(size_t), "Struct offset breaks backwards compatibility"); +static_assert(offsetof(host_interface_t, host_mode) == 14 * sizeof(size_t), "Struct offset breaks backwards compatibility"); +static_assert(sizeof(host_interface_t) == 15 * sizeof(size_t), "Did you add static asserts for the newly added fields?"); + +#define HOST_INTERFACE_LAYOUT_VERSION_HI 0x16041101 // YYMMDD:nn always increases when layout breaks compat. +#define HOST_INTERFACE_LAYOUT_VERSION_LO sizeof(host_interface_t) + class corehost_init_t { - // // WARNING // WARNING // WARNING // WARNING // WARNING // WARNING // - // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - // !! If you change this class layout increment the s_version field; !! - // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - -public: - static const int s_version = 0x8003; private: - int m_version; - std::vector m_probe_paths; - const pal::string_t m_deps_file; + std::vector m_clr_keys; + std::vector m_clr_values; + std::vector m_clr_keys_cstr; + std::vector m_clr_values_cstr; const pal::string_t m_fx_dir; + const pal::string_t m_fx_name; + const pal::string_t m_deps_file; + bool m_portable; + std::vector m_probe_paths; + std::vector m_probe_paths_cstr; + bool m_patch_roll_forward; + bool m_prerelease_roll_forward; host_mode_t m_host_mode; - const runtime_config_t* m_runtime_config; + host_interface_t m_host_interface; + const pal::string_t m_fx_ver; public: corehost_init_t( const pal::string_t& deps_file, const std::vector& probe_paths, const pal::string_t& fx_dir, const host_mode_t mode, - const runtime_config_t* runtime_config) + const runtime_config_t& runtime_config) : m_fx_dir(fx_dir) - , m_runtime_config(runtime_config) + , m_fx_name(runtime_config.get_fx_name()) , m_deps_file(deps_file) + , m_portable(runtime_config.get_portable()) , m_probe_paths(probe_paths) + , m_patch_roll_forward(runtime_config.get_patch_roll_fwd()) + , m_prerelease_roll_forward(runtime_config.get_prerelease_roll_fwd()) , m_host_mode(mode) - , m_version(s_version) + , m_host_interface() + , m_fx_ver(runtime_config.get_fx_version()) { - } - - const host_mode_t host_mode() const - { - return m_host_mode; - } - - const pal::string_t& deps_file() const - { - return m_deps_file; - } - - const std::vector& probe_paths() const - { - return m_probe_paths; + runtime_config.config_kv(&m_clr_keys, &m_clr_values); + make_cstr_arr(m_clr_keys, &m_clr_keys_cstr); + make_cstr_arr(m_clr_values, &m_clr_values_cstr); + make_cstr_arr(m_probe_paths, &m_probe_paths_cstr); } const pal::string_t& fx_dir() const @@ -69,21 +117,128 @@ public: return m_fx_dir; } - const runtime_config_t* runtime_config() const + const pal::string_t& fx_name() const { - return m_runtime_config; + return m_fx_name; } - int version() const + const pal::string_t& fx_version() const { - return m_version; + return m_fx_ver; + } + + const host_interface_t& get_host_init_data() + { + host_interface_t& hi = m_host_interface; + + hi.version_lo = HOST_INTERFACE_LAYOUT_VERSION_LO; + hi.version_hi = HOST_INTERFACE_LAYOUT_VERSION_HI; + + hi.config_keys.len = m_clr_keys_cstr.size(); + hi.config_keys.arr = m_clr_keys_cstr.data(); + + hi.config_values.len = m_clr_values_cstr.size(); + hi.config_values.arr = m_clr_values_cstr.data(); + + hi.fx_dir = m_fx_dir.c_str(); + hi.fx_name = m_fx_name.c_str(); + hi.deps_file = m_deps_file.c_str(); + hi.is_portable = m_portable; + + hi.probe_paths.len = m_probe_paths_cstr.size(); + hi.probe_paths.arr = m_probe_paths_cstr.data(); + + hi.patch_roll_forward = m_patch_roll_forward; + hi.prerelease_roll_forward = m_prerelease_roll_forward; + hi.host_mode = m_host_mode; + + return hi; + } + +private: + + static void make_cstr_arr(const std::vector& arr, std::vector* out) + { + out->reserve(arr.size()); + for (const auto& str : arr) + { + out->push_back(str.c_str()); + } + } +}; + + +struct hostpolicy_init_t +{ + std::vector cfg_keys; + std::vector cfg_values; + pal::string_t deps_file; + std::vector probe_paths; + pal::string_t fx_dir; + pal::string_t fx_name; + host_mode_t host_mode; + bool patch_roll_forward; + bool prerelease_roll_forward; + bool is_portable; + + static bool init(host_interface_t* input, hostpolicy_init_t* init) + { + // Check if there are any breaking changes. + if (input->version_hi != HOST_INTERFACE_LAYOUT_VERSION_HI) + { + trace::error(_X("The version of the data layout used to initialize %s is [0x%04x]; expected version [0x%04x]"), LIBHOSTPOLICY_NAME, input->version_hi, HOST_INTERFACE_LAYOUT_VERSION_HI); + return false; + } + // Check if the size is at least what we expect to contain. + if (input->version_lo < HOST_INTERFACE_LAYOUT_VERSION_LO) + { + trace::error(_X("The size of the data layout used to initialize %s is %d; expected at least %d"), LIBHOSTPOLICY_NAME, input->version_lo, HOST_INTERFACE_LAYOUT_VERSION_LO); + return false; + } + trace::verbose(_X("Reading from host interface version: [0x%04x:%d] to initialize policy version: [0x%04x:%d]"), input->version_hi, input->version_lo, HOST_INTERFACE_LAYOUT_VERSION_HI, HOST_INTERFACE_LAYOUT_VERSION_LO); + + make_stdstr_arr(input->config_keys.len, input->config_keys.arr, &init->cfg_keys); + make_stdstr_arr(input->config_values.len, input->config_values.arr, &init->cfg_values); + + init->fx_dir = input->fx_dir; + init->fx_name = input->fx_name; + init->deps_file = input->deps_file; + init->is_portable = input->is_portable; + + make_palstr_arr(input->probe_paths.len, input->probe_paths.arr, &init->probe_paths); + + init->patch_roll_forward = input->patch_roll_forward; + init->prerelease_roll_forward = input->prerelease_roll_forward; + init->host_mode = (host_mode_t) input->host_mode; + + return true; + } + +private: + static void make_palstr_arr(int argc, const pal::char_t** argv, std::vector* out) + { + out->reserve(argc); + for (int i = 0; i < argc; ++i) + { + out->push_back(argv[i]); + } + } + + static void make_stdstr_arr(int argc, const pal::char_t** argv, std::vector* out) + { + out->reserve(argc); + for (int i = 0; i < argc; ++i) + { + out->push_back(pal::to_stdstring(argv[i])); + } } }; void get_runtime_config_paths_from_app(const pal::string_t& file, pal::string_t* config_file, pal::string_t* dev_config_file); void get_runtime_config_paths_from_arg(const pal::string_t& file, pal::string_t* config_file, pal::string_t* dev_config_file); -host_mode_t detect_operating_mode(const int argc, const pal::char_t* argv[], pal::string_t* own_dir = nullptr); +host_mode_t detect_operating_mode(const pal::string_t& own_dir, const pal::string_t& own_dll, const pal::string_t& own_name); +bool hostpolicy_exists_in_svc(pal::string_t* resolved_dir); void try_patch_roll_forward_in_dir(const pal::string_t& cur_dir, const fx_ver_t& start_ver, pal::string_t* max_str); void try_prerelease_roll_forward_in_dir(const pal::string_t& cur_dir, const fx_ver_t& start_ver, pal::string_t* max_str); diff --git a/src/corehost/cli/runtime_config.cpp b/src/corehost/cli/runtime_config.cpp index 0b1eae6c2..c64b7cca2 100644 --- a/src/corehost/cli/runtime_config.cpp +++ b/src/corehost/cli/runtime_config.cpp @@ -208,11 +208,11 @@ const std::list& runtime_config_t::get_probe_paths() const return m_probe_paths; } -void runtime_config_t::config_kv(std::vector* keys, std::vector* values) const +void runtime_config_t::config_kv(std::vector* keys, std::vector* values) const { for (const auto& kv : m_properties) { - keys->push_back(pal::to_stdstring(kv.first)); - values->push_back(pal::to_stdstring(kv.second)); + keys->push_back(kv.first); + values->push_back(kv.second); } } diff --git a/src/corehost/cli/runtime_config.h b/src/corehost/cli/runtime_config.h index 29a0695b1..f51e0324f 100644 --- a/src/corehost/cli/runtime_config.h +++ b/src/corehost/cli/runtime_config.h @@ -1,6 +1,9 @@ // Copyright (c) .NET Foundation and contributors. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. +#ifndef __RUNTIME_CONFIG_H__ +#define __RUNTIME_CONFIG_H__ + #include #include "pal.h" @@ -10,11 +13,6 @@ typedef web::json::value json_value; class runtime_config_t { - // // WARNING // WARNING // WARNING // WARNING // WARNING // WARNING // - // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - // !! If you change this class layout increment the !! - // !! corehost_init_t::s_version field; !! - // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! public: runtime_config_t(const pal::string_t& path, const pal::string_t& dev_path); bool is_valid() { return m_valid; } @@ -28,7 +26,7 @@ public: bool get_prerelease_roll_fwd() const; bool get_portable() const; bool parse_opts(const json_value& opts); - void config_kv(std::vector*, std::vector*) const; + void config_kv(std::vector*, std::vector*) const; private: bool ensure_parsed(); @@ -48,3 +46,4 @@ private: bool m_portable; bool m_valid; }; +#endif // __RUNTIME_CONFIG_H__ \ No newline at end of file diff --git a/src/corehost/error_codes.h b/src/corehost/error_codes.h index d5a0bc141..3b06f6f9e 100644 --- a/src/corehost/error_codes.h +++ b/src/corehost/error_codes.h @@ -5,25 +5,26 @@ #define __ERROR_CODES_H__ enum StatusCode { - Success = 0, - InvalidArgFailure = 0x81, - CoreHostLibLoadFailure = 0x82, - CoreHostLibMissingFailure = 0x83, - CoreHostEntryPointFailure = 0x84, - CoreHostCurExeFindFailure = 0x85, - CoreHostResolveModeFailure = 0x86, - CoreClrResolveFailure = 0x87, - CoreClrBindFailure = 0x88, - CoreClrInitFailure = 0x89, - CoreClrExeFailure = 0x90, - ResolverInitFailure = 0x91, - ResolverResolveFailure = 0x92, - LibHostCurExeFindFailure = 0x93, - LibHostInitFailure = 0x94, - LibHostMuxFailure = 0x95, - LibHostExecModeFailure = 0x96, - LibHostSdkFindFailure = 0x97, - LibHostInvalidArgs = 0x98, - InvalidConfigFile = 0x99, + Success = 0, + InvalidArgFailure = 0x80008081, + CoreHostLibLoadFailure = 0x80008082, + CoreHostLibMissingFailure = 0x80008083, + CoreHostEntryPointFailure = 0x80008084, + CoreHostCurExeFindFailure = 0x80008085, + CoreHostResolveModeFailure = 0x80008086, + CoreClrResolveFailure = 0x80008087, + CoreClrBindFailure = 0x80008088, + CoreClrInitFailure = 0x80008089, + CoreClrExeFailure = 0x8000808a, + ResolverInitFailure = 0x8000808b, + ResolverResolveFailure = 0x8000808c, + LibHostCurExeFindFailure = 0x8000808d, + LibHostInitFailure = 0x8000808e, + LibHostMuxFailure = 0x8000808f, + LibHostExecModeFailure = 0x80008090, + LibHostSdkFindFailure = 0x80008091, + LibHostInvalidArgs = 0x80008092, + InvalidConfigFile = 0x80008093, + AppArgNotRunnable = 0x80008094 }; #endif // __ERROR_CODES_H__ diff --git a/src/dotnet/commands/dotnet-run/RunCommand.cs b/src/dotnet/commands/dotnet-run/RunCommand.cs index 2b5f9efd0..5f5296130 100644 --- a/src/dotnet/commands/dotnet-run/RunCommand.cs +++ b/src/dotnet/commands/dotnet-run/RunCommand.cs @@ -124,13 +124,14 @@ namespace Microsoft.DotNet.Tools.Run return result; } + List hostArgs = new List(); if (!_context.TargetFramework.IsDesktop()) { // Add Nuget Packages Probing Path var nugetPackagesRoot = _context.PackagesDirectory; var probingPathArg = "--additionalprobingpath"; - _args.Insert(0, nugetPackagesRoot); - _args.Insert(0, probingPathArg); + hostArgs.Insert(0, nugetPackagesRoot); + hostArgs.Insert(0, probingPathArg); } // Now launch the output and give it the results @@ -161,11 +162,13 @@ namespace Microsoft.DotNet.Tools.Run // The executable is a ".dll", we need to call it through dotnet.exe var muxer = new Muxer(); - command = Command.Create(muxer.MuxerPath, Enumerable.Concat(new[] { "exec", outputName }, _args)); + command = Command.Create(muxer.MuxerPath, Enumerable.Concat( + Enumerable.Concat(new string[] { "exec" }, hostArgs), + Enumerable.Concat(new string[] { outputName }, _args))); } else { - command = Command.Create(outputName, _args); + command = Command.Create(outputName, Enumerable.Concat(hostArgs, _args)); } result = command