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);
};
template void 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