使用dlopen动态链接库的一个问题

当我们采用异步事件驱动模型,保证主程序逻辑不变,将各个业务用动态链接库的形式加载进来,这就是所谓的插件。linux和Windows提供了加载和处理动态链接库的系统调用,非常方便。该文章记录一个在使用过程中的问题。

1、Linux

Linux提供了一套API来动态装载库:

dlopen,打开一个动态库,并为使用该库做些准备。
dlsym,在打开的库中查找符号的值。

dlclose,关闭库。
dlerror,返回一个描述最后一次调用dlopen、dlsym,或dlclose的错误信息的字符串。

包括头文件:
#include <dlfcn.h>
函数定义:
void * dlopen( const char * pathname, int mode);
函数描写叙述:mode是打开方式,其值有多个,不同操作系统上实现的功能有所不同,在linux下,按功能可分为三类:
(1)解析方式
RTLD_LAZY:在dlopen返回前,对于动态库中的没有定义的符号不运行解析(仅仅对函数引用有效。对于变量引用总是马上解析)。
RTLD_NOW: 须要在dlopen返回前。解析出全部没有定义符号,假设解析不出来。在dlopen会返回NULL,错误为:: undefined symbol: xxxx.......
(2)作用范围,可与解析方式通过“|”组合使用。
RTLD_GLOBAL:动态库中定义的符号可被其后打开的其他库解析。
RTLD_LOCAL: 与RTLD_GLOBAL作用相反,动态库中定义的符号不能被其后打开的其他库重定位。

假设没有指明是RTLD_GLOBAL还是RTLD_LOCAL。则缺省为RTLD_LOCAL。
(3)作用方式
RTLD_NODELETE: 在dlclose()期间不卸载库,而且在以后使用dlopen()又一次载入库时不初始化库中的静态变量。这个flag不是POSIX-2001标准。
RTLD_NOLOAD: 不载入库。

在Linux上,使用动态链接的应用程序需要和库libdl.so一起链接,也就是使用选项-ldl。但是,编译时不需要和动态装载的库一起链接.

遇到的一个问题:当我的一个模块在动态载入我的一个动态库 OpenMylib.so,然后动态库OpenMylib.so会执行库里面的Init() 初始化函数,而在这个Init中是其他动态库的函数接口调用,且我的OpenMylib.so也会被其他的模块动态加载,OpenMylib.so中的一些全局的变量会被其他模块使用,而我们在使用(void *)dlopen("./OpenMylib.so", RTLD_NOW );出现崩溃,说是非法的内存访问,我想这个应该是OpenMylib.so中使用的其他动态库Init相关接口,导致其他模块还没有加载好OpenMylib.so吧,于是我们改成(void *)dlopen("./OpenMylib.so", RTLD_NOW|RTLD_GLOBAL );就Ok了

2、Windows动态载入 DLL

Windows API 函数主要有 3 个, 分别是 LoadLibrary、 GetProcAddress 和FreeLibrary。

(void *)::LoadLibrary(path);
FARPROC GetProcAddress( HMODULE hModule,    LPCSTR lpProcName   );  // // DLL模块句柄, // 函数名
FreeLibrary(DLL 库的句柄);

若DLL不在调用方的同一目录下,可以用LoadLibrary(L"DLL绝对路径")加载。但若调用的DLL内部又调用另外一个DLL,此时调用仍会失败。解决办法是用LoadLibraryEx:
LoadLibraryEx("DLL绝对路径", NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
通过指定LOAD_WITH_ALTERED_SEARCH_PATH,让系统DLL搜索顺序从DLL所在目录开始。

猜你喜欢

转载自blog.csdn.net/Swallow_he/article/details/111264398
今日推荐