模块的动态加载

模块的动态加载

这些函数提供了一种跨平台的方式动态加载对象文件(通常称为“插件”)。当前的实现支持所有提供了dlopen()实现(例如Linux/Sun)的系统,以及通过DLLs的Windows平台。

想要使用这些函数的程序必须链接到由以下命令输出的库:

pkg-config --libs gmodule-2.0

使用它们之前,您必须首先通过调用g_module_supported()来确定平台是否支持动态加载。如果是的话,您可以使用g_module_open()打开一个模块,使用g_module_symbol()查找模块的符号(例如,函数名),并最终使用g_module_close()关闭模块。g_module_name()将返回当前打开模块的文件名。

如果上述任何函数失败,可以使用g_module_error()获取错误状态。

GModule实现针对打开的模块使用引用计数,并支持模块内的钩子函数,这些函数在模块加载和卸载时被调用(见GModuleCheckInitGModuleUnload)。

如果您的模块向正在运行的程序中的公共子系统引入了静态数据,例如通过调用

static GQuark my_module_quark =
  g_quark_from_static_string ("my-module-stuff");

它必须通过调用g_module_make_resident()确保它永远不会被卸载。

调用GModule中定义的函数

// the function signature for 'say_hello'
typedef void (* SayHelloFunc) (const char *message);

gboolean
just_say_hello (const char *filename, GError **error)
{
  SayHelloFunc say_hello;
  GModule *module;

  module = g_module_open (filename, G_MODULE_BIND_LAZY);
  if (module == NULL)
    {
      g_set_error (error, FOO_ERROR, FOO_ERROR_BLAH,
                   "%s", g_module_error ());
      return FALSE;
    }

  if (!g_module_symbol (module, "say_hello", (gpointer *)&say_hello))
    {
      g_set_error (error, SAY_ERROR, SAY_ERROR_OPEN,
                   "%s: %s", filename, g_module_error ());

      if (!g_module_close (module))
        g_warning ("%s: %s", filename, g_module_error ());

      return FALSE;
    }

  if (say_hello == NULL)
    {
      g_set_error (error, SAY_ERROR, SAY_ERROR_OPEN,
                   "symbol say_hello is NULL");

      if (!g_module_close (module))
        g_warning ("%s: %s", filename, g_module_error ());

      return FALSE;
    }

  // call our function in the module
  say_hello ("Hello world!");

  if (!g_module_close (module))
    g_warning ("%s: %s", filename, g_module_error ());

  return TRUE;
 }