Exemplo n.º 1
0
// -----------------------------------------------------------------------------
// 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);
}
Exemplo n.º 2
0
/**
 *  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,
        pal::string_t* output,
        std::unordered_set<pal::string_t>* breadcrumb)
{
    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);
    };
    // Action for post processing the resolved path
    std::function<pal::string_t(const pal::string_t&)>& action = is_resources ? resources : native;

    // Set for de-duplication
    std::unordered_set<pal::string_t> 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<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;

    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 (items.count(entry.asset_name))
        {
            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))
        {
            init_known_entry_path(entry, candidate);
            add_unique_path(asset_type, action(candidate), &items, output, &non_serviced, core_servicing);
        }
        else
        {
            // For standalone apps, apphost.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")) ||
                (ends_with(entry.library_name, _X(".Microsoft.NETCore.DotNetAppHost"), false) && entry.asset_name == _X("apphost")))
            {
                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;
    };

    for (const auto& entry : entries)
    {
        if (!add_package_cache_entry(entry, m_app_dir))
        {
            return false;
        }
    }

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

        (void) library_exists_in_dir(m_app_dir, LIBCORECLR_NAME, &m_coreclr_path);

        (void) library_exists_in_dir(m_app_dir, LIBCLRJIT_NAME, &m_clrjit_path);
    }
    
    for (const auto& entry : fx_entries)
    {
        if (!add_package_cache_entry(entry, m_fx_dir))
        {
            return false;
        }
    }

    output->append(non_serviced);

    return true;
}
Exemplo n.º 3
0
/**
 *  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,
        pal::string_t* output,
        std::unordered_set<pal::string_t>* breadcrumb)
{
    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);
    };
    // Action for post processing the resolved path
    std::function<pal::string_t(const pal::string_t&)>& action = is_resources ? resources : native;

    // Set for de-duplication
    std::unordered_set<pal::string_t> items;

    pal::string_t core_servicing = m_core_servicing;
    pal::realpath(&core_servicing, true);

    // Filter out non-serviced assets so the paths can be added after servicing paths.
    pal::string_t non_serviced;

    std::vector<deps_entry_t> empty(0);

    pal::string_t candidate;

    auto add_package_cache_entry = [&](const deps_entry_t& entry, const pal::string_t& deps_dir, int fx_level) -> bool
    {
        if (breadcrumb != nullptr && entry.is_serviceable)
        {
            breadcrumb->insert(entry.library_name + _X(",") + entry.library_version);
            breadcrumb->insert(entry.library_name);
        }

        if (items.count(entry.asset.name))
        {
            return true;
        }

        // Ignore placeholders
        if (ends_with(entry.asset.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.asset.relative_path.c_str());

        if (probe_deps_entry(entry, deps_dir, fx_level, &candidate))
        {
            init_known_entry_path(entry, candidate);
            add_unique_path(asset_type, action(candidate), &items, output, &non_serviced, core_servicing);
        }
        else
        {
            // For self-contained apps do not use the full package name
            // because of rid-fallback could happen (ex: CentOS falling back to RHEL)
            if ((entry.asset.name == _X("apphost")) && ends_with(entry.library_name, _X(".Microsoft.NETCore.DotNetAppHost"), false))
            {
                return report_missing_assembly_in_manifest(entry, true);
            }

            return report_missing_assembly_in_manifest(entry);
        }

        return true;
    };

    // Add app entries
    const auto& entries = get_deps().get_entries(asset_type);
    for (const auto& entry : entries)
    {
        if (!add_package_cache_entry(entry, m_app_dir, 0))
        {
            return false;
        }
    }

    // If the deps file is missing add known locations.
    if (!get_deps().exists())
    {
        // App local path
        add_unique_path(asset_type, m_app_dir, &items, output, &non_serviced, core_servicing);

        (void) library_exists_in_dir(m_app_dir, LIBCORECLR_NAME, &m_coreclr_path);
        (void) library_exists_in_dir(m_app_dir, LIBCLRJIT_NAME, &m_clrjit_path);
    }

    // Handle any additional deps.json that were specified.
    for (const auto& additional_deps : m_additional_deps)
    {
        const auto additional_deps_entries = additional_deps->get_entries(asset_type);
        for (const auto entry : additional_deps_entries)
        {
            if (!add_package_cache_entry(entry, m_app_dir, 0))
            {
                return false;
            }
        }
    }

    // Add fx package locations to fx_dir
    for (int i = 1; i < m_fx_definitions.size(); ++i)
    {
        const auto& fx_entries = m_fx_definitions[i]->get_deps().get_entries(asset_type);

        for (const auto& entry : fx_entries)
        {
            if (!add_package_cache_entry(entry, m_fx_definitions[i]->get_dir(), i))
            {
                return false;
            }
        }
    }

    output->append(non_serviced);

    return true;
}