Glib学习(21) 动态加载模块 Dynamic Loading of Modules

glib源码下载:http://ftp.gnome.org/pub/gnome/sources/glib/
glib帮助文档:https://developer.gnome.org/glib/

本节主要讲解一下Memory Allocation函数,基本就是linux系统函数的封装,我把函数使用谷歌翻译了一下,没有仔细校验,因为英语是在太差,而且函数基本差不多,懂了一个就能举一反三。

Includes
#include <gmodule.h>

描述
这些函数提供了一种动态加载目标文件的便携方式(通常称为“插件”)。 当前实现支持所有提供dlopen()(例如Linux / Sun)实现的系统,以及通过DLL提供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实现为打开的模块提供引用计数,并支持模块中的钩子函数,这些函数在加载和卸载模块时调用(参见GModuleCheckInit和GModuleUnload)。
如果您的模块将静态数据引入正在运行的程序中的公共子系统,例如 通过调用g_quark_from_static_string(“my-module-stuff”),它必须通过调用g_module_make_resident()来确保它永远不会被卸载。

// 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)
    {
      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;
 }

函数
g_module_supported ()
gboolean
g_module_supported (void);
检查当前平台是否支持模块。
返回值
如果支持模块,则为TRUE
g_module_build_path ()
gchar *
g_module_build_path (const gchar *directory,
                     const gchar *module_name);
一种构建模块文件名的便携方式。 如果需要,将特定于平台的前缀和后缀添加到文件名中,并使用正确的分隔符将结果添加到目录中。
该目录应指定可以找到模块的目录。 它可以是NULL或空字符串,以指示模块位于标准的特定于平台的目录中,但不建议这样做,因为可能找到了错误的模块。
例如,在目录为/lib且module_name为“mylibrary”的Linux系统上调用g_module_build_path()将返回/lib/libmylibrary.so。 在Windows系统上,使用\Windows作为目录,它将返回\Windows\mylibrary.dll。
参数
directory
模块所在的目录。 这可以是NULL或空字符串,以指示将使用标准的特定于平台的目录,但不建议这样做。
[nullable]
module_name

模块名字
返回值
模块的完整路径,包括标准库前缀和后缀。 不再需要时应该释放它

g_module_open ()
GModule *
g_module_open (const gchar *file_name,
               GModuleFlags flags);
打开一个模块。 如果模块已经打开,则其引用计数会递增。
首先,g_module_open()尝试将file_name作为模块打开。 如果失败并且file_name具有“.la”-suffix(并且是libtool存档),则它会尝试打开相应的模块。 如果失败并且没有适用于平台的模块后缀(G_MODULE_SUFFIX),则将附加此后缀并打开相应的模块。 如果失败并且file_name没有“.la”-suffix,则附加此后缀并且g_module_open()尝试打开相应的模块。 如果最终失败,则返回NULL。
参数
file_name
包含模块的文件的名称,或NULL以获取表示主程序本身的GModule。
[nullable]
flags
用于打开模块的标志。 这可以是任何GModuleFlags的逻辑或
返回值
a GModule on success, or NULL on failure

g_module_symbol ()
gboolean
g_module_symbol (GModule *module,
                 const gchar *symbol_name,
                 gpointer *symbol);
获取模块的符号指针,例如由G_MODULE_EXPORT导出的模块。 请注意,有效符号可以为NULL。
参数
module

a GModule
symbol_name
要查找的符号的名称
symbol
返回指向符号值的指针。
[out]
返回值
TRUE on success

g_module_name ()
const gchar *
g_module_name (GModule *module);
返回打开模块的文件名。
如果模块引用应用程序本身,则返回“main”。
参数
module

a GModule
返回值
模块的文件名。
[transfer none]

g_module_make_resident ()
void
g_module_make_resident (GModule *module);
确保永远不会卸载模块。 将忽略对模块的任何未来g_module_close()调用。
参数
module
一个GModule永久居住

g_module_close ()
gboolean
g_module_close (GModule *module);
Closes a module.

参数
module

a GModule to close
返回值
TRUE on success

g_module_error ()
const gchar *
g_module_error (void);
获取描述最后一个模块错误的字符串。
返回值
描述最后一个模块错误的字符串

GModuleCheckInit ()
const gchar *
(*GModuleCheckInit) (GModule *module);
指定模块初始化函数的类型。 如果模块包含名为g_module_check_init()的函数,则在加载模块时会自动调用它。 它传递给GModule结构,成功时应返回NULL或描述初始化错误的字符串。
参数
module
与刚加载的模块对应的GModule
返回值
成功时为NULL,或描述初始化错误的字符串

GModuleUnload ()
void
(*GModuleUnload) (GModule *module);
指定卸载时调用的模块函数的类型。 如果模块包含名为g_module_unload()的函数,则在卸载模块时会自动调用它。 它通过了GModule结构。
参数
module
即将卸载的GModule

typedef struct _GModule GModule;
GModule结构是一个不透明的数据结构,用于表示动态加载的模块。 只能通过以下功能访问它。
enum GModuleFlags
标志传递给g_module_open()。 请注意,并非所有平台都支持这些标志。
Members
G_MODULE_BIND_LAZY
指定仅在需要时解析符号。 默认操作是在加载模块时绑定所有符号。
G_MODULE_BIND_LOCAL
指定不应将模块中的符号添加到全局名称空间。 大多数平台上的默认操作是将模块中的符号放在全局名称空间中,这可能会导致与现有符号冲突。
G_MODULE_BIND_MASK
所有标志的掩码。
G_MODULE_SUFFIX
#define G_MODULE_SUFFIX "so"
在没有前导点的情况下扩展到当前平台的正确共享库后缀。 对于大多数Unices和Linux来说,这是“so”,对于Windows,这是“dll”。
G_MODULE_EXPORT
#  define G_MODULE_EXPORT        __declspec(dllexport)
用于声明由库或模块导出的函数。
在为Windows编译时,它将符号标记为dllexport。
在为Linux和Unices进行编译时,它会将符号标记为具有默认可见性。 除非使用非默认可见性标志(例如hidden)编译代码,否则这是无操作。
G_MODULE_IMPORT
#define G_MODULE_IMPORT        extern
用于声明从模块导入的函数。

例子:

首先需要准备一个库,一会需要动态加载

hello.h

/*************************************************************************
    > File Name: hello.h
 ************************************************************************/
#ifndef _HELLO_H_
#define _HELLO_H_
#include <gmodule.h>
void hello();
void SayHello (const char *message);
const gchar *	g_module_check_init(GModule *module);
void	g_module_unload(GModule *module);

#endif

hello.c

/*************************************************************************
    > File Name: hello.c
 ************************************************************************/
 
#include <stdio.h>
#include "hello.h"

const gchar *g_module_check_init(GModule *module)
{
	g_print("%s: g_module_check_init!\n", g_module_name(module));
	return NULL;
}

void g_module_unload(GModule *module)
{
	g_print("%s: g_module_unload!\n", g_module_name(module));
}

void hello()
{
    printf("hello world!\n");
}

void SayHello(const char *message)
{
    printf("hello %s!\n", message);
}

编译出.so

gcc hello.c -I../include -I/home/renz/glibtest/glib/include/glib-2.0 -I/home/renz/glibtest/glib/lib/glib-2.0/include -fpic -shared -o libhello.so

需要写个例子:

gmodules.c

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

// 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;

	GQuark FOO_ERROR = g_quark_from_string("FOO_ERROR");
	gint FOO_ERROR_BLAH;
	GQuark SAY_ERROR = g_quark_from_string("SAY_ERROR");
	gint SAY_ERROR_OPEN;
    module = g_module_open (filename, G_MODULE_BIND_LAZY);
    if (!module) {
        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;
}

int main(int argc, char **argv)
{
	SayHelloFunc  say_hello;
	GQuark FOO_ERROR = g_quark_from_string("FOO_ERROR");
	gint FOO_ERROR_BLAH;
	GQuark SAY_ERROR = g_quark_from_string("SAY_ERROR");
	gint SAY_ERROR_OPEN;
	g_printf ("main in\n");
	g_printf ("module is %ssupported!\n", g_module_supported ()?"":"not ");
	gchar *str_lib = 
	g_module_build_path ("/home/renz/glibtest",
						 "hello");
	g_printf ("path of the module:%s\n", str_lib);

	GModule *module = 
	g_module_open (str_lib,
				   G_MODULE_BIND_LAZY);
	
	const gchar *module_name =
	g_module_name (module);
	g_printf ("filename of the module:%s\n", module_name);
	
	if (!g_module_symbol (module, "say_hello", (gpointer *)&say_hello)) {
        g_warning ("%s\n", g_module_error ());
    }
	if (!g_module_symbol (module, "SayHello", (gpointer *)&say_hello)) {
        g_warning ("%s\n", g_module_error ());
        if (!g_module_close (module))
            g_warning ("%s: %s\n", str_lib, g_module_error ());
    }
	
	say_hello ("Hello world!");
	
	if (!g_module_close (module))
        g_warning ("%s: %s", str_lib, g_module_error ());
	
	g_printf ("main out\n");
    return 0;
}


编译:gcc gmodules.c -o gmodules -L/home/renz/glibtest/glib/lib -I/home/renz/glibtest/glib/include/glib-2.0 -I/home/renz/glibtest/glib/lib/glib-2.0/include -lglib-2.0 -lpthread -lgmodule-2.0 -g -rdynamic

执行文件输出如下:

main in
module is supported!
path of the module:/home/renz/glibtest/libhello.so
/home/renz/glibtest/libhello.so: g_module_check_init!
filename of the module:/home/renz/glibtest/libhello.so

** (process:26230): WARNING **: 'say_hello': /home/renz/glibtest/libhello.so: undefined symbol: say_hello

hello Hello world!!
/home/renz/glibtest/libhello.so: g_module_unload!
main out

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值