mario::konrad
programming / C++ / sailing / nerd stuff
Loadable Modules
© 2004 / Mario Konrad

Introduction

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++.

Modules in 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:

#include <stdio.h>

void say_hello(void)
{
    printf("Hello World!\n");
}

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:

$ gcc -shared -fPIC -o module_c.so module_c.c
$ gcc -o main_c main_c.c

For newer versions of the compiler, you may omit even the -fPIC parameter, because all code is compiled position independent.

Now, run the program:

$ ./main_c

Modules in C++ (object oriented)

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'':

$ make

and run it:

$ ./main Test_Module_1.so
$ ./main Test_Module_2.so

Download

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: