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:
Senthil 2016-04-04 18:22:51 -07:00
parent 722cd3b681
commit bcef2372a2
5 changed files with 90 additions and 5 deletions

View file

@ -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);
}

View file

@ -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;

View file

@ -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))
{

View file

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

View file

@ -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)
{