The class PluginLoader is constructed with the path to a shared object library containing the actual plugin(s):
PluginLoader loader("[path to object library]");
The template function
getSymbol (string symbol, T &value)does the work of retrieving the entry point from the library. The idea is to pass a function pointer type which can be used to construct the plugin. This is preferable to returning a pointer to a created object as the application has full control over construction/destruction.
In the simple example below a plugin base class is created from which two plugins (PluginA and PluginB) are derived and must implement the pure virtual
outputMessage();The functions to construct the objects are declared "extern C" as this prevents C++ name mangling.
extern "C" PluginBase* LOAD_PLUGIN_A() { return new PluginA(); }
Below is a simple example which extracts two plugins, constructs them and runs the outputMessage() method:
typedef PluginBase* (*plugin_base_initfunc)(); //typedef to function pointer int main(int argc, char** argv) { try { PluginLoader loader("libSimplePlugin.so"); PluginBase* pPluginA = 0; PluginBase* pPluginB = 0; plugin_base_initfunc func; loader.getSymbolFunc("LOAD_PLUGIN_A", func); //extract function to construct a PluginA object pPluginA = (func)(); //construct plugin object cout << pPluginA->outputMessage() << endl; delete pPluginA; loader.getSymbolFunc("LOAD_PLUGIN_B", func); //extract function to construct a PluginB object pPluginB = (func)(); //construct plugin object cout << pPluginB->outputMessage() << endl; } catch (exception &e) { cout << e.what() << endl; } return 0; }
This produces the following output:
./pluginapp PluginA: Hello world PluginB: Hello world
See full source files below:
Class definition for PluginLoader.h
/** * Description: Class definition for loading shared object libraries at runtime. */ #ifndef PLUGIN_LOADER_H #define PLUGIN_LOADER_H #include "string.h" #include "iostream" using namespace std; class PluginLoader { public: /** * * @param libname path to required shared library file */ PluginLoader(string libname); virtual ~PluginLoader(); /** * * @param symbol symbol (defined using extern "C") to extract from opened shared library. * * @return address of symbol (either function or object) */ void *getSymbol(string symbol) const; /** * * @return name of shared library */ string getLibName() const { return(m_libname); }; templatevoid getSymbol (string symbol, T &value) const { void *sym = getSymbol(symbol); value = (T)(sym); } private: void *m_lib; string m_libname; }; #endif
Implementaion PluginLoader.cpp:
#include "CpluginLoader.h" #include "sstream" #include "dlfcn.h" #include "iostream" #include "stdexcept" using namespace std; PluginLoader::PluginLoader(string libname) { m_libname = libname; m_lib = dlopen(m_libname.c_str(), RTLD_LAZY | RTLD_GLOBAL); if (m_lib == 0) { stringstream errortext; if (char * err = dlerror()) { errortext << " dlopen() error: " << err << endl; throw runtime_error(errortext.str()); } } } PluginLoader::~PluginLoader() { dlclose(m_lib); } void * PluginLoader::getSymbol(string symbol) const { void *sym = 0; if (m_lib) { sym = dlsym(m_lib, symbol.c_str()); if (char * err = dlerror()) { stringstream errortext; errortext << "DynamicLibrary::getSymbol() - Error on " << symbol << "message: " << err; throw runtime_error(errortext.str()); } } else { throw runtime_error("DynamicLibrary::getSymbol() - Error accessing library"); } return (sym); }
Class definition PluginBase:
class PluginBase { public: PluginBase(); virtual ~PluginBase(); virtual string outputMessage()=0; };
Class definition PluginA:
class PluginA : public PluginBase { public: PluginA(); virtual ~PluginA(); virtual string outputMessage(); }; extern "C" PluginBase* LOAD_PLUGIN_A() { return new PluginA(); }
Implementaion of pure virtual:
string PluginA::outputMessage() { return "PluginA: Hello world"; }
No comments:
Post a Comment