Skip to content

Instantly share code, notes, and snippets.

@colesnicov
Last active January 28, 2017 16:20
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 colesnicov/23390d6bb8c89c910752ff429e34fb52 to your computer and use it in GitHub Desktop.
Save colesnicov/23390d6bb8c89c910752ff429e34fb52 to your computer and use it in GitHub Desktop.
Modular system in C++
/**
* @file Loader.cpp part of @file Loader.hpp
*
* @author Denis Colesnicov <eugustus@gmail.com>
* @date 2017/01/15
*
* @copyright MIT
*/
#include "LibraryLoader.h"
LibraryLoader* LibraryLoader::m_instance = nullptr;
LibraryLoader::LibraryLoader(bool verbose) :
m_verbose(verbose)
{
if (m_verbose)
{
std::cout << "LibraryLoader: Initialized" << std::endl;
}
}
LibraryLoader::~LibraryLoader()
{
unloadAll();
m_instance = nullptr;
}
void LibraryLoader::unloadAll()
{
size_t counts = m_handlers.size();
if (counts > 0)
{
if (m_verbose)
{
std::cout << "LibraryLoader: unloadAll(" << counts << ")" << std::endl;
}
std::map<const char*, void*>::iterator it = m_handlers.begin();
for (; it != m_handlers.end(); ++it)
{
unloadLib(it->first);
//m_handlers.erase(it);
}
}
}
LibraryLoader* LibraryLoader::getInstance(bool verbose)
{
if (!m_instance)
{
m_instance = new LibraryLoader(verbose);
}
return m_instance;
}
bool LibraryLoader::loadLib(const char* libName, bool reload)
{
if (reload)
{
unloadLib(libName);
}
if (m_verbose)
{
std::cout << "LibraryLoader: loadLib('" << libName << "', " << reload << ") ";
}
void* hndl = dlopen(libName, RTLD_LAZY);
if (hndl == NULL)
{
if (m_verbose)
{
std::cout << "[FAILED] ";
}
std::cout << dlerror() << std::endl;
return false;
}
else
{
if (m_verbose)
{
std::cout << "[SUCCESS]" << std::endl;
m_handlers.insert(std::pair<const char*, void*>(libName, hndl));
return true;
}
}
}
void* LibraryLoader::getHandler(const char* libName)
{
std::map<const char*, void*>::iterator it = m_handlers.find(libName);
if (it == m_handlers.end())
{
return NULL;
}
else
{
return it->second;
}
}
void LibraryLoader::unloadLib(const char* libName)
{
if (m_verbose)
{
std::cout << "LibraryLoader: unloadLib('" << libName << "')" << std::endl;
}
std::map<const char*, void*>::iterator it = m_handlers.find(libName);
if (it != m_handlers.end())
{
dlclose(it->second);
m_handlers.erase(it);
}
}
#ifndef LIBRARYLOADER_H
#define LIBRARYLOADER_H
/**
* @file Loader.hpp
* @version 1.2
*
* @brief Loader/Unloader for modules
* @details Singleton
*
* @author Denis Colesnicov <eugustus@gmail.com>
* @date 2017/01/15
*
* @copyright MIT
*/
#include <dlfcn.h>
#include <map>
#include <iostream>
class LibraryLoader {
public:
/**
* Destructor
*
* @detail Unload unreleased libraries and delete self instantion
*/
~LibraryLoader();
/**
* Create and/or Return instance of singleton
*
* @param verbose Print internal state to standard output
*
* @return LibraryLoader*
*/
static LibraryLoader* getInstance(bool verbose = false);
/**
* Load a library into memory.
*
* @detail You can choose whether the library has Reload without having to call yourself @see @param reload
*
* @param libName Name of Library to load
* @param reload If [true] trying to unload the library, before load
*
* @return TRUE if succeed, otherwise FALSE
*/
bool loadLib(const char* libName, bool reload = false);
/**
* Return pointer to Instantion of class
*
* @param libName Name of Library to load from it
* @param methodName The method name (factory) that creates a class object and returns it
*
* @return Instantion of T
*/
template <class T>
T loadClass(const char* libName, const char* methodName) {
if (m_verbose) {
std::cout << "LibraryLoader: loadClass('" << libName << "', '" << methodName << "') ";
}
void* handler = getHandler(libName);
if (handler == NULL) {
if (m_verbose) {
std::cout << "[FAILED] ";
std::cout << "You must load library using 'loadLibrary(" << libName << ")' first." << std::endl;
}
return NULL;
} else {
if (m_verbose) {
std::cout << "[SUCCESS]" << std::endl;
}
T(*mtd)() = reinterpret_cast<T(*)()> (dlsym(handler, methodName));
if (mtd) {
return mtd();
} else if (m_verbose) {
std::cout << "LibraryLoader: reinterpret_cast [FAILED] ";
std::cerr << dlerror() << std::endl;
}
}
}
/**
* Unload a library from memory
*
* @param libName Name of Library to unload
*/
void unloadLib(const char* libName);
/**
* Unload unreleased libraries
*/
void unloadAll();
private:
std::map<const char*, void*> m_handlers;
bool m_verbose;
static LibraryLoader* m_instance;
LibraryLoader(bool verbose);
LibraryLoader(const LibraryLoader& orig);
/**
* Returns pointer to use it as 'handle' of a dynamic library
*
* @param libName Name of Library
*
* @return Pointer to use with dl*(...) methods
*/
void* getHandler(const char* libName);
};
#endif /* LIBRARYLOADER_H */
/**
* @file: main.cpp
* @brief Example of use.
*
* @author: Denis Colesnicov <eugustus@gmail.com>
* @date 2017/01/15
*/
#include "Module.h"
#include "LibraryLoader.h"
int main()
{
app::context::IO* appContext = new app::context::IO();
app::Module* m;
LibraryLoader* loader = LibraryLoader::getInstance(true);
loader->loadLib("libMyModule.so");
m = loader->loadClass<app::Module *>("libMyModule.so", "make");
if (!m)
{
return 1;
}
m->Run();
loader->loadLib("libMyModule.so", true);
m = loader->loadClass<app::Module *>("libMyModule.so", "make");
if (!m)
{
return 1;
}
m->Run();
delete loader;
return 0;
}
#ifndef MODULE_H
#define MODULE_H
/**
* @file Module.hpp
* @version 1.2
*
* @brief Abstract class to create custom dinamicaly loaded modules
* @details Must be inherited and define method @see Run()
*
* @author Denis Colesnicov <eugustus@gmail.com>
* @date 2017/01/15
*
* @copyright MIT
*/
class Module{
public:
Module(){}
virtual void Run() = 0;
};
#endif /* MODULE_H */
#ifndef MYMODULE_H
#define MYMODULE_H
/**
* @file MyModule.hpp
* @version 1.0
*
* @brief Implementation of my module
* @details Inherited from Module @see @file Module.hpp
*
* @author Denis Colesnicov <eugustus@gmail.com>
* @date 2017/01/15
*
* @copyright MIT
*/
#include "Module.h"
#include <iostream>
class MyModule: public Module{
public:
void Run(){
std::cout << "Hello from MyModule :-)" <, std::endl;
}
};
extern "C" Module* make(){
return new MyModule();
}
#endif /* MYMODULE_H */
@colesnicov
Copy link
Author

Loader implements the singleton pattern. Here is the source

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment