Loading src/plugin/PluginManager.cpp +10 −1 Changes for src/plugin/PluginManager.cpp: 10 added lines, 1 removed line. Original line number Diff line number Diff line Loading @@ -32,7 +32,16 @@ void PluginManager::loadDirectory(const std::string &dir, const std::map<std::st std::cout << "[plugin] loading " << path << std::endl; void *handle = ::dlopen(path.c_str(), RTLD_NOW | RTLD_LOCAL); // RTLD_GLOBAL, not RTLD_LOCAL: IPlugin and its extension-point interfaces (see // PluginApi.h) have no out-of-line virtual function, so their vtable/typeinfo get // vague (weak) linkage rather than one strong definition. Under RTLD_LOCAL every // dlopen'd plugin -- and the host binary -- carries its own private copy, and // dynamic_cast (used by collect<Iface>() below) compares typeinfo identity across // images and finds no match, even though the plugin genuinely implements the // interface (virtual calls still work fine since those go through the vtable // pointer directly, not RTTI). RTLD_GLOBAL lets the dynamic linker share one copy // of those weak symbols across the whole process instead. void *handle = ::dlopen(path.c_str(), RTLD_NOW | RTLD_GLOBAL); if (!handle) { std::cerr << "[plugin] " << fname << ": dlopen failed: " << (::dlerror() ? ::dlerror() : "unknown error") << std::endl; Loading Loading
src/plugin/PluginManager.cpp +10 −1 Changes for src/plugin/PluginManager.cpp: 10 added lines, 1 removed line. Original line number Diff line number Diff line Loading @@ -32,7 +32,16 @@ void PluginManager::loadDirectory(const std::string &dir, const std::map<std::st std::cout << "[plugin] loading " << path << std::endl; void *handle = ::dlopen(path.c_str(), RTLD_NOW | RTLD_LOCAL); // RTLD_GLOBAL, not RTLD_LOCAL: IPlugin and its extension-point interfaces (see // PluginApi.h) have no out-of-line virtual function, so their vtable/typeinfo get // vague (weak) linkage rather than one strong definition. Under RTLD_LOCAL every // dlopen'd plugin -- and the host binary -- carries its own private copy, and // dynamic_cast (used by collect<Iface>() below) compares typeinfo identity across // images and finds no match, even though the plugin genuinely implements the // interface (virtual calls still work fine since those go through the vtable // pointer directly, not RTTI). RTLD_GLOBAL lets the dynamic linker share one copy // of those weak symbols across the whole process instead. void *handle = ::dlopen(path.c_str(), RTLD_NOW | RTLD_GLOBAL); if (!handle) { std::cerr << "[plugin] " << fname << ": dlopen failed: " << (::dlerror() ? ::dlerror() : "unknown error") << std::endl; Loading