一、前言
为了使程序方便扩展,具备通用性,可以采用插件形式。采用异步事件驱动模型,保证主程序逻辑不变,将各个业务已动态链接库的形式加载进来,这就是所谓的插件。linux提供了加载和处理动态链接库的系统调用,非常方便。
生成动态链接库语法:
gcc -fPIC -shared <源文件> -o libxxx.so
用法示例:
gcc -fPIC -shared sum.c -o libsum.so
二、dlopen系列函数
Linux提供以下4个函数用于处理动态库:
void *dlopen(const char *filename, int flag);
char *dlerror(void);
void *dlsym(void *handle, const char *symbol);
int dlclose(void *handle);
Link with -ldl.
注意: 编译时候要加入 -ldl (指定dl库)
2.1 dlopen函数介绍
功能:打开一个动态链接库
包含头文件: #include<dlfcn.h>
函数定义:
void *dlopen( const char * pathname, int flag);
函数描述: 使用dlopen函数以指定模式打开指定的动态连接库文件,并返回一个句柄给调用进程。完毕之后,使用dlclose()来卸载打开的库。
flag:分为这2种
RTLD_LAZY 暂缓决定,等有需要时再解出符号
RTLD_NOW 立即决定,返回前解除所有未决定的符号。
返回值:
打开错误返回NULL
成功,返回库引用
使用dlopen:
dlopen()是一个强大的库函数。该函数将打开一个新库,并把它装入内存。该函数主要用来加载库中的符号,这些符号在编译的时候是不知道的。当库被装入后,可以把 dlopen() 返回的句柄作为给 dlsym() 的第一个参数,以获得符号在库中的地址。使用这个地址,就可以获得库中特定函数的指针,并且调用装载库中的相应函数。
示例代码:
int main()
{
int (*p)(int,int); //函数指针
void *handle;
/*1. 打开库文件*/
handle=dlopen("./sum/libsum.so",RTLD_LAZY);
if(handle==NULL)
{
printf("库打开失败!\n");
return 0;
}
/*2. 获取指定的函数地址*/
p=dlsym(handle,"sum");
if(p==NULL)
{
printf("函数地址获取失败!\n");
return 0;
}
//调用函数
printf("sum=%d\n",p(12,12));
/*3. 关闭库文件*/
dlclose(handle);
return 0;
}
2.2 dlsym()函数介绍
dlsym()的函数原型是:
void* dlsym(void* handle,const char* symbol)
该函数在<dlfcn.h>文件中。
handle是由dlopen打开动态链接库后返回的指针,symbol就是要求获取的函数的名称,函数返回值是void*,指向函数的地址,供调用使用
dlsym根据动态链接库操作句柄(pHandle)与符号(symbol),返回符号对应的地址。使用这个函数不但可以获取函数地址,也可以获取变量地址。
比如:假设在so中定义了一个
voidmytest()函数,那在使用so时先声明一个函数指针:void(*pMytest)(), 然后使用dlsym函数将函数指针pMytest指向mytest函数,pMytest = (void(*)())dlsym(pHandle, "mytest");
2.3 dlclose函数介绍
包含头文件: #include<dlfcn.h>
函数原型为: int dlclose (void *handle);
函数描述: dlclose用于关闭指定句柄的动态链接库,只有当此动态链接库的使用计数为0时,才会真正被系统卸载。
2.4 dlerror函数介绍
包含头文件: #include<dlfcn.h>
函数原型: constchar *dlerror(void);
函数描述:当动态链接库操作函数执行失败时,dlerror可以返回出错信息,返回值为NULL时表示操作函数执行成功。