Add ApiSets to PATH
-- So CoreCLR load of PInvoke can actually see these dependencies. Add DllDirectory so CoreCLR itself can be loaded.
This commit is contained in:
parent
722cd3b681
commit
bcef2372a2
5 changed files with 90 additions and 5 deletions
|
@ -22,7 +22,7 @@ namespace
|
|||
void add_tpa_asset(
|
||||
const pal::string_t& asset_name,
|
||||
const pal::string_t& asset_path,
|
||||
std::set<pal::string_t>* items,
|
||||
std::unordered_set<pal::string_t>* items,
|
||||
pal::string_t* output)
|
||||
{
|
||||
if (items->count(asset_name))
|
||||
|
@ -48,7 +48,7 @@ void add_tpa_asset(
|
|||
void add_unique_path(
|
||||
deps_entry_t::asset_types asset_type,
|
||||
const pal::string_t& path,
|
||||
std::set<pal::string_t>* existing,
|
||||
std::unordered_set<pal::string_t>* existing,
|
||||
pal::string_t* output)
|
||||
{
|
||||
// Resolve sym links.
|
||||
|
@ -377,7 +377,7 @@ void deps_resolver_t::resolve_tpa_list(
|
|||
get_dir_assemblies(m_fx_dir, _X("fx"), &m_fx_assemblies);
|
||||
}
|
||||
|
||||
std::set<pal::string_t> items;
|
||||
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)
|
||||
{
|
||||
|
@ -474,7 +474,7 @@ void deps_resolver_t::resolve_probe_dirs(
|
|||
return get_directory(str);
|
||||
};
|
||||
std::function<pal::string_t(const pal::string_t&)>& action = is_resources ? resources : native;
|
||||
std::set<pal::string_t> items;
|
||||
std::unordered_set<pal::string_t> items;
|
||||
|
||||
std::vector<deps_entry_t> empty(0);
|
||||
const auto& entries = m_deps->get_entries(asset_type);
|
||||
|
@ -482,15 +482,34 @@ 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)
|
||||
{
|
||||
if (probe_entry_in_configs(entry, &candidate))
|
||||
{
|
||||
add_unique_path(asset_type, action(candidate), &items, output);
|
||||
// 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)
|
||||
|
@ -501,15 +520,34 @@ void deps_resolver_t::resolve_probe_dirs(
|
|||
{
|
||||
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);
|
||||
}
|
||||
|
||||
|
|
|
@ -76,6 +76,11 @@ public:
|
|||
{
|
||||
return m_deps_file;
|
||||
}
|
||||
|
||||
const std::unordered_set<pal::string_t>& get_api_sets() const
|
||||
{
|
||||
return m_api_set_paths;
|
||||
}
|
||||
private:
|
||||
|
||||
static pal::string_t get_fx_deps(const pal::string_t& fx_dir, const pal::string_t& fx_name)
|
||||
|
@ -129,6 +134,9 @@ private:
|
|||
|
||||
pal::string_t m_package_cache;
|
||||
|
||||
// Special entry for api-sets
|
||||
std::unordered_set<pal::string_t> m_api_set_paths;
|
||||
|
||||
// Special entry for coreclr in the deps entries
|
||||
int m_coreclr_index;
|
||||
|
||||
|
|
|
@ -96,6 +96,9 @@ int run(const corehost_init_t* init, const runtime_config_t& config, const argum
|
|||
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
|
||||
if (!coreclr::bind(clr_path))
|
||||
{
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include <cstdarg>
|
||||
#include <tuple>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <memory>
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
|
@ -99,6 +100,8 @@ namespace pal
|
|||
typedef FARPROC proc_t;
|
||||
|
||||
inline string_t exe_suffix() { return _X(".exe"); }
|
||||
inline bool need_api_sets() { return true; }
|
||||
void setup_api_sets(const std::unordered_set<pal::string_t>& api_sets);
|
||||
|
||||
pal::string_t to_string(int value);
|
||||
|
||||
|
@ -140,6 +143,8 @@ namespace pal
|
|||
typedef void* proc_t;
|
||||
|
||||
inline string_t exe_suffix() { return _X(""); }
|
||||
inline bool need_api_sets() { return false; }
|
||||
inline void setup_api_sets(const std::unordered_set<pal::string_t>& api_sets) { }
|
||||
|
||||
pal::string_t to_string(int value);
|
||||
|
||||
|
|
|
@ -54,6 +54,37 @@ bool pal::find_coreclr(pal::string_t* recv)
|
|||
return false;
|
||||
}
|
||||
|
||||
void pal::setup_api_sets(const std::unordered_set<pal::string_t>& api_sets)
|
||||
{
|
||||
if (api_sets.empty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
pal::string_t path;
|
||||
|
||||
(void) getenv(_X("PATH"), &path);
|
||||
|
||||
// We need this ugly hack, as the PInvoked DLL's static dependencies can come from
|
||||
// some other NATIVE_DLL_SEARCH_DIRECTORIES and not necessarily side by side. However,
|
||||
// CoreCLR.dll loads PInvoke DLLs with LOAD_WITH_ALTERED_SEARCH_PATH. Note that this
|
||||
// option cannot be combined with LOAD_LIBRARY_SEARCH_USER_DIRS, so the AddDllDirectory
|
||||
// doesn't help much in telling CoreCLR where to load the PInvoke DLLs from.
|
||||
// So we resort to modifying the PATH variable on our own hoping Windows loader will do the right thing.
|
||||
for (const auto& as : api_sets)
|
||||
{
|
||||
// AddDllDirectory is still needed for Standalone App's CoreCLR load.
|
||||
::AddDllDirectory(as.c_str());
|
||||
|
||||
// Path patch is needed for static dependencies of a PInvoked DLL load out of the nuget cache.
|
||||
path.push_back(PATH_SEPARATOR);
|
||||
path.append(as);
|
||||
}
|
||||
|
||||
trace::verbose(_X("Setting PATH=%s"), path.c_str());
|
||||
|
||||
::SetEnvironmentVariableW(_X("PATH"), path.c_str());
|
||||
}
|
||||
|
||||
bool pal::getcwd(pal::string_t* recv)
|
||||
{
|
||||
|
|
Loading…
Reference in a new issue