From 5129c29a865c5014a8cc89e0f8e7a2bec1fc9f99 Mon Sep 17 00:00:00 2001 From: Andrew Belt Date: Sat, 25 Jan 2020 16:51:05 -0500 Subject: [PATCH] Use -rpath=. for plugins. Set cwd when loading plugins. --- plugin.mk | 10 ++++---- src/plugin.cpp | 69 ++++++++++++++++++++++++++++++-------------------- 2 files changed, 47 insertions(+), 32 deletions(-) diff --git a/plugin.mk b/plugin.mk index 21e23f53..bd6dd49b 100644 --- a/plugin.mk +++ b/plugin.mk @@ -20,24 +20,24 @@ FLAGS += -I$(RACK_DIR)/include -I$(RACK_DIR)/dep/include # I don't really understand the side effects (see GCC manual), but so far tests are positive. FLAGS += -fno-gnu-unique +LDFLAGS += -shared +LDFLAGS += -Wl,-rpath=. +LDFLAGS += -L$(RACK_DIR) -lRack + include $(RACK_DIR)/arch.mk ifdef ARCH_LIN - LDFLAGS += -shared TARGET := plugin.so RACK_USER_DIR ?= $(HOME)/.Rack - # Link to glibc 2.23 -# FLAGS += -include force_link_glibc_2.23.h endif ifdef ARCH_MAC - LDFLAGS += -shared -undefined dynamic_lookup TARGET := plugin.dylib + LDFLAGS += -undefined dynamic_lookup RACK_USER_DIR ?= $(HOME)/Documents/Rack endif ifdef ARCH_WIN - LDFLAGS += -shared -L$(RACK_DIR) -lRack TARGET := plugin.dll RACK_USER_DIR ?= "$(USERPROFILE)"/Documents/Rack endif diff --git a/src/plugin.cpp b/src/plugin.cpp index 916b1839..1f9e551c 100644 --- a/src/plugin.cpp +++ b/src/plugin.cpp @@ -43,51 +43,66 @@ namespace plugin { // private API //////////////////// +static void* loadLibrary(std::string libraryPath) { + #if defined ARCH_WIN + SetErrorMode(SEM_NOOPENFILEERRORBOX | SEM_FAILCRITICALERRORS); + std::wstring libraryFilenameW = string::toWstring(libraryPath); + HINSTANCE handle = LoadLibraryW(libraryFilenameW.c_str()); + SetErrorMode(0); + if (!handle) { + int error = GetLastError(); + throw Exception(string::f("Failed to load library %s: code %d", libraryPath.c_str(), error)); + } + #else + // Plugin uses -rpath=. so change working directory so it can find libRack. + char cwd[PATH_MAX]; + cwd[0] = '\0'; + getcwd(cwd, sizeof(cwd)); + chdir(asset::systemDir.c_str()); + // And then change it back + DEFER({ + chdir(cwd); + }); + // Load library with dlopen + void* handle = dlopen(libraryPath.c_str(), RTLD_NOW | RTLD_LOCAL); + if (!handle) { + throw Exception(string::f("Failed to load library %s: %s", libraryPath.c_str(), dlerror())); + } + #endif + return handle; +} + typedef void (*InitCallback)(Plugin*); -static InitCallback loadLibrary(Plugin* plugin) { +static InitCallback loadPluginCallback(Plugin* plugin) { // Load plugin library - std::string libraryFilename; + std::string libraryExt; #if defined ARCH_LIN - libraryFilename = plugin->path + "/" + "plugin.so"; + libraryExt = "so"; #elif defined ARCH_WIN - libraryFilename = plugin->path + "/" + "plugin.dll"; + libraryExt = "dll"; #elif ARCH_MAC - libraryFilename = plugin->path + "/" + "plugin.dylib"; + libraryExt = "dylib"; #endif + std::string libraryPath = plugin->path + "/plugin." + libraryExt; // Check file existence - if (!system::isFile(libraryFilename)) { - throw Exception(string::f("Library %s does not exist", libraryFilename.c_str())); + if (!system::isFile(libraryPath)) { + throw Exception(string::f("Library %s does not exist", libraryPath.c_str())); } // Load dynamic/shared library -#if defined ARCH_WIN - SetErrorMode(SEM_NOOPENFILEERRORBOX | SEM_FAILCRITICALERRORS); - std::wstring libraryFilenameW = string::toWstring(libraryFilename); - HINSTANCE handle = LoadLibraryW(libraryFilenameW.c_str()); - SetErrorMode(0); - if (!handle) { - int error = GetLastError(); - throw Exception(string::f("Failed to load library %s: code %d", libraryFilename.c_str(), error)); - } -#else - void* handle = dlopen(libraryFilename.c_str(), RTLD_NOW | RTLD_LOCAL); - if (!handle) { - throw Exception(string::f("Failed to load library %s: %s", libraryFilename.c_str(), dlerror())); - } -#endif - plugin->handle = handle; + plugin->handle = loadLibrary(libraryPath); // Get plugin's init() function InitCallback initCallback; #if defined ARCH_WIN - initCallback = (InitCallback) GetProcAddress(handle, "init"); + initCallback = (InitCallback) GetProcAddress(plugin->handle, "init"); #else - initCallback = (InitCallback) dlsym(handle, "init"); + initCallback = (InitCallback) dlsym(plugin->handle, "init"); #endif if (!initCallback) { - throw Exception(string::f("Failed to read init() symbol in %s", libraryFilename.c_str())); + throw Exception(string::f("Failed to read init() symbol in %s", libraryPath.c_str())); } return initCallback; @@ -139,7 +154,7 @@ static Plugin* loadPlugin(std::string path) { initCallback = core::init; } else { - initCallback = loadLibrary(plugin); + initCallback = loadPluginCallback(plugin); } initCallback(plugin);