以前總是不明白爲什麼不同的模塊是相互獨立的編譯,相互之間不存在的調用關係, 怎麼做到在使用的時候加載不使用的時候卸載掉? 現在總算是明白了。其實就是將一個功能做成一個動態庫,在window中叫dll,在Unix/Linux中叫做so。通過配置在運行的時候,在運行的時候,通過一些特殊的函數對dll或者so進行操作。找到函數的地址,調用函數。在使用函數的時候找函數,不是使用的時候釋放就可以了。
我也找不到合適的列子。我直接上代碼吧。通過輸入不同的so或者dll執行不同的內容。本文件以Unix/Linux中的C語言代碼爲例子。使用到的知識很簡單。就是dlopen和dlsym函數。所有的函數都在dlfcn.h頭文件中。
void * dlopen( const char * pathname, int mode);
pathname:so或者dll文件的路徑,在Linux中必須是以"./"或者"../"開始的相對路徑 或者 以"/"開始的絕對路徑
mode:解析so或者dll文件的方式,可以取以下值
RTLD_LAZY:在dlopen返回前,對於動態庫中的未定義的符號不執行解析(只對函數引用有效,對於變量引用總是立即解析)。
RTLD_NOW: 需要在dlopen返回前,解析出所有未定義符號,如果解析不出來,在dlopen會返回NULL
打開錯誤返回NULL
成功,返回庫引用
.
dlsym(void *dp, char * funtionname);
dp:已經打開的so或者dll文件句柄
functionname:要解析的文件名字
數返回值是void*,指向函數的地址
dlclose(void *dp)
關閉指定句柄的動態鏈接庫,只有當此動態鏈接庫的使用計數爲0時,纔會真正被系統卸載。
主函數
#include <stdio.h>
#include <dlfcn.h>
#include "dll.h"
int main(){
void *dp;
char *err;
char fname[20];
dll p;
void (*init)(dll *p);
printf("請輸入要加載模塊的名字:model1 或者model2");
scanf("%s", fname);
sprintf("./%s^", fname);
dp = dlopen(fname, RTLD_LAZY);//打開動態庫。
if( NULL == dp) {
printf("%s\n", dlerror());
exit(1);
}
init = dlsym(dp, "init");//找到init函數的地址。
init(&p);
printf("%s\n", p.name);
p.done();//注意這裏done雖然是so中函數。卻沒有使用使用dlsym找done函數的地址。 err = dlerror(); dlclose(dp);}model1.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "dll.h"
void done(){
printf("This is test module 1!\n");
}
void init(dll *p){
p->name = (char *)calloc(3, sizeof(char));
strcpy(p->name, "so1");
p->done = done;
}
model1.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "dll.h"
void done(){
printf("This is test module 2!\n");
}
void init(dll *p){
p->name = (char *)calloc(3, sizeof(char));
strcpy(p->name, "so2");
p->done = done;
}
dll.h 頭文件
typedef struct dll{
char * name;
void (*done)() ;
}dll;
以下爲gcc的編譯過程
gcc -rdynamic -o test test.c dll.h -ldl //-ldl (指定dl庫)因爲dlopen和dlsym在dl庫中
gcc -shared -o module1.so module1.c dll.h
gcc -shared -o $module2.so module2.c dll.h
將會根據輸入的不同顯調用不同的dll中的函數。
.
blog: http://blog.csdn.net/rentiansheng/article/details//8606125