Glib's GModules are fun :-) These functions provide a braindead interface to modular (think "plug-in based") programming. I wrote some testing code today (read the API a year ago or so but never played with it), here's a short introduction.
When writing module based applications there are mainly 2 parts: the modules, and the application using them. So we'll have to write these 2 things.
Getting started with the module is the easiest part:
#include <glib.h>
#include <gmodule.h>
G_MODULE_EXPORT void m_helloworld() {
g_print("Hello modular world!\n");
}
This code is pretty straight-forward. The only "strange" thing is G_MODULE_EXPORT, a platform-independent macro telling the compiler/linker to export the function.
Then comes the "client" application, a little more difficult. Comments inline:
#include <glib.h>
#include <gmodule.h>
/* A prototype of the function pointer we'll use */
/* void function(void) */
typedef void (*HelloWorldFunc) (void);
gint main(gint argc, gchar *argv[]) {
/* We need:
* - A handle to our module
* - A pointer to the function we'll import
* - Some helper strings */
GModule *module = NULL;
HelloWorldFunc hello = NULL;
gchar *module_path = NULL, *curr = NULL;
/* Check whether glib is compiled with module support */
if(g_module_supported() == FALSE) {
g_error("Modules not supported :(");
return 1;
}
/* We need to figure out the path to our module. In our test case, this
* is ".", so we want the current dir. */
curr = g_get_current_dir();
/* Create the path to the module. This function does quite a lot of
* of things, check the GModule API. */
module_path = g_module_build_path((const gchar *) curr, "module");
/* Don't we love debugging? */
g_debug("Module path: %s", module_path);
/* Finally we're able to open the module. We want lazy symbol resolving.
* This means we only want a symbol to be resolved if we request it.
* Once more, see the API for more information. */
module = g_module_open(module_path, G_MODULE_BIND_LAZY);
/* Get rid of those helper strings */
g_free(module_path);
g_free(curr);
/* Check whether the module was loaded successfully */
if(module == NULL) {
g_error("Unable to load module");
return 1;
}
/* Load the symbol and assign it to our function pointer.
* Check for errors */
if(g_module_symbol(module, "m_helloworld", (gpointer *) &hello) == FALSE) {
g_error("Unable to get function reference: %s", g_module_error());
return 1;
}
/* Now we can call our funtion.
* As you can see, we can call it as if it's a normal function.
* Don't we love function pointers? */
hello();
/* We're nice citizens and close all references when we leave */
if(g_module_close(module) == FALSE) {
g_error("Unable to close module: %s", g_module_error());
return 1;
}
return 0;
}
(this looks like a lot of code (well...) but if you strip all comments and debugging stuff/checks, you'll only have 10 lines or so)
Should be quite easy to understand too.
Now it's compile time. Of course, in a real-world situation, we'd use autotools to compile our libraries, we'd have a libtoolized library etc etc etc. Here we'll do it in the quick-and-dirty way:
# gcc -o libmodule.so -shared `pkg-config --libs --cflags glib-2.0 gmodule-2.0` module.c # gcc -o main `pkg-config --libs --cflags glib-2.0 gmodule-2.0` main.c # ls libmodule.so main main.c module.c # ./main ** (process:26533): DEBUG: Module path: /home/foo/bar/libmodule.so Hello modular world!
Loading all these symbols by hand is a boring task, so most of the time you'll create some API using vtables to make your life easier. More on this later (got to study now ;-) :|)
Comments:
took me some time to google it thogh.
thanx.
Thanks !
Regards,