Skip to content

Instantly share code, notes, and snippets.

@hamsham
Last active August 29, 2015 14:08
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save hamsham/cc3993fe822fdb0876a6 to your computer and use it in GitHub Desktop.
Save hamsham/cc3993fe822fdb0876a6 to your computer and use it in GitHub Desktop.
Example source file for a shared library loader that loads plugin objects from the pluginAPI.h header
#include <iostream>
#include <string>
#include <cctype> // tolower()
#include <SDL2/SDL.h>
#include "sharedLibrary.h"
//-----------------------------------------------------------------------------
// Destructor
//-----------------------------------------------------------------------------
sharedLibrary::~sharedLibrary() {
unload();
}
//-----------------------------------------------------------------------------
// Move Constructor
//-----------------------------------------------------------------------------
sharedLibrary::sharedLibrary(sharedLibrary&& sl) :
pFactory{sl.pFactory},
pDeleter{sl.pDeleter},
pPlugin{sl.pPlugin},
pHandle{sl.pHandle}
{
sl.pFactory = nullptr;
sl.pDeleter = nullptr;
sl.pPlugin = nullptr;
sl.pHandle = nullptr;
}
//-----------------------------------------------------------------------------
// Move Operator
//-----------------------------------------------------------------------------
sharedLibrary& sharedLibrary::operator=(sharedLibrary&& sl) {
pFactory = sl.pFactory;
sl.pFactory = nullptr;
pDeleter = sl.pDeleter;
sl.pDeleter = nullptr;
pPlugin = sl.pPlugin;
sl.pPlugin = nullptr;
pHandle = sl.pHandle;
sl.pHandle = nullptr;
return *this;
}
//-----------------------------------------------------------------------------
// Load the plugin creation method from a shared library
//-----------------------------------------------------------------------------
bool sharedLibrary::loadFactoryMethod() {
// Get the plugin's factory function from the loaded library.
std::cout << "Attempting to load a plugin factory." << std::endl;
// ISO C and C++ prevent casting from void pointers to function pointers.
// A workaround is to cast to a ptrdiff_t, then cast again to a function
// pointer.
const ptrdiff_t ptrVal = reinterpret_cast<ptrdiff_t>(
SDL_LoadFunction(pHandle, PLUGIN_FACTORY_NAME)
);
pFactory = reinterpret_cast<pluginFactory_t>(ptrVal);
// make sure that the factory method loaded correctly.
if (!pFactory) {
std::cerr << "Failed to load a plugin factory." << std::endl;
}
else {
std::cout << "Successfully loaded a plugin factory." << std::endl;
}
return pFactory != nullptr;
}
//-----------------------------------------------------------------------------
// Load the plugin deletion method from a shared library
//-----------------------------------------------------------------------------
bool sharedLibrary::loadDeleterMethod() {
// Get the plugin's deleter function from the loaded library.
std::cout << "Attempting to load a plugin deleter." << std::endl;
// ISO C and C++ prevent casting from void pointers to function pointers.
// A workaround is to cast to a ptrdiff_t, then cast again to a function
// pointer.
const ptrdiff_t ptrVal = reinterpret_cast<ptrdiff_t>(
SDL_LoadFunction(pHandle, PLUGIN_DELETER_NAME)
);
pDeleter = reinterpret_cast<pluginDeleter_t>(ptrVal);
// make sure that the deletion method loaded correctly.
if (!pDeleter) {
std::cerr << "Failed to load a plugin deleter." << std::endl;
}
else {
std::cout << "Successfully loaded a plugin deleter." << std::endl;
}
return pDeleter != nullptr;
}
//-----------------------------------------------------------------------------
// Load a plugin object from a shared library into *this.
//-----------------------------------------------------------------------------
bool sharedLibrary::load(const std::string& filename) {
unload();
// load the plugin library file.
std::cout << "Attempting to load the shared library " << filename << '.' << std::endl;
// Get a handle to the shared library. SDL returns NULL if it couldn't be loaded
pHandle = SDL_LoadObject(filename.c_str());
if (!pHandle
|| !loadFactoryMethod()
|| !loadDeleterMethod()
) {
std::cerr << "Unable to load the shared library " << filename << '.' << std::endl;
unload();
return false;
}
else {
std::cout << "Successfully loaded the shared library " << filename << '.' << std::endl;
}
// Instantiate the plugin object from the loaded library factory.
std::cout << "Attempting to instantiate a plugin from " << filename << '.' << std::endl;
pPlugin = (*pFactory)();
// Simple error checking.
if (!pPlugin) {
std::cerr << "Failed to instantiate a plugin from " << filename << '.' << std::endl;
unload();
return false;
}
else {
std::cout << "Successfully instantiated a plugin from " << filename << '.' << std::endl;
}
return true;
}
//-----------------------------------------------------------------------------
// Unload all handles to a shared library
//-----------------------------------------------------------------------------
void sharedLibrary::unload() {
// Delete the loaded plugin object using the deletion method.
if (pPlugin) {
// A deleter method is guaranteed to be provided if a plugin exists.
(*pDeleter)(pPlugin);
SDL_UnloadObject(pHandle);
}
// Remove all expired pointers
pFactory = nullptr;
pDeleter = nullptr;
pPlugin = nullptr;
pHandle = nullptr;
}
//-----------------------------------------------------------------------------
// Get a pointer to the plugin object contained within *this.
// Returns NULL if nothing is there.
//-----------------------------------------------------------------------------
const plugin* sharedLibrary::getPlugin() const {
return pPlugin;
}
//-----------------------------------------------------------------------------
// A simple file name check for shared library files
//-----------------------------------------------------------------------------
bool sharedLibrary::isSharedLib(const std::string& filename) {
std::cout << "Parsing the file " << filename << " for its extension." << std::endl;
std::string::size_type extPos = filename.rfind('.');
if (extPos == std::string::npos) {
std::cerr << "Unable to find the input file's extension." << std::endl;
return false;
}
// extract the extension of the input file name
std::string&& extStr = filename.substr(extPos);
const std::string globalPluginExt{PLUGIN_EXT};
// turn all of the file name's letters to lowercase for easier parsing
for (unsigned i = 0; i < extStr.size(); ++i) {
extStr[i] = std::tolower(extStr[i]);
if (extStr[i] != globalPluginExt[i]) {
std::cerr
<< "The plugin " << filename << " has an unknown extension of "
<< extStr << ". This program only accepts plugins with the extension "
<< globalPluginExt << '.' << std::endl;
return false;
}
}
return true;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment