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