Instantly share code, notes, and snippets.
Last active
August 29, 2015 14:08
-
Star
(0)
0
You must be signed in to star a gist -
Fork
(0)
0
You must be signed in to fork a gist
-
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
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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