// ----------------------------------------------------------------------------- // 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() { auto process_coreclr = [&] (bool is_portable, const pal::string_t& deps_dir, deps_json_t* deps) -> pal::string_t { 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()); } if (!clr_dir.empty()) { return clr_dir; } // Use platform-specific search algorithm pal::string_t install_dir; if (pal::find_coreclr(&install_dir)) { return install_dir; } return pal::string_t(); }
/** * 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) { if (probe_entry_in_configs(entry, candidate)) { return true; } if (entry.is_rid_specific && entry.to_rel_path(deps_dir, candidate)) { return true; } if (!entry.is_rid_specific && entry.to_dir_path(deps_dir, candidate)) { return true; } return false; }
// ----------------------------------------------------------------------------- // 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( deps_entry_t::asset_types asset_type, const pal::string_t& clr_dir, pal::string_t* output) { bool is_resources = asset_type == deps_entry_t::asset_types::resources; assert(is_resources || asset_type == deps_entry_t::asset_types::native); // For resources assemblies, we need to provide the base directory of the resources path. // For example: .../Foo/en-US/Bar.dll, then, the resolved path is .../Foo std::function<pal::string_t(const pal::string_t&)> resources = [] (const pal::string_t& str) { return get_directory(get_directory(str)); }; // For native assemblies, obtain the directory path from the file path std::function<pal::string_t(const pal::string_t&)> native = [] (const pal::string_t& str) { return get_directory(str); }; std::function<pal::string_t(const pal::string_t&)>& action = is_resources ? resources : native; std::unordered_set<pal::string_t> items; std::vector<deps_entry_t> empty(0); const auto& entries = m_deps->get_entries(asset_type); const auto& fx_entries = m_portable ? m_fx_deps->get_entries(asset_type) : empty; pal::string_t candidate; bool track_api_sets = true; auto add_package_cache_entry = [&](const deps_entry_t& entry) { if (probe_entry_in_configs(entry, &candidate)) { // 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); } }; 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) { std::for_each(entries.begin(), entries.end(), [&](const deps_entry_t& entry) { 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); } // 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); // 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); } add_unique_path(asset_type, m_fx_dir, &items, output); } // CLR path add_unique_path(asset_type, clr_dir, &items, output); }
void deps_resolver_t::resolve_tpa_list( const pal::string_t& clr_dir, pal::string_t* output) { const std::vector<deps_entry_t> 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<pal::string_t> 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) { if (items.count(entry.asset_name)) { return; } 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)) { 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)) { 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::verbose(_X("Error: Could not resolve path to assembly: [%s, %s, %s]"), entry.library_name.c_str(), entry.library_version.c_str(), entry.relative_path.c_str()); } }; 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); }); // 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) { add_tpa_asset(kv.first, kv.second, &items, output); } 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) { add_tpa_asset(kv.first, kv.second, &items, output); } }