from : http://hi.baidu.com/xiaochongs/blog/item/23a70b5592e662c4b645aef2.html
和Windows系統(tǒng)一樣Linux也有靜態(tài)/動態(tài)鏈接庫,下面介紹創(chuàng)建和使用方法:
假設(shè)有下面幾個文件:
頭文件String.h,聲明相關(guān)函數(shù)原形,內(nèi)容如下:
Strlen.c:函數(shù)Strlen的實現(xiàn),獲取給定字符串的長度,內(nèi)容如下:
Strlnen.c:函數(shù)StrNlen的實現(xiàn),獲取給定字符串的長度,如果輸入字符串的長度大于指定的最大長度,則返回最大長度,否者返回字符串的實際長度,內(nèi)容如下:
生成靜態(tài)庫:
利用GCC生成對應(yīng)目標(biāo)文件:
gcc –c Strlen.c Strnlen.c
如果對應(yīng)的文件沒有錯誤,gcc會對文件進(jìn)行編譯生成Strlen.o和Strnlen.o兩個目標(biāo)文件(相當(dāng)于windows下的obj文件)。然后用ar創(chuàng)建一個名字為libstr.a的庫文件,并把Strlen.o 和Strnlen.o的內(nèi)容插入到對應(yīng)的庫文件中。,相關(guān)命令如下:
ar –rc libstr.a Strlen.o Strnlen.o
命令執(zhí)行成功以后,對應(yīng)的靜態(tài)庫libstr.a已經(jīng)成功生成。
/***********************************
Filename : String.h Description : Author : HCJ Date : 2006-5-7 ************************************/ int Strlen(char *pStr); int StrNlen(char *pStr, unsigned long ulMaxLen); |
/**************************************
Filename : get string length Description : Author : HCJ Date : 2006/5/7 **************************************/ #include<stdio.h> #include<assert.h> int Strlen(char *pStr) { unsigned long ulLength; assert(NULL != pStr); ulLength = 0; while(*pStr++) { ulLength++; } return ulLength; } |
**********************************************
Fileneme: mystrnlen.c Description: get input string length,if string large max length input return max length, else real length Author: HCJ Date : 2006-5-7 **********************************************/ #include<stdio.h> #include<assert.h> int StrNlen(char *pStr, unsigned long ulMaxLen) { unsigned long ulLength; assert(NULL != pStr); if(ulMaxLen <= 0) { printf("Wrong Max Length!\n"); return -1; } ulLength = 0; while(*pStr++ && ulLength < ulMaxLen) { ulLength++; } return ulLength; } |
生成動態(tài)鏈接庫:
gcc -fpic -shared -o libstr.so Strlen.c Strnlen.c
-fpic 使輸出的對象模塊是按照可重定位地址方式生成的。
-shared指定把對應(yīng)的源文件生成對應(yīng)的動態(tài)鏈接庫文件libstr.so文件。
對應(yīng)的鏈接庫已經(jīng)生成,下面看一下如何使用對應(yīng)的鏈接庫。
靜態(tài)庫的使用:
假設(shè)有下面的文件要使用對應(yīng)的的靜態(tài)庫:
編譯生成對應(yīng)的目標(biāo)文件:
gcc -c -I/home/hcj/xxxxxxxx main.c
生成可執(zhí)行文件:
gcc -o main1 -L/home/hcj/xxxxxxxx main.o libstr.a
其中-I/home/hcj/xxxxxxxx和-L/home/hcj/xxxxxxxx是通過-I和-L指定對應(yīng)的頭文件和庫文件的路徑。libstr.a是對應(yīng)的靜態(tài)庫的名稱。這樣對應(yīng)的靜態(tài)庫已經(jīng)編譯到對應(yīng)的可執(zhí)行程序中。執(zhí)行對應(yīng)的可執(zhí)行文件便可以對應(yīng)得函數(shù)調(diào)用的結(jié)果。
/*****************************************
FileName: main.c Description: test static/dynamic library Author: HCJ Date : 2005-5-7 ******************************************/ #include<stdio.h> #include <String.h> //靜態(tài)庫對應(yīng)函數(shù)的頭文件 int main(int argc, char* argv[]) { char str[] = {"hello world"}; unsigned long ulLength = 0; printf("The string is : %s\n", str); ulLength = Strlen(str); printf("The string length is : %d(use Strlen)\n", ulLength); ulLength = StrNlen(str, 10); printf("The string length is : %d(use StrNlen)\n", ulLength); return 0; } |
動態(tài)庫的分為隱式調(diào)用和顯式調(diào)用兩種調(diào)用方法:
隱式調(diào)用的使用使用方法和靜態(tài)庫的調(diào)用差不多,具體方法如下:
gcc -c -I/home/hcj/xxxxxxxx main.c
gcc -o main1 -L/home/hcj/xxxxxxxx main.o libstr.so //這里是*.so
在這種調(diào)用方式中,需要維護(hù)動態(tài)鏈接庫的配置文件/etc/ld.so.conf來讓動態(tài)鏈接庫為系統(tǒng)所使用,通常將動態(tài)鏈接庫所在目錄名追加到動態(tài)鏈接庫配置文件中。否則在執(zhí)行相關(guān)的可執(zhí)行文件的時候就會出現(xiàn)載入動態(tài)鏈接庫失敗的現(xiàn)象。在編譯所引用的動態(tài)庫時,可以在gcc采用 –l或-L選項或直接引用所需的動態(tài)鏈接庫方式進(jìn)行編譯。在Linux里面,可以采用ldd命令來檢查程序依賴共享庫。
顯式調(diào)用:
/*****************************************
FileName: main2.c Description: test static/dynamic library Author: HCJ Date : 2005-5-7 ******************************************/ #include<stdio.h> #include<dlfcn.h> int main(int argc, char* argv[]) { //define function pointor int (*pStrlenFun)(char* pStr); //聲明對應(yīng)的函數(shù)的函數(shù)指針 int (*pStrnlenFun)(char* pStr, int ulMaxLen); char str[] = {"hello world"}; unsigned long ulLength = 0; void *pdlHandle; char *pszErr; pdlHandle = dlopen("./libstr.so", RTLD_LAZY); //加載鏈接庫/libstr.so if(!pdlHandle) { printf("Failed load library\n"); } pszErr = dlerror(); if(pszErr != NULL) { printf("%s\n", pszErr); return 0; } //get function from lib pStrlenFun = dlsym(pdlHandle, "Strlen"); //獲取函數(shù)的地址 pszErr = dlerror(); if(pszErr != NULL) { printf("%s\n", pszErr); return 0; } pStrnlenFun = dlsym(pdlHandle, "StrNlen"); pszErr = dlerror(); if(pszErr != NULL) { printf("%s\n", pszErr); return 0; } printf("The string is : %s\n", str); ulLength = pStrlenFun(str); //調(diào)用相關(guān)的函數(shù) printf("The string length is : %d(use Strlen)\n", ulLength); ulLength = pStrnlenFun(str, 10); printf("The string length is : %d(use StrNlen)\n", ulLength); dlclose(pdlHandle); return 0; } |
gcc -o mian2 -ldl main2.c
相關(guān)函數(shù)的說明如下:
(1)dlopen()
第一個參數(shù):指定共享庫的名稱,將會在下面位置查找指定的共享庫。
-環(huán)境變量LD_LIBRARY_PATH列出的用分號間隔的所有目錄。
-文件/etc/ld.so.cache中找到的庫的列表,用ldconfig維護(hù)。
-目錄usr/lib。
-目錄/lib。
-當(dāng)前目錄。
第二個參數(shù):指定如何打開共享庫。
-RTLD_NOW:將共享庫中的所有函數(shù)加載到內(nèi)存
-RTLD_LAZY:會推后共享庫中的函數(shù)的加載操作,直到調(diào)用dlsym()時方加載某函數(shù)
(2)dlsym()
調(diào)用dlsym時,利用dlopen()返回的共享庫的phandle以及函數(shù)名稱作為參數(shù),返回要加載函數(shù)的入口地址。
(3)dlerror()
該函數(shù)用于檢查調(diào)用共享庫的相關(guān)函數(shù)出現(xiàn)的錯誤。
這樣我們就用簡單的例子說明了在Linux下靜態(tài)/動態(tài)庫的創(chuàng)建和使用。