Loading CMakeLists.txt +10 −0 Changes for CMakeLists.txt: 10 added lines, 0 removed lines. Original line number Diff line number Diff line Loading @@ -71,6 +71,16 @@ add_executable(proxyplus src/main.cpp) target_link_libraries(proxyplus PRIVATE proxyplus_core) target_compile_definitions(proxyplus PRIVATE PROXYPLUS_DEFAULT_STATIC_DIR="${CMAKE_INSTALL_PREFIX}/share/proxyplus/admin") # ENABLE_EXPORTS (-rdynamic/--export-dynamic): IPlugin and its extension-point interfaces # (see src/plugin/PluginApi.h) have no out-of-line virtual function, so their vtable/typeinfo # get vague (weak) linkage rather than one strong definition -- proxyplus's own copy (pulled # in via CertificateManager.cpp etc.) needs to be visible in the dynamic symbol table so the # dynamic linker can merge it with the copy inside each dlopen()'d plugin .so. Without this, # dynamic_cast<ICertificateProviderPlugin*> (used by PluginManager::collect<Iface>()) finds # no match even though the plugin genuinely implements the interface -- confirmed to matter # in practice on OpenBSD/clang/libc++abi; virtual calls (e.g. IPlugin::name()) work regardless # since those go through the vtable pointer directly, not RTTI. set_target_properties(proxyplus PROPERTIES ENABLE_EXPORTS ON) install(TARGETS proxyplus RUNTIME DESTINATION bin) install(DIRECTORY admin/static/ DESTINATION share/proxyplus/admin) Loading src/plugin/PluginManager.cpp +1 −10 Changes for src/plugin/PluginManager.cpp: 1 added line, 10 removed lines. Original line number Diff line number Diff line Loading @@ -28,16 +28,7 @@ void PluginManager::loadDirectory(const std::string &dir, const std::map<std::st std::string path = dir + "/" + fname; // 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); void *handle = ::dlopen(path.c_str(), RTLD_NOW | RTLD_LOCAL); if (!handle) { _errors.push_back(fname + ": " + std::string(::dlerror() ? ::dlerror() : "dlopen failed")); Loading Loading
CMakeLists.txt +10 −0 Changes for CMakeLists.txt: 10 added lines, 0 removed lines. Original line number Diff line number Diff line Loading @@ -71,6 +71,16 @@ add_executable(proxyplus src/main.cpp) target_link_libraries(proxyplus PRIVATE proxyplus_core) target_compile_definitions(proxyplus PRIVATE PROXYPLUS_DEFAULT_STATIC_DIR="${CMAKE_INSTALL_PREFIX}/share/proxyplus/admin") # ENABLE_EXPORTS (-rdynamic/--export-dynamic): IPlugin and its extension-point interfaces # (see src/plugin/PluginApi.h) have no out-of-line virtual function, so their vtable/typeinfo # get vague (weak) linkage rather than one strong definition -- proxyplus's own copy (pulled # in via CertificateManager.cpp etc.) needs to be visible in the dynamic symbol table so the # dynamic linker can merge it with the copy inside each dlopen()'d plugin .so. Without this, # dynamic_cast<ICertificateProviderPlugin*> (used by PluginManager::collect<Iface>()) finds # no match even though the plugin genuinely implements the interface -- confirmed to matter # in practice on OpenBSD/clang/libc++abi; virtual calls (e.g. IPlugin::name()) work regardless # since those go through the vtable pointer directly, not RTTI. set_target_properties(proxyplus PROPERTIES ENABLE_EXPORTS ON) install(TARGETS proxyplus RUNTIME DESTINATION bin) install(DIRECTORY admin/static/ DESTINATION share/proxyplus/admin) Loading
src/plugin/PluginManager.cpp +1 −10 Changes for src/plugin/PluginManager.cpp: 1 added line, 10 removed lines. Original line number Diff line number Diff line Loading @@ -28,16 +28,7 @@ void PluginManager::loadDirectory(const std::string &dir, const std::map<std::st std::string path = dir + "/" + fname; // 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); void *handle = ::dlopen(path.c_str(), RTLD_NOW | RTLD_LOCAL); if (!handle) { _errors.push_back(fname + ": " + std::string(::dlerror() ? ::dlerror() : "dlopen failed")); Loading