Loadable modules are great if you like to implement some plugin mechanism or a similar feature. This tutorial shows you how to do this in pure C and C++.
The implementation of modules in is very easy. This example shows a main program that loads one module and executes its function.
The source of the module is simple:
module_c.c
:
The entire complexity lies in the main program:
main_c.c
:
#include <stdio.h>
#include <dlfcn.h>
int main(void)
{
// variables needed to handle the module
void * module_handle = 0;
void (*hello)(void) = 0;
const char * error = 0;
// open the module
module_handle = dlopen("module_c.so", RTLD_LAZY);
if (!module_handle)
{
// error: not able to open the module
fprintf(stderr, "%s\n", dlerror());
exit(-1);
}
// link symbol
hello = dlsym(module_handle, "say_hello");
if ((error = dlerror()) != 0)
{
// error: symbol not found in module
fprintf(stderr, "%s\n", error);
exit(-2);
}
// use module
hello();
// close/unload module
dlclose(module_handle);
return 0;
}
To build the program, follow the steps:
For newer versions of the compiler, you may omit even the -fPIC
parameter, because all code is compiled position independent.
Now, run the program:
The object oriented case is more complex than the previous one. Let’s have a look at the class diagram to get the general idea:
The core of this example is the class Module
. It provides all functionality that are needed to handle loadable modules. Have a look at the source code:
Module.h
:
#ifndef __MODULE_H__
#define __MODULE_H__
class Module
{
private:
void * handle;
public:
static Module * load(const char *);
static bool unload(Module *);
public:
virtual const char * name() = 0;
};
extern "C" Module * create_module(void);
#endif
Module.cpp
:
#include "Module.h"
#include <iostream>
#include <dlfcn.h>
using namespace std;
Module * Module::load(const char * module_name)
{
void * handle = 0;
Module * module = 0;
Module * (*creator)(void) = 0;
const char * error = 0;
// open module
handle = dlopen(module_name, RTLD_NOW);
if (!handle)
{
if ((error = dlerror()) != 0) cerr << error << endl;
return 0;
}
// link factory method
creator = (Module *(*)(void))dlsym(handle, "create_module");
if (!creator)
{
if ((error = dlerror()) != 0)
{
cerr << error << endl;
return 0;
}
}
// create object and return it
module = (*creator)();
module->handle = handle;
return module;
}
bool Module::unload(Module * module)
{
// destroy object and close module
if (!module) return false;
void * handle = module->handle;
delete module;
dlclose(handle);
return true;
}
The modules are rather easy:
Test_Module_1.h
:
#ifndef __TEST_MODULE_1_H__
#define __TEST_MODULE_1_H__
#include "Module.h"
class Test_Module_1 : public Module
{
public:
virtual const char * name();
};
extern "C" Module * create_module(void);
#endif
Test_Module_1.cpp
:
#include "Test_Module_1.h"
const char * Test_Module_1::name()
{
return "Test Module 1";
}
extern "C" Module * create_module(void)
{
return new Test_Module_1;
}
Test_Module_2.h
:
#ifndef __TEST_MODULE_2_H__
#define __TEST_MODULE_2_H__
#include "Module.h"
class Test_Module_2 : public Module
{
public:
virtual const char * name();
};
extern "C" Module * create_module(void);
#endif
Test_Module_2.cpp
:
#include "Test_Module_2.h"
const char * Test_Module_2::name()
{
return "Test Module 2";
}
extern "C" Module * create_module(void)
{
return new Test_Module_2;
}
The usage of the modules is now very easy, just use the module factory:
main.cpp
:
#include "Module.h"
#include <iostream>
using namespace std;
int main(int argc, char ** argv)
{
Module * module = Module::load(argv[1]);
if (!module)
{
cerr << "error: could not load module" << endl;
exit(-1);
}
cout `<< "name: [" << module->`name() << "]" << endl;
Module::unload(module);
return 0;
}
To build this demo program, just use the ‘’Makefile’’:
and run it:
All source files provided by this page are free to modify, distribute or to use them in any kind you like. Use them on your own risk.
All files for the C tutorial:
All files for the C++ tutorial: