和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下靜態/動態庫的建立和使用