包含的頭文件:
#include <dlfcn.h>
使用的函數有以下4個:
1) void * dlopen( const char * pathname, int mode)
參數pathname: 動態庫so名稱;
參數mode: 打開方式,有以下選項
RTLD_DEEPBIND -- 動態庫里的函數優先調用本動態庫的符號,優先級甚至高於LD_PRELOAD
RTLD_LAZY -- 等有需要時才解析出符號,所以如果有未定義的符號,在沒調用之前也不執行解析
RTLD_NOW -- 在dlopen返回前,解析出所有的未定義符號,如果解析不出來,返回NULL
RTLD_GLOBAL 動態庫中符號表全局打開,因此符號可被其后打開的其它庫重定位
RTLD_LOCAL 與RTLD_GLOBAL作用相反,動態庫中符號表非全局打開,定義的符號不能被其后打開的其它庫重定位
返回值:
打開錯誤返回NULL
成功,返回庫引用
2) void* dlsym(void* handle,const char* symbol)
參數handle: 動態庫應用或者RTLD_NEXT(在當前庫之后load進來的動態庫中尋找第一次出現的符號)
參數symbol: 符號名稱
返回值:符號函數指針
3) int dlclose (void *handle)
關閉指定句柄的動態鏈接庫
4) char* dlerror();
返回值:返回加載失敗的報錯信息
實例:
plugin.h頭文件中定義接口
#ifndef __PLUGIN_H__ #define __PLUGIN_H__ #include "stdio.h" class IPlugin { public: virtual void print()=0; }; #endif
main.cpp
#include "plugin.h" #include <dlfcn.h> #include <stdlib.h> #include <stdio.h> typedef IPlugin* (*func)(); int main() { void* handle = dlopen("/home/hongrui/work/dlopen/libplugin.so", RTLD_NOW); if (!handle) { printf("dlopen:%s\n",dlerror()); return -1; } func getInterface = (func)dlsym(handle, "getInterface"); if (getInterface == NULL) { printf("dlsym:%s\n", dlerror()); return -1; } IPlugin* plugin = getInterface(); plugin->print();
dlclose(handle); return 0; }
編譯main.cpp 生成可執行文件
g++ main.cpp -o main -ldl
plugin.cpp是動態庫cpp
#include "plugin.h" #include "stdio.h" class CPlugin : public IPlugin { public: CPlugin() {} virtual ~CPlugin(){} virtual void print() { printf("this is plugin\n"); } }; extern "C" __attribute__ ((visibility("default"))) IPlugin* getInterface() { return new CPlugin; }
編譯plguin.cpp生成動態庫libplugin.so
g++ -fvisibility=hidden -fpic -shared plugin.cpp -o libplugin.so -ldl