Load provider shared libraries relative to core runtime executable (#3884)

* Load provider DLL relative to core runtime executable
* Use LoadLibraryEx to fix dependent DLL loading
* Fix custom op DLL loading path issue.
This commit is contained in:
Ryan Hill 2020-05-09 20:49:15 -07:00 committed by GitHub
parent 3c24841569
commit 408f62dd57
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 35 additions and 5 deletions

View file

@ -504,7 +504,9 @@ struct ProviderHostImpl : ProviderHost {
struct ProviderLibrary {
ProviderLibrary(const char* filename) {
Env::Default().LoadDynamicLibrary(filename, &handle_);
std::string full_path = Env::Default().GetRuntimePath() + std::string(filename);
Env::Default().LoadDynamicLibrary(full_path, &handle_);
if (!handle_)
return;

View file

@ -206,6 +206,12 @@ class Env {
virtual common::Status UnloadDynamicLibrary(void* handle) const = 0;
// \brief Gets the file path of the onnx runtime code
//
// Used to help load other shared libraries that live in the same folder as the core code, for example
// The DNNL provider shared library. Without this path, the module won't be found on windows in all cases.
virtual std::string GetRuntimePath() const { return ""; }
// \brief Get a pointer to a symbol from a dynamic library.
//
// "handle" should be a pointer returned from a previous call to LoadDynamicLibrary.

View file

@ -35,6 +35,8 @@ limitations under the License.
#include "core/platform/path_lib.h" // for LoopDir()
EXTERN_C IMAGE_DOS_HEADER __ImageBase;
namespace onnxruntime {
namespace {
@ -428,9 +430,25 @@ class WindowsEnv : public Env {
return Status::OK();
}
// Return the path of the executable/shared library for the current running code. This is to make it
// possible to load other shared libraries installed next to our core runtime code.
std::string GetRuntimePath() const override {
char buffer[MAX_PATH];
if (!GetModuleFileNameA(reinterpret_cast<HINSTANCE>(&__ImageBase), buffer, _countof(buffer)))
return "";
// Remove the filename at the end, but keep the trailing slash
std::string path(buffer);
auto slash_index = path.find_last_of('\\');
if (slash_index == std::string::npos)
return "";
return path.substr(0, slash_index + 1);
}
virtual Status LoadDynamicLibrary(const std::string& library_filename, void** handle) const override {
*handle = ::LoadLibraryA(library_filename.c_str());
if (!handle)
*handle = ::LoadLibraryExA(library_filename.c_str(), nullptr, LOAD_LIBRARY_SEARCH_DEFAULT_DIRS | LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR);
if (!*handle)
return common::Status(common::ONNXRUNTIME, common::FAIL, "Failed to load library");
return common::Status::OK();
}

View file

@ -346,11 +346,15 @@ TEST(CApiTest, DISABLED_test_custom_op_library) {
std::string lib_name;
#if defined(_WIN32)
lib_name = "custom_op_library.dll";
char current_directory[/*MAX_PATH*/ 260];
if (_getcwd(current_directory, _countof(current_directory)))
lib_name = current_directory;
lib_name += "\\custom_op_library.dll";
#elif defined(__APPLE__)
lib_name = "libcustom_op_library.dylib";
#else
lib_name = "./libcustom_op_library.so";
lib_name = "./libcustom_op_library.so";
#endif
TestInference<PATH_TYPE, int32_t>(*ort_env, CUSTOM_OP_LIBRARY_TEST_MODEL_URI, inputs, "output", expected_dims_y, expected_values_y, 0, nullptr, lib_name.c_str());