动态加载库

  linux系统下有两种类型的库:1.静态库(.a);2.动态库(.so)。

  静态库会直接链接到可执行文件中,所以可执行文件运行时,不再需要静态库。

      动态库的使用分为两种:a.动态链接:在编译时声明动态库的存在,在运行期间链接动态库,意味着动态库在编译时对编译器可见。b.动态加载:在运行期间动态加载库,是由用户自己链接而不是由链接器,在编译期间可以不需要知道动态库的存在。

      工程项目中,如果需要设计成为一个插件化的架构,就需要使用动态加载库的机制。这需要使用到dlopen、dlsym、dlclose三个函数实现,但在编译时,需要使用-rdynamic选项。假设现在我们的工程想要将几个功能实现成插件,这些插件由配置文件控制需要加载的模块,在工程需要添加或者删除其中的某些模块时,都不要重新进行编译。在程序初始化时,就需要将这些模块信息加载进来,其dso.h头文件实现如下:

#include <vector>
using namespace std;

#define MODULE_OK 0
#define MODULE_ERR 1

#define MAGIC_MAJOR_NUMBER 20170515
#define MAGIC_MINOR_NUMBER 0

#define STANDEAD_MODULE_STUFF MAGIC_MAJOR_NUMBER, \
                              MAGIC_MINOR_NUMBER, \
                              __FILE__

typedef struct Module{
   int   version;                   //主版本号
   int   minor_version;         //子版本号
   const char   *name;        //模块名
   void (*init)(Module *);    //初始化函数
   int   (*handle)(void *);    //处理函数
}Module;

Module* dso_load(const char *path, const char *name);

   dso.cpp:

Module* dos_load(const char *path, const char *name)
{
         char *npath = strcat2(3, path, name, ".so");
        
         char *handle = NULL;
         if((handle = (dlopen(npath, RTLD_GLOBAL|RTLD_NOW)) == NULL)
         {
                LOG(LOG_LEVEL_ERROR, "load module fail(dlopen): %s",dlerror());
         }

         char *rv = NULL;
         if((rv = dlsym(handle, name)) == NULL)
         {
                LOG(LOG_LEVEL_ERROR, "load module fail(dlsym): %s", dlerror());
         }  

         module = (Module *)rv;
         module->init(module);
}

  其中,dlopen的函数原型是:

void *dlopen(const char *path, int mode);

  dlopen以指定的mode模式打开path指定的动态链接库,并返回这个动态链接库的句炳。该函数主要用来加载动态库中的符号,这些符号是在程序编译时不知道的。mode指定了解析的方式:RTLD_LAZY、RTLD_NOW和作用范围:RTLD_GLOBAL、RTLD_LOCAL。RTLD_LAZY是对库中符号延迟解析,等由需要的时候再进行解析。RTLD_NOW是立即将所有符号导出。RTLD_GLOBAL是允许到处符号,使库中解析的变量在随后的其它动态链接库中可以使用。

  dlsym的函数原型是:

void* dlsym(void* handle, const char *symbol);

  dlsym的作用是获取动态库中的函数地址和变量地址。

      

posted on 2017-05-15 01:25  残余的光  阅读(637)  评论(0编辑  收藏  举报

导航