Ikke's Blog

Post details: GModuleLoader

May 21
GModuleLoader

After Philip was talking about his GQueueThread/ASyncWorker on #gnome-nl, I was tempted to write some Glib-extension too, and so I did.

You might remember the extra exercise in my article on GModules and vtables, about loading all modules in the current directory and use them. Well, I created a generic object to handle this, because it's a functionality needed quite frequently in plugin-based programs.

I called this "GModuleLoader" ;-)

Here's a sample client application, loading 2 modules:

#include <glib.h>
#include <gmodule.h>

#include "g-module-loader.h"
#include "g-module-loader-module.h"

gint main(gint argc, gchar *argv[]) {
        GModuleLoader *l = NULL;
        guint cnt = 0;
        GPtrArray *modules = NULL;

        g_type_init();

        /* Create a new GModuleLoader */
        l = (GModuleLoader *) g_module_loader_new();
        g_assert(l != NULL);

        /* Load all modules in ".libs", with "simple-test" as data.
         * We do not want any error reporting (yet) */
        g_module_loader_load(l, ".libs", "simple-test", NULL);

        g_print("\n\nLooping through all loaded modules, printing the data\n");
        /* Get the list of all modules */
        modules = g_module_loader_get_modules(l);
        if(modules == NULL) {
                g_object_unref(l);
                g_error("No modules in list, aborting");
                return 1;
        }
        
        /* Loop */
        for(cnt = 0; cnt < modules->len; cnt++) {
                GModuleLoaderModule *m = NULL;
                gchar *data = NULL;
                GModule *mod = NULL;

                /* Get the GModuleLoaderModule */
                m = (GModuleLoaderModule *) g_ptr_array_index(modules, cnt);
                /* Normally we don't ever need the real GModule,
                 * because we use a vtable with all tables we need as returned
                 * data from the init function */
                mod = g_module_loader_module_get_module(m);
                if(m == NULL) {
                        g_error("Module in a GModuleLoaderModule should never be null");
                        return 1;
                }
                /* This is the data returned by the module init function.
                 * Most times this will be a vtable/struct */
                data = g_module_loader_module_get_module_data(m);

                g_print("%s:\t%s\n", g_module_name(mod), data);
        }
        g_print("\n");
        
        /* Clean up */
        g_object_unref(l);
        
        return 0;
}

I hope this is understandable :-)

Here's the code for "module1.c", the source for libmodule1.so. "module2.c" is almost the same: s/M1/M2 and s/module1/module2:

#include <glib.h>
#include <gmodule.h>

/* This is a fixed name, the module init function
 * It takes a pointer (given by the client code)
 * and can return some data (most of the time a vtable/struct, we keep it 
 * simple here) */
G_MODULE_EXPORT gpointer module_get_data(gpointer data) {
        gchar *s = NULL;
        
        s = (gchar *) data;
        if(s != NULL) {
                g_print("\n[M1] Module1 loaded with data \"%s\"\n\n", s);
        }

        return g_strdup("[M1] module1data");
}

/* Same thing, fixed name.
 * This function takes a pointer to the data given by module_get_data
 * and is called when this data should be freed */
G_MODULE_EXPORT void module_free_data(gpointer data) {
        gchar *s = NULL;
        
        s = (gchar *) data;
        if(s != NULL) {
                g_print("\n[M1] Freeing module1 data \"%s\"\n\n", s);
                g_free(data);
        }

        return;
}

As you can see I'm using fixed names in the plugins, I don't think there's any other way to do this kind of things. None of these 2 functions are required though.

Here's the output of the test application:

# ./simple-test
** (process:24094): DEBUG: Loading all modules in .libs, suffix is so
** (process:24094): DEBUG: Suffix for .libs/libmodule1.so is so, loading module
** (process:24094): DEBUG: Loading data for .libs/libmodule1.so

[M1] Module1 loaded with data "simple-test"

** (process:24094): DEBUG: Module .libs/libmodule1.so is valid, adding
** (process:24094): DEBUG: Suffix for .libs/libmodule2.so is so, loading module
** (process:24094): DEBUG: Loading data for .libs/libmodule2.so

[M2] Module2 loaded with data "simple-test"

** (process:24094): DEBUG: Module .libs/libmodule2.so is valid, adding


Looping through all loaded modules, printing the data
.libs/libmodule1.so:    [M1] module1data
.libs/libmodule2.so:    [M2] module2data

** (process:24094): DEBUG: Deleting 2 modules
** (process:24094): DEBUG: Freeing data for .libs/libmodule1.so

[M1] Freeing module1 data "[M1] module1data"

** (process:24094): DEBUG: Closing module .libs/libmodule1.so
** (process:24094): DEBUG: Freeing data for .libs/libmodule2.so

[M2] Freeing module2 data "[M2] module2data"

** (process:24094): DEBUG: Closing module .libs/libmodule2.so

It should be fairly easy to follow all steps, find out the module_get_data and module_free_data calls, etc.

It's working fairly well now, I'll try to enhance it some more, test it better and document it, then maybe I'll send some email to the Glib list ;-)

Comments:

No Comments for this post yet...

Leave a comment:

Your email address will not be displayed on this site.
Your URL will be displayed.

Allowed XHTML tags: <p, ul, ol, li, dl, dt, dd, address, blockquote, ins, del, span, bdo, br, em, strong, dfn, code, samp, kdb, var, cite, abbr, acronym, q, sub, sup, tt, i, b, big, small>
(Line breaks become <br />)
(Set cookies for name, email and url)
(Allow users to contact you through a message form (your email will NOT be displayed.))

Categories

Who's Online?

  • Guest Users: 457

Misc

XML Feeds

What is RSS?