動態 庫(Dynamic Link Library)(Linux下稱共享對象技術Share Object)的使用,其目的是減小程序大小,節省磁盤空間。Linux下的動態庫文件命名通常爲<name>.so,或 <name>.so.<ver>。 下面主要對動態庫的製作及使用作一個簡單介紹。
1, 動 態庫函數的製作.
1.1 動態庫中的函數定義跟普通函數沒什麼區別. 如下:
//func.c
void print(char *buf)
{
printf(“Hello World: %s/n”,buf);
}
1.2 動態庫的編譯.
有兩種編譯方式:
(a) gcc -shared -fpic -o libfunc.so func.c
(b) gcc -c -fpic -o func.o func.c
gcc -shared -o libfunc.so func.o
值得說明的是: 這裏的-fpic 表示將 目標編譯成可重入的格式, pic 是position indepent code 的簡稱. 如果不加上這個選項, 在執行使用這個動態庫的時候, 會出現類似如下的錯誤:
error while loading shared libraries:/apps/src/demo/libfunc.so cannot restore segment prot after reloc: Permission denied
-shared 表 示鏈接成動態庫. 動態庫目標文件的命名跟靜態庫一樣, 只是將擴展名該爲so 即可, 如: libNAME.so
2, 動態庫的使用.
使用動態庫中的函數有兩種調用方式:靜態調用和動態調用。
2.1 靜態調用,也稱爲隱式調用,由編譯器在編譯時完成對動態庫加載和程序結束時動態庫卸載的編碼。 請看如下代碼:
//test.c
void print(); // 函數聲明, 在動 態庫libfunc.so 中定義.
int main(void)
{
print();
return 0;
}
2.2 動態調用,使用dl系列函數,完成對動態庫函數的調用。
2.2.1 重要的dlfcn.h頭文件
LINUX下使用動態鏈接庫,源程序需要包含dlfcn.h頭文件,此文件定義了調用動態鏈接庫的函數的原型。
2.2.2 dlerror
原型爲: const char *dlerror(void);
當動態鏈接庫操作函數執行失敗時,dlerror可以返回出錯信息,返回值爲NULL時表示操作函數執行成功。
2.2.3 dlopen
原型爲: void *dlopen (const char *filename, int flag);
dlopen用於打開指定名字(filename)的動態鏈接庫,並返回操作句柄。
filename: 如果名字不以/開頭,則非絕對路徑名,將按下列先後順序查找該文件。
(1) 用戶環境變量中的LD_LIBRARY_PATH值;
(2) 動態鏈接緩衝文件/etc/ld.so.cache
(3) 目錄/lib,/usr/lib
flag表示在什麼時 候解決未定義的符號(調用)。取值有兩個:
1) RTLD_LAZY : 表明在動態鏈接庫的函數代碼執行時解決。
2) RTLD_NOW : 表明在dlopen返回前就解決所有未定義的符號,一旦未解決,dlopen將返回錯誤。
dlopen調用失敗時,將返回NULL值,否則返回的是操作句柄。
2.2.4 dlsym : 取函數執行地址
原型爲: void *dlsym(void *handle, char *symbol);
dlsym根據動態鏈接庫操作句柄(handle)與符號(symbol),返回符號對應的函數的執行代碼地址。由此地址,可以帶參數執行相應的函數。
如 程序代碼: void (*print_func)(char *buf); /* 說明一下要調用的動態函數print_func*/
print_func=dlsym("libfunc.so","print"); /* 打開libfunc.so共享庫,取print函數地址 */
print_func("John"); /* 調用print_func函數 */
2.2.5 dlclose : 關閉動態鏈接庫
原型爲: int dlclose (void *handle);
dlclose用於關閉指定句柄的動態鏈接庫,只有當此動態鏈接庫的使用計數爲0時,纔會真正被系統卸載。
2.3編譯:
gcc -L/apps/src/demo/ test.c -lfunc -o test
上面這條編譯鏈接指令, 我們都非常熟悉了. 接 下來就可以執行test 文件了.
很不幸, 當 我們敲下:
./test
時, 問 題又出來了:
./test: error while loading shared libraries: libfunc.so: cannot open shared object file: No such file or directory
很明顯, 是 動態庫的路徑不正確, 編譯時用-L 指定的庫文件路徑, 在執行文件時不起作用了. 怎樣讓可執行文件找到我們自己建立的庫呢? 這 裏有幾種方法:
( a ) 將庫文件libfunc.so 拷貝 到/usr/lib 或 /lib 或 /usr/local/lib 下, 默認情況下, 系統從這幾 個地方尋找庫文件.
( b ) 導出 符號LD_LIBRARY_PATH, 如export LD_LIBRARY_PATH=/apps/src/demo/
如果有多條路徑, 用 ‘:’ 分割.
( c ) 將庫文件的路徑添加到 /etc/ld.so.conf 中去, 並執行/sbin/ldconfig
( d ) 在編譯鏈接時添加選項目 -Wl,--rpath 指 定, 如:
gcc -Wl,--rpath,/apps/src/demo/ -L/apps/src/demo/ test.c -lfunc -o test
或者
gcc -Wl,--rpath -Wl,/apps/src/demo/ -L/apps/src/demo/ test.c -lfunc -o test
補充:查看文件使用的動態 庫用ldd命令.
參考文獻:
GCC: the complete reference