Merge pull request #2392 from schellap/fxr-pol

Make hostfxr backward compatible with hostpolicy
This commit is contained in:
Senthil 2016-04-11 22:16:56 -07:00
commit 5f2183489f
15 changed files with 392 additions and 321 deletions

View file

@ -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);

View file

@ -18,8 +18,11 @@ arguments_t::arguments_t() :
{
}
bool parse_arguments(const pal::string_t& deps_path, const std::vector<pal::string_t>& 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<pal::string_t>& 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<pal::stri
args.app_argc = argc - 1;
}
std::unordered_map<pal::string_t, std::vector<pal::string_t>> opts;
std::vector<pal::string_t> 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);
}

View file

@ -115,6 +115,6 @@ struct arguments_t
}
};
bool parse_arguments(const pal::string_t& deps_path, const std::vector<pal::string_t>& 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<pal::string_t>& probe_paths, host_mode_t mode, const int argc, const pal::char_t* argv[], arguments_t* args);
#endif // ARGS_H

View file

@ -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))

View file

@ -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<deps_json_t>(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<pal::string_t>& probe_paths);

View file

@ -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<pal::string_t> 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<pal::string_t, std::vector<pal::string_t>> 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<const pal::char_t*> vec_argv;
const pal::char_t** new_argv = argv;
int new_argc = argc;
std::vector<const pal::char_t*> 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<pal::string_t, std::vector<pal::string_t>>& 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<pal::string_t> probe_paths = opts.count(opts_probe_path) ? opts[opts_probe_path] : std::vector<pal::string_t>();
trace::verbose(_X("Current argv is %s"), app_candidate.c_str());
std::vector<pal::string_t> probe_paths = opts.count(opts_probe_path) ? opts.find(opts_probe_path)->second : std::vector<pal::string_t>();
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);
}

View file

@ -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<pal::string_t, std::vector<pal::string_t>>& 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);

View file

@ -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<pal::string_t>(), 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<pal::string_t>(), _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);
}

View file

@ -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<std::string> cfg_keys;
std::vector<std::string> 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;
}

View file

@ -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;

View file

@ -3,7 +3,9 @@
#ifndef __LIBHOST_H__
#define __LIBHOST_H__
#include <stdint.h>
#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<pal::string_t> m_probe_paths;
const pal::string_t m_deps_file;
std::vector<pal::string_t> m_clr_keys;
std::vector<pal::string_t> m_clr_values;
std::vector<const pal::char_t*> m_clr_keys_cstr;
std::vector<const pal::char_t*> 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<pal::string_t> m_probe_paths;
std::vector<const pal::char_t*> 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<pal::string_t>& 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<pal::string_t>& 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<pal::string_t>& arr, std::vector<const pal::char_t*>* out)
{
out->reserve(arr.size());
for (const auto& str : arr)
{
out->push_back(str.c_str());
}
}
};
struct hostpolicy_init_t
{
std::vector<std::string> cfg_keys;
std::vector<std::string> cfg_values;
pal::string_t deps_file;
std::vector<pal::string_t> 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<pal::string_t>* 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<std::string>* 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);

View file

@ -208,11 +208,11 @@ const std::list<pal::string_t>& runtime_config_t::get_probe_paths() const
return m_probe_paths;
}
void runtime_config_t::config_kv(std::vector<std::string>* keys, std::vector<std::string>* values) const
void runtime_config_t::config_kv(std::vector<pal::string_t>* keys, std::vector<pal::string_t>* 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);
}
}

View file

@ -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 <list>
#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::string>*, std::vector<std::string>*) const;
void config_kv(std::vector<pal::string_t>*, std::vector<pal::string_t>*) const;
private:
bool ensure_parsed();
@ -48,3 +46,4 @@ private:
bool m_portable;
bool m_valid;
};
#endif // __RUNTIME_CONFIG_H__

View file

@ -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__

View file

@ -124,13 +124,14 @@ namespace Microsoft.DotNet.Tools.Run
return result;
}
List<string> hostArgs = new List<string>();
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