diff --git a/build_projects/dotnet-cli-build/CompileTargets.cs b/build_projects/dotnet-cli-build/CompileTargets.cs index 43c11c707..85f2af5f9 100644 --- a/build_projects/dotnet-cli-build/CompileTargets.cs +++ b/build_projects/dotnet-cli-build/CompileTargets.cs @@ -396,7 +396,8 @@ namespace Microsoft.DotNet.Cli.Build File.Copy(Path.Combine(Dirs.CorehostLocked, $"{Constants.DynamicLibPrefix}hostfxr{Constants.DynamicLibSuffix}"), Path.Combine(outputDir, $"{Constants.DynamicLibPrefix}hostfxr{Constants.DynamicLibSuffix}"), overwrite: true); File.Copy(Path.Combine(Dirs.CorehostLatest, $"{Constants.DynamicLibPrefix}hostpolicy{Constants.DynamicLibSuffix}"), Path.Combine(outputDir, $"{Constants.DynamicLibPrefix}hostpolicy{Constants.DynamicLibSuffix}"), overwrite: true); - var binaryToCorehostifyOutDir = Path.Combine(outputDir, "runtimes", "any", "native"); + var binaryToCorehostifyRelDir = Path.Combine("runtimes", "any", "native"); + var binaryToCorehostifyOutDir = Path.Combine(outputDir, binaryToCorehostifyRelDir); // Corehostify binaries foreach (var binaryToCorehostify in BinariesForCoreHost) { @@ -407,7 +408,13 @@ namespace Microsoft.DotNet.Cli.Build File.Delete(Path.Combine(binaryToCorehostifyOutDir, $"{binaryToCorehostify}.exe")); File.Copy(compilersDeps, Path.Combine(outputDir, binaryToCorehostify + ".deps.json")); File.Copy(compilersRuntimeConfig, Path.Combine(outputDir, binaryToCorehostify + ".runtimeconfig.json")); - ChangeEntryPointLibraryName(Path.Combine(outputDir, binaryToCorehostify + ".deps.json"), binaryToCorehostify); + var binaryToCoreHostifyDeps = Path.Combine(outputDir, binaryToCorehostify + ".deps.json"); + ChangeEntryPointLibraryName(binaryToCoreHostifyDeps, binaryToCorehostify); + foreach (var binaryToRemove in new string[] { "csc", "vbc" }) + { + var assetPath = Path.Combine(binaryToCorehostifyRelDir, $"{binaryToRemove}.exe").Replace(Path.DirectorySeparatorChar, '/'); + RemoveAssetFromDepsPackages(binaryToCoreHostifyDeps, "runtimeTargets", assetPath); + } } catch (Exception ex) { @@ -430,6 +437,40 @@ namespace Microsoft.DotNet.Cli.Build return c.Success(); } + private static void RemoveAssetFromDepsPackages(string depsFile, string sectionName, string assetPath) + { + JToken deps; + using (var file = File.OpenText(depsFile)) + using (JsonTextReader reader = new JsonTextReader(file)) + { + deps = JObject.ReadFrom(reader); + } + + foreach (JProperty target in deps["targets"]) + { + foreach (JProperty pv in target.Value.Children()) + { + var section = pv.Value[sectionName]; + if (section != null) + { + foreach (JProperty relPath in section) + { + if (assetPath.Equals(relPath.Name)) + { + relPath.Remove(); + break; + } + } + } + } + } + using (var file = File.CreateText(depsFile)) + using (var writer = new JsonTextWriter(file) { Formatting = Formatting.Indented }) + { + deps.WriteTo(writer); + } + } + private static void ChangeEntryPointLibraryName(string depsFile, string newName) { JToken deps; diff --git a/build_projects/dotnet-cli-build/build.ps1 b/build_projects/dotnet-cli-build/build.ps1 index 7d6bace1c..8c6d2bcfc 100644 --- a/build_projects/dotnet-cli-build/build.ps1 +++ b/build_projects/dotnet-cli-build/build.ps1 @@ -56,7 +56,7 @@ if (!(Test-Path $env:DOTNET_INSTALL_DIR)) # Install a stage 0 Write-Host "Installing .NET Core CLI Stage 0 from branchinfo channel" -& "$RepoRoot\scripts\obtain\dotnet-install.ps1" -Channel $env:CHANNEL -Architecture $Architecture -Verbose -Version 1.0.0-preview2-002818 +& "$RepoRoot\scripts\obtain\dotnet-install.ps1" -Channel $env:CHANNEL -Architecture $Architecture -Verbose if($LASTEXITCODE -ne 0) { throw "Failed to install stage0" } # Put the stage0 on the path diff --git a/build_projects/dotnet-cli-build/build.sh b/build_projects/dotnet-cli-build/build.sh index 4ac49075b..1ef8f7ca1 100755 --- a/build_projects/dotnet-cli-build/build.sh +++ b/build_projects/dotnet-cli-build/build.sh @@ -85,7 +85,7 @@ done < "$REPOROOT/branchinfo.txt" [ -z "$DOTNET_INSTALL_DIR" ] && export DOTNET_INSTALL_DIR=$REPOROOT/.dotnet_stage0/$(uname) [ -d "$DOTNET_INSTALL_DIR" ] || mkdir -p $DOTNET_INSTALL_DIR -$REPOROOT/scripts/obtain/dotnet-install.sh --channel $CHANNEL --verbose --version 1.0.0-preview2-002818 +$REPOROOT/scripts/obtain/dotnet-install.sh --channel $CHANNEL --verbose # Put stage 0 on the PATH (for this shell only) PATH="$DOTNET_INSTALL_DIR:$PATH" diff --git a/build_projects/dotnet-host-build/build.ps1 b/build_projects/dotnet-host-build/build.ps1 index 1fb83650e..4e6ae8aa6 100644 --- a/build_projects/dotnet-host-build/build.ps1 +++ b/build_projects/dotnet-host-build/build.ps1 @@ -56,7 +56,7 @@ if (!(Test-Path $env:DOTNET_INSTALL_DIR)) # Install a stage 0 Write-Host "Installing .NET Core CLI Stage 0 from branchinfo channel" -& "$RepoRoot\scripts\obtain\dotnet-install.ps1" -Channel $env:CHANNEL -Architecture $Architecture -Verbose -Version 1.0.0-preview2-002818 +& "$RepoRoot\scripts\obtain\dotnet-install.ps1" -Channel $env:CHANNEL -Architecture $Architecture -Verbose if($LASTEXITCODE -ne 0) { throw "Failed to install stage0" } # Put the stage0 on the path diff --git a/build_projects/dotnet-host-build/build.sh b/build_projects/dotnet-host-build/build.sh index 327b0a44c..f214f6c27 100755 --- a/build_projects/dotnet-host-build/build.sh +++ b/build_projects/dotnet-host-build/build.sh @@ -85,7 +85,7 @@ done < "$REPOROOT/branchinfo.txt" [ -z "$DOTNET_INSTALL_DIR" ] && export DOTNET_INSTALL_DIR=$REPOROOT/.dotnet_stage0/$(uname) [ -d "$DOTNET_INSTALL_DIR" ] || mkdir -p $DOTNET_INSTALL_DIR -$REPOROOT/scripts/obtain/dotnet-install.sh --channel $CHANNEL --verbose --version 1.0.0-preview2-002818 +$REPOROOT/scripts/obtain/dotnet-install.sh --channel $CHANNEL --verbose # Put stage 0 on the PATH (for this shell only) PATH="$DOTNET_INSTALL_DIR:$PATH" diff --git a/src/corehost/cli/deps_format.cpp b/src/corehost/cli/deps_format.cpp index 93b51438f..68e462c69 100644 --- a/src/corehost/cli/deps_format.cpp +++ b/src/corehost/cli/deps_format.cpp @@ -349,8 +349,10 @@ bool deps_json_t::has_package(const pal::string_t& name, const pal::string_t& ve // bool deps_json_t::load(bool portable, const pal::string_t& deps_path, const rid_fallback_graph_t& rid_fallback_graph) { + m_file_exists = pal::file_exists(deps_path); + // If file doesn't exist, then assume parsed. - if (!pal::file_exists(deps_path)) + if (!m_file_exists) { trace::verbose(_X("Could not locate the dependencies manifest file [%s]. Some libraries may fail to resolve."), deps_path.c_str()); return true; diff --git a/src/corehost/cli/deps_format.h b/src/corehost/cli/deps_format.h index 8ac273b46..f577ef33c 100644 --- a/src/corehost/cli/deps_format.h +++ b/src/corehost/cli/deps_format.h @@ -28,6 +28,7 @@ class deps_json_t public: deps_json_t() : m_valid(false) + , m_file_exists(false) , m_coreclr_index(-1) , m_hostpolicy_index(-1) { @@ -62,6 +63,11 @@ public: return m_hostpolicy_index >= 0; } + bool exists() + { + return m_file_exists; + } + const deps_entry_t& get_coreclr_entry() { assert(has_coreclr_entry()); @@ -109,6 +115,7 @@ private: rid_fallback_graph_t m_rid_fallback_graph; int m_coreclr_index; int m_hostpolicy_index; + bool m_file_exists; bool m_valid; }; diff --git a/src/corehost/cli/deps_resolver.cpp b/src/corehost/cli/deps_resolver.cpp index 5a29940ae..99ef5bbe0 100644 --- a/src/corehost/cli/deps_resolver.cpp +++ b/src/corehost/cli/deps_resolver.cpp @@ -330,89 +330,95 @@ bool deps_resolver_t::probe_entry_in_configs(const deps_entry_t& entry, pal::str return false; } -// ----------------------------------------------------------------------------- -// Resolve coreclr directory from the deps file. -// -// Description: -// Look for CoreCLR from the dependency list in the package cache and then -// the packages directory. -// -pal::string_t deps_resolver_t::resolve_coreclr_dir() +/** + * Probe helper for a deps entry. Lookup all probe configurations and then + * lookup in the directory where the deps file is present. For app dirs, + * 1. RID specific entries are present in the package relative structure. + * 2. Non-RID entries are present in the directory path. + */ +bool deps_resolver_t::probe_deps_entry(const deps_entry_t& entry, const pal::string_t& deps_dir, pal::string_t* candidate) { - trace::verbose(_X("--- Resolving CoreCLR directory ---")); - - auto process_coreclr = [&] - (bool is_portable, const pal::string_t& deps_dir, deps_json_t* deps) -> pal::string_t + if (probe_entry_in_configs(entry, candidate)) { - pal::string_t candidate; - - if (deps->has_coreclr_entry()) - { - const deps_entry_t& entry = deps->get_coreclr_entry(); - if (probe_entry_in_configs(entry, &candidate)) - { - return get_directory(candidate); - } - else if (entry.is_rid_specific && entry.to_rel_path(deps_dir, &candidate)) - { - return get_directory(candidate); - } - } - else - { - trace::verbose(_X("Deps has no CoreCLR entry.")); - } - - // App/FX main dir or standalone app dir. - trace::verbose(_X("Probing for CoreCLR in deps directory=[%s]"), deps_dir.c_str()); - if (coreclr_exists_in_dir(deps_dir)) - { - return deps_dir; - } - - return pal::string_t(); - }; - - trace::info(_X("-- Starting CoreCLR Probe from app deps.json")); - pal::string_t clr_dir = process_coreclr(m_portable, m_app_dir, m_deps.get()); - if (clr_dir.empty() && m_portable) - { - trace::info(_X("-- Starting CoreCLR Probe from FX deps.json")); - clr_dir = process_coreclr(false, m_fx_dir, m_fx_deps.get()); + return true; } - if (!clr_dir.empty()) + if (entry.is_rid_specific && entry.to_rel_path(deps_dir, candidate)) { - return clr_dir; + return true; } - - // Use platform-specific search algorithm - pal::string_t install_dir; - if (pal::find_coreclr(&install_dir)) + if (!entry.is_rid_specific && entry.to_dir_path(deps_dir, candidate)) { - return install_dir; + return true; } - - return pal::string_t(); + return false; } -void deps_resolver_t::resolve_tpa_list( - const pal::string_t& clr_dir, +/** + * Helper for obtaining CoreCLR from a given deps file and the deps file's directory. + */ +bool deps_resolver_t::get_coreclr_dir_from_deps(const pal::string_t& deps_dir, deps_json_t* deps, pal::string_t* candidate) +{ + if (!deps->has_coreclr_entry()) + { + return false; + } + + pal::string_t coreclr; + if (probe_deps_entry(deps->get_coreclr_entry(), deps_dir, &coreclr)) + { + *candidate = get_directory(coreclr); + return true; + } + + return false; +} + + +/** + * Probe for coreclr relative to the app and then from the framework root. + * If deps does not exist, then just use the app base. + */ +bool deps_resolver_t::resolve_coreclr_dir(pal::string_t* clr_dir) +{ + trace::info(_X("-- Starting CoreCLR Probe from app deps.json")); + + if (get_coreclr_dir_from_deps(m_app_dir, m_deps.get(), clr_dir)) + { + return true; + } + + if (m_portable) + { + trace::info(_X("-- Starting CoreCLR Probe from FX deps.json")); + if (get_coreclr_dir_from_deps(m_fx_dir, m_fx_deps.get(), clr_dir)) + { + return true; + } + } + + if (!m_deps->exists()) + { + if (coreclr_exists_in_dir(m_app_dir)) + { + *clr_dir = m_app_dir; + return true; + } + } + + return false; +} + +/** + * Resovle the TPA assembly locations + */ +bool deps_resolver_t::resolve_tpa_list( pal::string_t* output, std::unordered_set* breadcrumb) { const std::vector empty(0); - - // Obtain the local assemblies in the app dir. - get_dir_assemblies(m_app_dir, _X("local"), &m_local_assemblies); - if (m_portable) - { - // For portable also obtain FX dir assemblies. - get_dir_assemblies(m_fx_dir, _X("fx"), &m_fx_assemblies); - } - std::unordered_set items; - auto process_entry = [&](const pal::string_t& deps_dir, deps_json_t* deps, const dir_assemblies_t& dir_assemblies, const deps_entry_t& entry) + auto process_entry = [&](const pal::string_t& deps_dir, deps_json_t* deps, const deps_entry_t& entry) -> bool { if (entry.is_serviceable) { @@ -421,81 +427,81 @@ void deps_resolver_t::resolve_tpa_list( } if (items.count(entry.asset_name)) { - return; + return true; } + // Ignore placeholders + if (ends_with(entry.relative_path, _X("/_._"), false)) + { + return true; + } + pal::string_t candidate; trace::info(_X("Processing TPA for deps entry [%s, %s, %s]"), entry.library_name.c_str(), entry.library_version.c_str(), entry.relative_path.c_str()); - // Try to probe from the shared locations. - if (probe_entry_in_configs(entry, &candidate)) + if (probe_deps_entry(entry, deps_dir, &candidate)) { add_tpa_asset(entry.asset_name, candidate, &items, output); } - // The rid asset should be picked up from app relative subpath. - else if (entry.is_rid_specific && entry.to_rel_path(deps_dir, &candidate)) + // Leave the mscorlib error handling to the CoreCLR -- this is because apps might choose to use mscorlib.ni.dll + // and delete mscorlib.dll and vice-versa. + else if (entry.asset_name != _X("mscorlib")) { - add_tpa_asset(entry.asset_name, candidate, &items, output); - } - // The rid-less asset should be picked up from the app base. - else if (dir_assemblies.count(entry.asset_name)) - { - add_tpa_asset(entry.asset_name, dir_assemblies.find(entry.asset_name)->second, &items, output); - } - else - { - // FIXME: Consider this error as a fail fast? - trace::warning(_X("Could not resolve path to assembly: [%s, %s, %s]"), entry.library_name.c_str(), entry.library_version.c_str(), entry.relative_path.c_str()); + trace::error(_X("Error: assembly specified in the dependencies manifest was not found -- package: '%s', version: '%s', path: '%s'"), + entry.library_name.c_str(), entry.library_version.c_str(), entry.relative_path.c_str()); + return false; } + + return true; }; - + + // First add managed assembly to the TPA. + // TODO: Remove: the deps should contain the managed DLL. + // Workaround for: csc.deps.json doesn't have the csc.dll + pal::string_t managed_app_asset = get_filename_without_ext(m_managed_app); + add_tpa_asset(managed_app_asset, m_managed_app, &items, output); + const auto& deps_entries = m_deps->get_entries(deps_entry_t::asset_types::runtime); - std::for_each(deps_entries.begin(), deps_entries.end(), [&](const deps_entry_t& entry) { - process_entry(m_app_dir, m_deps.get(), m_local_assemblies, entry); - }); + for (const auto& entry : deps_entries) + { + if (!process_entry(m_app_dir, m_deps.get(), entry)) + { + return false; + } + } // Finally, if the deps file wasn't present or has missing entries, then // add the app local assemblies to the TPA. - for (const auto& kv : m_local_assemblies) + if (!m_deps->exists()) { - add_tpa_asset(kv.first, kv.second, &items, output); + dir_assemblies_t local_assemblies; + + // Obtain the local assemblies in the app dir. + get_dir_assemblies(m_app_dir, _X("local"), &local_assemblies); + for (const auto& kv : local_assemblies) + { + add_tpa_asset(kv.first, kv.second, &items, output); + } } + // Probe FX deps entries after app assemblies are added. const auto& fx_entries = m_portable ? m_fx_deps->get_entries(deps_entry_t::asset_types::runtime) : empty; - std::for_each(fx_entries.begin(), fx_entries.end(), [&](const deps_entry_t& entry) { - process_entry(m_fx_dir, m_fx_deps.get(), m_fx_assemblies, entry); - }); - - for (const auto& kv : m_fx_assemblies) + for (const auto& entry : fx_entries) { - add_tpa_asset(kv.first, kv.second, &items, output); + if (!process_entry(m_fx_dir, m_fx_deps.get(), entry)) + { + return false; + } } + + return true; } -// ----------------------------------------------------------------------------- -// Resolve the directories order for resources/native lookup -// -// Description: -// This general purpose function specifies priority order of directory lookup -// for both native images and resources specific resource images. Lookup for -// resources assemblies is done by looking up two levels above from the file -// path. Lookup for native images is done by looking up one level from the -// file path. -// -// Parameters: -// asset_type - The type of the asset that needs lookup, currently -// supports "resources" and "native" -// app_dir - The application local directory -// package_dir - The directory path to where packages are restored -// package_cache_dir - The directory path to secondary cache for packages -// clr_dir - The directory where the host loads the CLR -// -// Returns: -// output - Pointer to a string that will hold the resolved lookup dirs -// -void deps_resolver_t::resolve_probe_dirs( +/** + * Resolve native and culture assembly directories based on "asset_type" parameter. + */ +bool deps_resolver_t::resolve_probe_dirs( deps_entry_t::asset_types asset_type, - const pal::string_t& clr_dir, pal::string_t* output, std::unordered_set* breadcrumb) { @@ -511,10 +517,16 @@ void deps_resolver_t::resolve_probe_dirs( std::function native = [] (const pal::string_t& str) { return get_directory(str); }; + // Action for post processing the resolved path std::function& action = is_resources ? resources : native; + + // Set for de-duplication std::unordered_set items; + pal::string_t core_servicing = m_core_servicing; pal::realpath(&core_servicing); + + // Filter out non-serviced assets so the paths can be added after servicing paths. pal::string_t non_serviced; std::vector empty(0); @@ -523,85 +535,80 @@ void deps_resolver_t::resolve_probe_dirs( pal::string_t candidate; - bool track_api_sets = true; - auto add_package_cache_entry = [&](const deps_entry_t& entry) + auto add_package_cache_entry = [&](const deps_entry_t& entry, const pal::string_t& deps_dir) -> bool { if (entry.is_serviceable) { breadcrumb->insert(entry.library_name + _X(",") + entry.library_version); breadcrumb->insert(entry.library_name); } - - if (probe_entry_in_configs(entry, &candidate)) + if (items.count(entry.asset_name)) { - // For standalone apps, on win7, coreclr needs ApiSets which has to be in the DLL search path. - const pal::string_t result_dir = action(candidate); - - if (track_api_sets && pal::need_api_sets() && - ends_with(entry.library_name, _X("Microsoft.NETCore.Windows.ApiSets"), false)) - { - // For standalone and portable apps, get the ApiSets DLL directory, - // as they could come from servicing or other probe paths. - // Note: in portable apps, the API set would come from FX deps - // which is actually a standalone deps (rid specific API set). - // If the portable app relied on its version of API sets, then - // the rid selection fallback would have already been performed - // by the host (deps_format.cpp) - m_api_set_paths.insert(result_dir); - } - - add_unique_path(asset_type, result_dir, &items, output, &non_serviced, core_servicing); + return true; } + // Ignore placeholders + if (ends_with(entry.relative_path, _X("/_._"), false)) + { + return true; + } + + trace::verbose(_X("Processing native/culture for deps entry [%s, %s, %s]"), + entry.library_name.c_str(), entry.library_version.c_str(), entry.relative_path.c_str()); + + if (probe_deps_entry(entry, deps_dir, &candidate)) + { + add_unique_path(asset_type, action(candidate), &items, output, &non_serviced, core_servicing); + } + else + { + // For standalone apps, dotnet.exe will be renamed. Do not use the full package name + // because of rid-fallback could happen (ex: CentOS falling back to RHEL) + if (ends_with(entry.library_name, _X(".Microsoft.NETCore.DotNetHost"), false) && entry.asset_name == _X("dotnet")) + { + trace::warning(_X("Warning: assembly specified in the dependencies manifest was not found -- package: '%s', version: '%s', path: '%s'"), + entry.library_name.c_str(), entry.library_version.c_str(), entry.relative_path.c_str()); + return true; + } + trace::error(_X("Error: assembly specified in the dependencies manifest was not found -- package: '%s', version: '%s', path: '%s'"), + entry.library_name.c_str(), entry.library_version.c_str(), entry.relative_path.c_str()); + return false; + } + + if (m_api_set_paths.empty() && pal::need_api_sets() && + ends_with(entry.library_name, _X("Microsoft.NETCore.Windows.ApiSets"), false)) + { + m_api_set_paths.insert(action(candidate)); + } + + return true; }; - std::for_each(entries.begin(), entries.end(), add_package_cache_entry); - track_api_sets = m_api_set_paths.empty(); - std::for_each(fx_entries.begin(), fx_entries.end(), add_package_cache_entry); - track_api_sets = m_api_set_paths.empty(); - // For portable rid specific assets, the app relative directory must be used. - if (m_portable) + for (const auto& entry : entries) { - std::for_each(entries.begin(), entries.end(), [&](const deps_entry_t& entry) + if (!add_package_cache_entry(entry, m_app_dir)) { - if (entry.is_rid_specific && entry.asset_type == asset_type && entry.to_rel_path(m_app_dir, &candidate)) - { - add_unique_path(asset_type, action(candidate), &items, output, &non_serviced, core_servicing); - } - - // App called out an explicit API set dependency. - if (track_api_sets && entry.is_rid_specific && pal::need_api_sets() && - ends_with(entry.library_name, _X("Microsoft.NETCore.Windows.ApiSets"), false)) - { - m_api_set_paths.insert(action(candidate)); - } - }); - } - - track_api_sets = m_api_set_paths.empty(); - - // App local path - add_unique_path(asset_type, m_app_dir, &items, output, &non_serviced, core_servicing); - - // If API sets is not found (i.e., empty) in the probe paths above: - // 1. For standalone app, do nothing as all are sxs. - // 2. For portable app, add FX dir. - - // FX path if present - if (!m_fx_dir.empty()) - { - // For portable apps, if we didn't find api sets in probe paths - // add the FX directory. - if (track_api_sets && pal::need_api_sets()) - { - m_api_set_paths.insert(m_fx_dir); + return false; } - add_unique_path(asset_type, m_fx_dir, &items, output, &non_serviced, core_servicing); } - // CLR path - add_unique_path(asset_type, clr_dir, &items, output, &non_serviced, core_servicing); + // If the deps file is missing add known locations. + if (!m_deps->exists()) + { + // App local path + add_unique_path(asset_type, m_app_dir, &items, output, &non_serviced, core_servicing); + } + + for (const auto& entry : fx_entries) + { + if (!add_package_cache_entry(entry, m_fx_dir)) + { + return false; + } + } output->append(non_serviced); + + return true; } @@ -617,10 +624,19 @@ void deps_resolver_t::resolve_probe_dirs( // resolved path ordering. // // -bool deps_resolver_t::resolve_probe_paths(const pal::string_t& clr_dir, probe_paths_t* probe_paths, std::unordered_set* breadcrumb) +bool deps_resolver_t::resolve_probe_paths(probe_paths_t* probe_paths, std::unordered_set* breadcrumb) { - resolve_tpa_list(clr_dir, &probe_paths->tpa, breadcrumb); - resolve_probe_dirs(deps_entry_t::asset_types::native, clr_dir, &probe_paths->native, breadcrumb); - resolve_probe_dirs(deps_entry_t::asset_types::resources, clr_dir, &probe_paths->resources, breadcrumb); + if (!resolve_tpa_list(&probe_paths->tpa, breadcrumb)) + { + return false; + } + if (!resolve_probe_dirs(deps_entry_t::asset_types::native, &probe_paths->native, breadcrumb)) + { + return false; + } + if (!resolve_probe_dirs(deps_entry_t::asset_types::resources, &probe_paths->resources, breadcrumb)) + { + return false; + } return true; } diff --git a/src/corehost/cli/deps_resolver.h b/src/corehost/cli/deps_resolver.h index 05edf945f..3a602ccd3 100644 --- a/src/corehost/cli/deps_resolver.h +++ b/src/corehost/cli/deps_resolver.h @@ -27,6 +27,7 @@ public: deps_resolver_t(const hostpolicy_init_t& init, const arguments_t& args) : m_fx_dir(init.fx_dir) , m_app_dir(args.app_dir) + , m_managed_app(args.managed_application) , m_coreclr_index(-1) , m_portable(init.is_portable) , m_deps(nullptr) @@ -58,6 +59,11 @@ public: errors->assign(_X("An error occurred while parsing ") + m_deps_file); return false; } + if (m_portable && !m_fx_deps->exists()) + { + errors->assign(_X("A fatal error was encountered, missing dependencies manifest at: ") + m_fx_deps_file); + return false; + } if (m_portable && !m_fx_deps->is_valid()) { errors->assign(_X("An error occurred while parsing ") + m_fx_deps_file); @@ -73,11 +79,12 @@ public: void setup_additional_probes(const std::vector& probe_paths); bool resolve_probe_paths( - const pal::string_t& clr_dir, probe_paths_t* probe_paths, std::unordered_set* breadcrumb); - pal::string_t resolve_coreclr_dir(); + bool get_coreclr_dir_from_deps(const pal::string_t& deps_dir, deps_json_t* deps, pal::string_t* candidate); + + bool resolve_coreclr_dir(pal::string_t* clr_dir); const pal::string_t& get_fx_deps_file() const { @@ -104,15 +111,13 @@ private: } // Resolve order for TPA lookup. - void resolve_tpa_list( - const pal::string_t& clr_dir, + bool resolve_tpa_list( pal::string_t* output, std::unordered_set* breadcrumb); // Resolve order for culture and native DLL lookup. - void resolve_probe_dirs( + bool resolve_probe_dirs( deps_entry_t::asset_types asset_type, - const pal::string_t& clr_dir, pal::string_t* output, std::unordered_set* breadcrumb); @@ -122,6 +127,12 @@ private: const pal::string_t& dir_name, std::unordered_map* dir_assemblies); + // Probe entry in probe configurations and deps dir. + bool probe_deps_entry( + const deps_entry_t& entry, + const pal::string_t& deps_dir, + pal::string_t* candidate); + // Probe entry in probe configurations. bool probe_entry_in_configs( const deps_entry_t& entry, @@ -143,14 +154,15 @@ private: // Map of simple name -> full path of local/fx assemblies populated // in priority order of their extensions. typedef std::unordered_map dir_assemblies_t; - dir_assemblies_t m_local_assemblies; - dir_assemblies_t m_fx_assemblies; std::unordered_map m_patch_roll_forward_cache; std::unordered_map m_prerelease_roll_forward_cache; pal::string_t m_package_cache; + // The managed application the dependencies are being resolved for. + pal::string_t m_managed_app; + // Servicing root, could be empty on platforms that don't support or when errors occur. pal::string_t m_core_servicing; diff --git a/src/corehost/cli/fxr/fx_muxer.cpp b/src/corehost/cli/fxr/fx_muxer.cpp index 73ba1724e..b59fb4f56 100644 --- a/src/corehost/cli/fxr/fx_muxer.cpp +++ b/src/corehost/cli/fxr/fx_muxer.cpp @@ -85,9 +85,9 @@ pal::string_t resolve_hostpolicy_version_from_deps(const pal::string_t& deps_jso const auto& json = root.as_object(); const auto& libraries = json.at(_X("libraries")).as_object(); - // Walk through the libraries section and check any library that starts with: - // "runtime.win7-x64.Microsoft.NETCore.DotNetHostPolicy/" followed by version. - pal::string_t prefix = _STRINGIFY(HOST_POLICY_PKG_NAME) + pal::string_t(_X("/")); + // Look up the root package instead of the "runtime" package because we can't do a full rid resolution. + // i.e., look for "Microsoft.NETCore.DotNetHostPolicy/" followed by version. + pal::string_t prefix = _X("Microsoft.NETCore.DotNetHostPolicy/"); for (const auto& library : libraries) { if (starts_with(library.first, prefix, false)) diff --git a/src/corehost/cli/hostpolicy.cpp b/src/corehost/cli/hostpolicy.cpp index 93ad5c305..c01ebdbf2 100644 --- a/src/corehost/cli/hostpolicy.cpp +++ b/src/corehost/cli/hostpolicy.cpp @@ -27,8 +27,8 @@ int run(const arguments_t& args) return StatusCode::ResolverInitFailure; } - pal::string_t clr_path = resolver.resolve_coreclr_dir(); - if (clr_path.empty() || !pal::realpath(&clr_path)) + pal::string_t clr_path; + if (!resolver.resolve_coreclr_dir(&clr_path) || 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; @@ -49,7 +49,7 @@ int run(const arguments_t& args) breadcrumbs.insert(policy_name + _X(",") + policy_version); probe_paths_t probe_paths; - if (!resolver.resolve_probe_paths(clr_path, &probe_paths, &breadcrumbs)) + if (!resolver.resolve_probe_paths(&probe_paths, &breadcrumbs)) { return StatusCode::ResolverResolveFailure; }