from : http://hi.baidu.com/xiaochongs/blog/item/23a70b5592e662c4b645aef2.html
和Windows系統一樣Linux也有靜態/動態鏈接庫,下面介紹創建和使用方法:
假設有下面幾個文件:
頭文件String.h,聲明相關函數原形,內容如下:
Strlen.c:函數Strlen的實現,獲取給定字符串的長度,內容如下:
Strlnen.c:函數StrNlen的實現,獲取給定字符串的長度,如果輸入字符串的長度大于指定的最大長度,則返回最大長度,否者返回字符串的實際長度,內容如下:
生成靜態庫:
利用GCC生成對應目標文件:
gcc –c Strlen.c Strnlen.c
如果對應的文件沒有錯誤,gcc會對文件進行編譯生成Strlen.o和Strnlen.o兩個目標文件(相當于windows下的obj文件)。然后用ar創建一個名字為libstr.a的庫文件,并把Strlen.o 和Strnlen.o的內容插入到對應的庫文件中。,相關命令如下:
ar –rc libstr.a Strlen.o Strnlen.o
命令執行成功以后,對應的靜態庫libstr.a已經成功生成。
/***********************************
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;
}
|
生成動態鏈接庫:
gcc -fpic -shared -o libstr.so Strlen.c Strnlen.c
-fpic 使輸出的對象模塊是按照可重定位地址方式生成的。
-shared指定把對應的源文件生成對應的動態鏈接庫文件libstr.so文件。
對應的鏈接庫已經生成,下面看一下如何使用對應的鏈接庫。
靜態庫的使用:
假設有下面的文件要使用對應的的靜態庫:
編譯生成對應的目標文件:
gcc -c -I/home/hcj/xxxxxxxx main.c
生成可執行文件:
gcc -o main1 -L/home/hcj/xxxxxxxx main.o libstr.a
其中-I/home/hcj/xxxxxxxx和-L/home/hcj/xxxxxxxx是通過-I和-L指定對應的頭文件和庫文件的路徑。libstr.a是對應的靜態庫的名稱。這樣對應的靜態庫已經編譯到對應的可執行程序中。執行對應的可執行文件便可以對應得函數調用的結果。
/*****************************************
FileName: main.c
Description: test static/dynamic library
Author: HCJ
Date : 2005-5-7
******************************************/
#include<stdio.h>
#include <String.h> //靜態庫對應函數的頭文件
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;
}
|
動態庫的分為隱式調用和顯式調用兩種調用方法:
隱式調用的使用使用方法和靜態庫的調用差不多,具體方法如下:
gcc -c -I/home/hcj/xxxxxxxx main.c
gcc -o main1 -L/home/hcj/xxxxxxxx main.o libstr.so //這里是*.so
在這種調用方式中,需要維護動態鏈接庫的配置文件/etc/ld.so.conf來讓動態鏈接庫為系統所使用,通常將動態鏈接庫所在目錄名追加到動態鏈接庫配置文件中。否則在執行相關的可執行文件的時候就會出現載入動態鏈接庫失敗的現象。在編譯所引用的動態庫時,可以在gcc采用 –l或-L選項或直接引用所需的動態鏈接庫方式進行編譯。在Linux里面,可以采用ldd命令來檢查程序依賴共享庫。
顯式調用:
/*****************************************
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); //聲明對應的函數的函數指針
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"); //獲取函數的地址
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); //調用相關的函數
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
用gcc編譯對應的源文件生成可執行文件,-ldl選項,表示生成的對象模塊需要使用共享庫。執行對應得文件同樣可以得到正確的結果。
相關函數的說明如下:
(1)dlopen()
第一個參數:指定共享庫的名稱,將會在下面位置查找指定的共享庫。
-環境變量LD_LIBRARY_PATH列出的用分號間隔的所有目錄。
-文件/etc/ld.so.cache中找到的庫的列表,用ldconfig維護。
-目錄usr/lib。
-目錄/lib。
-當前目錄。
第二個參數:指定如何打開共享庫。
-RTLD_NOW:將共享庫中的所有函數加載到內存
-RTLD_LAZY:會推后共享庫中的函數的加載操作,直到調用dlsym()時方加載某函數
(2)dlsym()
調用dlsym時,利用dlopen()返回的共享庫的phandle以及函數名稱作為參數,返回要加載函數的入口地址。
(3)dlerror()
該函數用于檢查調用共享庫的相關函數出現的錯誤。
這樣我們就用簡單的例子說明了在Linux下靜態/動態庫的創建和使用。