采用dlopen、dlsym、dlclose加載動態鏈接庫【總結】
1、前言
為了使程序方便擴展,具備通用性,可以采用插件形式。采用異步事件驅動模型,保證主程序邏輯不變,將各個業務已動態鏈接庫的形式加載進來,這就是所謂的插件。linux提供了加載和處理動態鏈接庫的系統調用,非常方便。本文先從使用上進行總結,涉及到基本的操作方法,關於動態鏈接庫的本質及如何加載進來,需要進一步學習,后續繼續補充。如何將程序設計為插件形式,挖掘出主題和業務之間的關系,需要進一步去學習。
2、生產動態鏈接庫
編譯參數 gcc -fPIC -shared
例如將如下程序編譯為動態鏈接庫libcaculate.so,程序如下:
int add(int a,int b)
{
return (a + b);
}
int sub(int a, int b)
{
return (a - b);
}
int mul(int a, int b)
{
return (a * b);
}
int div(int a, int b)
{
return (a / b);
}
編譯如下: gcc -fPIC -shared caculate.c -o libcaculate.so

3、dlopen、dlsym函數介紹
在linux上man dlopen可以看到使用說明,函數聲明如下:
#include <dlfcn.h> void *dlopen(const char *filename, int flag); char *dlerror(void); void *dlsym(void *handle, const char *symbol); int dlclose(void *handle);
dlopen以指定模式打開指定的動態連接庫文件,並返回一個句柄給調用進程,dlerror返回出現的錯誤,dlsym通過句柄和連接符名稱獲取函數名或者變量名,dlclose來卸載打開的庫。 dlopen打開模式如下:
RTLD_LAZY 暫緩決定,等有需要時再解出符號
RTLD_NOW 立即決定,返回前解除所有未決定的符號。
采用上面生成的libcaculate.so,寫個測試程序如下:
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <dlfcn.h>
4
5 //動態鏈接庫路徑
6 #define LIB_CACULATE_PATH "./libcaculate.so"
7
8 //函數指針
9 typedef int (*CAC_FUNC)(int, int);
10
11 int main()
12 {
13 void *handle;
14 char *error;
15 CAC_FUNC cac_func = NULL;
16
17 //打開動態鏈接庫
18 handle = dlopen(LIB_CACULATE_PATH, RTLD_LAZY);
19 if (!handle) {
20 fprintf(stderr, "%s\n", dlerror());
21 exit(EXIT_FAILURE);
22 }
23
24 //清除之前存在的錯誤
25 dlerror();
26
27 //獲取一個函數
28 *(void **) (&cac_func) = dlsym(handle, "add");
29 if ((error = dlerror()) != NULL) {
30 fprintf(stderr, "%s\n", error);
31 exit(EXIT_FAILURE);
32 }
33 printf("add: %d\n", (*cac_func)(2,7));
34
35 cac_func = (CAC_FUNC)dlsym(handle, "sub");
36 printf("sub: %d\n", cac_func(9,2));
37
38 cac_func = (CAC_FUNC)dlsym(handle, "mul");
39 printf("mul: %d\n", cac_func(3,2));
40
41 cac_func = (CAC_FUNC)dlsym(handle, "div");
42 printf("div: %d\n", cac_func(8,2));
43
44 //關閉動態鏈接庫
45 dlclose(handle);
46 exit(EXIT_SUCCESS);
47 }
編譯選項如下:gcc -rdynamic -o main main.c -ldl
測試結果如下所示:


