int run(const arguments_t& args, const pal::string_t& clr_path) { // Load the deps resolver deps_resolver_t resolver(args); if (!resolver.valid()) { trace::error(_X("Invalid .deps file")); return StatusCode::ResolverInitFailure; } // Add packages directory pal::string_t packages_dir = args.nuget_packages; if (!pal::directory_exists(packages_dir)) { (void)pal::get_default_packages_directory(&packages_dir); } trace::info(_X("Package directory: %s"), packages_dir.empty() ? _X("not specified") : packages_dir.c_str()); probe_paths_t probe_paths; if (!resolver.resolve_probe_paths(args.app_dir, packages_dir, args.dotnet_packages_cache, clr_path, &probe_paths)) { return StatusCode::ResolverResolveFailure; } // Build CoreCLR properties const char* property_keys[] = { "TRUSTED_PLATFORM_ASSEMBLIES", "APP_PATHS", "APP_NI_PATHS", "NATIVE_DLL_SEARCH_DIRECTORIES", "PLATFORM_RESOURCE_ROOTS", "AppDomainCompatSwitch", // TODO: pipe this from corehost.json "SERVER_GC", }; auto tpa_paths_cstr = pal::to_stdstring(probe_paths.tpa); auto app_base_cstr = pal::to_stdstring(args.app_dir); auto native_dirs_cstr = pal::to_stdstring(probe_paths.native); auto culture_dirs_cstr = pal::to_stdstring(probe_paths.culture); // Workaround for dotnet/cli Issue #488 and #652 pal::string_t server_gc; std::string server_gc_cstr = (pal::getenv(_X("COREHOST_SERVER_GC"), &server_gc) && !server_gc.empty()) ? pal::to_stdstring(server_gc) : "1"; const char* property_values[] = { // TRUSTED_PLATFORM_ASSEMBLIES tpa_paths_cstr.c_str(), // APP_PATHS app_base_cstr.c_str(), // APP_NI_PATHS app_base_cstr.c_str(), // NATIVE_DLL_SEARCH_DIRECTORIES native_dirs_cstr.c_str(), // PLATFORM_RESOURCE_ROOTS culture_dirs_cstr.c_str(), // AppDomainCompatSwitch "UseLatestBehaviorWhenTFMNotSpecified", // SERVER_GC server_gc_cstr.c_str(), }; size_t property_size = sizeof(property_keys) / sizeof(property_keys[0]); // Bind CoreCLR if (!coreclr::bind(clr_path)) { trace::error(_X("Failed to bind to coreclr")); return StatusCode::CoreClrBindFailure; } // Verbose logging if (trace::is_enabled()) { for (size_t i = 0; i < property_size; ++i) { pal::string_t key, val; pal::to_palstring(property_keys[i], &key); pal::to_palstring(property_values[i], &val); trace::verbose(_X("Property %s = %s"), key.c_str(), val.c_str()); } } std::string own_path; pal::to_stdstring(args.own_path.c_str(), &own_path); // Initialize CoreCLR coreclr::host_handle_t host_handle; coreclr::domain_id_t domain_id; auto hr = coreclr::initialize( own_path.c_str(), "clrhost", property_keys, property_values, property_size, &host_handle, &domain_id); if (!SUCCEEDED(hr)) { trace::error(_X("Failed to initialize CoreCLR, HRESULT: 0x%X"), hr); return StatusCode::CoreClrInitFailure; } if (trace::is_enabled()) { pal::string_t arg_str; for (int i = 0; i < args.app_argc; i++) { arg_str.append(args.app_argv[i]); arg_str.append(_X(",")); } trace::info(_X("Launch host: %s app: %s, argc: %d args: %s"), args.own_path.c_str(), args.managed_application.c_str(), args.app_argc, arg_str.c_str()); } // Initialize with empty strings std::vector<std::string> argv_strs(args.app_argc); std::vector<const char*> argv(args.app_argc); for (int i = 0; i < args.app_argc; i++) { pal::to_stdstring(args.app_argv[i], &argv_strs[i]); argv[i] = argv_strs[i].c_str(); } std::string managed_app = pal::to_stdstring(args.managed_application); // Execute the application unsigned int exit_code = 1; hr = coreclr::execute_assembly( host_handle, domain_id, argv.size(), argv.data(), managed_app.c_str(), &exit_code); if (!SUCCEEDED(hr)) { trace::error(_X("Failed to execute managed app, HRESULT: 0x%X"), hr); return StatusCode::CoreClrExeFailure; } // Shut down the CoreCLR hr = coreclr::shutdown(host_handle, domain_id); if (!SUCCEEDED(hr)) { trace::warning(_X("Failed to shut down CoreCLR, HRESULT: 0x%X"), hr); } coreclr::unload(); return exit_code; }
int run(const arguments_t& args) { // Load the deps resolver deps_resolver_t resolver(g_init, args); pal::string_t resolver_errors; if (!resolver.valid(&resolver_errors)) { trace::error(_X("Error initializing the dependency resolver: %s"), resolver_errors.c_str()); return StatusCode::ResolverInitFailure; } // Setup breadcrumbs pal::string_t policy_name = _STRINGIFY(HOST_POLICY_PKG_NAME); pal::string_t policy_version = _STRINGIFY(HOST_POLICY_PKG_VER); // Always insert the hostpolicy that the code is running on. std::unordered_set<pal::string_t> breadcrumbs; breadcrumbs.insert(policy_name); breadcrumbs.insert(policy_name + _X(",") + policy_version); probe_paths_t probe_paths; if (!resolver.resolve_probe_paths(&probe_paths, &breadcrumbs)) { return StatusCode::ResolverResolveFailure; } pal::string_t clr_path = probe_paths.coreclr; if (clr_path.empty() || !pal::realpath(&clr_path)) { trace::error(_X("Could not resolve CoreCLR path. For more details, enable tracing by setting COREHOST_TRACE environment variable to 1"));; return StatusCode::CoreClrResolveFailure; } pal::string_t clrjit_path = probe_paths.clrjit; if (clrjit_path.empty()) { trace::warning(_X("Could not resolve CLRJit path")); } else if (pal::realpath(&clrjit_path)) { trace::verbose(_X("The resolved JIT path is '%s'"), clrjit_path.c_str()); } else { clrjit_path.clear(); trace::warning(_X("Could not resolve symlink to CLRJit path '%s'"), probe_paths.clrjit.c_str()); } // Build CoreCLR properties std::vector<const char*> property_keys = { "TRUSTED_PLATFORM_ASSEMBLIES", "NATIVE_DLL_SEARCH_DIRECTORIES", "PLATFORM_RESOURCE_ROOTS", "AppDomainCompatSwitch", // Workaround: mscorlib does not resolve symlinks for AppContext.BaseDirectory dotnet/coreclr/issues/2128 "APP_CONTEXT_BASE_DIRECTORY", "APP_CONTEXT_DEPS_FILES", "FX_DEPS_FILE" }; // Note: these variables' lifetime should be longer than coreclr_initialize. std::vector<char> tpa_paths_cstr, app_base_cstr, native_dirs_cstr, resources_dirs_cstr, fx_deps, deps, clrjit_path_cstr; pal::pal_clrstring(probe_paths.tpa, &tpa_paths_cstr); pal::pal_clrstring(args.app_dir, &app_base_cstr); pal::pal_clrstring(probe_paths.native, &native_dirs_cstr); pal::pal_clrstring(probe_paths.resources, &resources_dirs_cstr); pal::pal_clrstring(resolver.get_fx_deps_file(), &fx_deps); pal::pal_clrstring(resolver.get_deps_file() + _X(";") + resolver.get_fx_deps_file(), &deps); std::vector<const char*> property_values = { // TRUSTED_PLATFORM_ASSEMBLIES tpa_paths_cstr.data(), // NATIVE_DLL_SEARCH_DIRECTORIES native_dirs_cstr.data(), // PLATFORM_RESOURCE_ROOTS resources_dirs_cstr.data(), // AppDomainCompatSwitch "UseLatestBehaviorWhenTFMNotSpecified", // APP_CONTEXT_BASE_DIRECTORY app_base_cstr.data(), // APP_CONTEXT_DEPS_FILES, deps.data(), // FX_DEPS_FILE fx_deps.data() }; if (!clrjit_path.empty()) { pal::pal_clrstring(clrjit_path, &clrjit_path_cstr); property_keys.push_back("JIT_PATH"); property_values.push_back(clrjit_path_cstr.data()); } bool set_app_paths = false; // Runtime options config properties. for (int i = 0; i < g_init.cfg_keys.size(); ++i) { // Provide opt-in compatible behavior by using the switch to set APP_PATHS if (pal::cstrcasecmp(g_init.cfg_keys[i].data(), "Microsoft.NETCore.DotNetHostPolicy.SetAppPaths") == 0) { set_app_paths = (pal::cstrcasecmp(g_init.cfg_values[i].data(), "true") == 0); } property_keys.push_back(g_init.cfg_keys[i].data()); property_values.push_back(g_init.cfg_values[i].data()); } // App paths and App NI paths if (set_app_paths) { property_keys.push_back("APP_PATHS"); property_keys.push_back("APP_NI_PATHS"); property_values.push_back(app_base_cstr.data()); property_values.push_back(app_base_cstr.data()); } size_t property_size = property_keys.size(); assert(property_keys.size() == property_values.size()); // Add API sets to the process DLL search pal::setup_api_sets(resolver.get_api_sets()); // Bind CoreCLR pal::string_t clr_dir = get_directory(clr_path); trace::verbose(_X("CoreCLR path = '%s', CoreCLR dir = '%s'"), clr_path.c_str(), clr_dir.c_str()); if (!coreclr::bind(clr_dir)) { trace::error(_X("Failed to bind to CoreCLR at '%s'"), clr_path.c_str()); return StatusCode::CoreClrBindFailure; } // Verbose logging if (trace::is_enabled()) { for (size_t i = 0; i < property_size; ++i) { pal::string_t key, val; pal::clr_palstring(property_keys[i], &key); pal::clr_palstring(property_values[i], &val); trace::verbose(_X("Property %s = %s"), key.c_str(), val.c_str()); } } std::vector<char> own_path; pal::pal_clrstring(args.own_path, &own_path); // Initialize CoreCLR coreclr::host_handle_t host_handle; coreclr::domain_id_t domain_id; auto hr = coreclr::initialize( own_path.data(), "clrhost", property_keys.data(), property_values.data(), property_size, &host_handle, &domain_id); if (!SUCCEEDED(hr)) { trace::error(_X("Failed to initialize CoreCLR, HRESULT: 0x%X"), hr); return StatusCode::CoreClrInitFailure; } // Initialize clr strings for arguments std::vector<std::vector<char>> argv_strs(args.app_argc); std::vector<const char*> argv(args.app_argc); for (int i = 0; i < args.app_argc; i++) { pal::pal_clrstring(args.app_argv[i], &argv_strs[i]); argv[i] = argv_strs[i].data(); } if (trace::is_enabled()) { pal::string_t arg_str; for (int i = 0; i < argv.size(); i++) { pal::string_t cur; pal::clr_palstring(argv[i], &cur); arg_str.append(cur); arg_str.append(_X(",")); } trace::info(_X("Launch host: %s, app: %s, argc: %d, args: %s"), args.own_path.c_str(), args.managed_application.c_str(), args.app_argc, arg_str.c_str()); } std::vector<char> managed_app; pal::pal_clrstring(args.managed_application, &managed_app); // Leave breadcrumbs for servicing. breadcrumb_writer_t writer(&breadcrumbs); writer.begin_write(); // Previous hostpolicy trace messages must be printed before executing assembly trace::flush(); // Execute the application unsigned int exit_code = 1; hr = coreclr::execute_assembly( host_handle, domain_id, argv.size(), argv.data(), managed_app.data(), &exit_code); if (!SUCCEEDED(hr)) { trace::error(_X("Failed to execute managed app, HRESULT: 0x%X"), hr); return StatusCode::CoreClrExeFailure; } // Shut down the CoreCLR hr = coreclr::shutdown(host_handle, domain_id); if (!SUCCEEDED(hr)) { trace::warning(_X("Failed to shut down CoreCLR, HRESULT: 0x%X"), hr); } coreclr::unload(); // Finish breadcrumb writing writer.end_write(); return exit_code; }