linux環(huán)境下撤缴,庫(kù)文件包含靜態(tài)函數(shù)庫(kù)和動(dòng)態(tài)函數(shù)庫(kù)兩種:
靜態(tài)函數(shù)庫(kù):
這類庫(kù)的名字一般是libxxx.a坛猪;利用靜態(tài)函數(shù)庫(kù)編譯成的文件比較大,因?yàn)?strong>整個(gè)函數(shù)庫(kù)的所有數(shù)據(jù)都會(huì)被整合進(jìn)目標(biāo)代碼中,他的優(yōu)點(diǎn)就顯而易見(jiàn)了分衫,即編譯后的執(zhí)行程序不需要外部的函數(shù)庫(kù)支持模聋,因?yàn)樗惺褂玫暮瘮?shù)都已經(jīng)被編譯進(jìn)可執(zhí)行文件了肩民。當(dāng)然這也會(huì)成為他的缺點(diǎn),因?yàn)槿绻o態(tài)函數(shù)庫(kù)改變了链方,那么你的程序必須重新編譯持痰,而且體積也較大。
動(dòng)態(tài)函數(shù)庫(kù):
這類庫(kù)的名字一般是libxxx.so祟蚀,動(dòng)態(tài)庫(kù)又稱共享庫(kù);相對(duì)于靜態(tài)函數(shù)庫(kù)工窍,動(dòng)態(tài)函數(shù)庫(kù)在編譯的時(shí)候并沒(méi)有被編譯進(jìn)目標(biāo)代碼中,你的程序執(zhí)行到相關(guān)函數(shù)時(shí)才調(diào)用該函數(shù)庫(kù)里的相應(yīng)函數(shù)前酿,因此動(dòng)態(tài)函數(shù)庫(kù)所產(chǎn)生的可執(zhí)行文件比較小患雏。由于函數(shù)庫(kù)沒(méi)有被整合進(jìn)你的程序,而是程序運(yùn)行時(shí)動(dòng)態(tài)的申請(qǐng)并調(diào)用薪者,所以程序的運(yùn)行環(huán)境中必須提供相應(yīng)的庫(kù)纵苛。動(dòng)態(tài)函數(shù)庫(kù)的改變并不影響你的程序,所以動(dòng)態(tài)函數(shù)庫(kù)的升級(jí)比較方便言津。而且如果多個(gè)應(yīng)用程序都要使用同一函數(shù)庫(kù)攻人,動(dòng)態(tài)庫(kù)就非常適合,可以減小應(yīng)用程序的體積悬槽。
在開(kāi)發(fā)過(guò)程中引入庫(kù)的作用主要包括:
1.函數(shù)模塊的功能相同,實(shí)現(xiàn)代碼也相同,通過(guò)對(duì)它們進(jìn)行封裝為庫(kù)怀吻,方便模塊之間的調(diào)用,避免代碼重復(fù)初婆。
2.封裝另外一個(gè)目的是針對(duì)接口編程蓬坡,對(duì)實(shí)現(xiàn)代碼進(jìn)行保密猿棉,利于代碼保護(hù)和代碼升級(jí)。
第一節(jié):靜態(tài)函數(shù)庫(kù)
在linux中屑咳,靜態(tài)函數(shù)庫(kù)有固定的命名規(guī)則:lib+類庫(kù)名稱+.a萨赁。
把函數(shù)打包成.a靜態(tài)庫(kù)包括下面幾個(gè)步驟:
1.程序?qū)嵗?/h4>
/*************************************************************
FileName : myAddLib.h
FileFunc : 定義頭文件
Version : V0.1
Author : Sunrier
Date : 2012-04-28
Descp : Linux下實(shí)現(xiàn)靜態(tài)庫(kù)
*************************************************************/
#ifndef _MYADDLIB_H_
#define _MYADDLIB_H_
#ifdef __cplusplus
extern "C" {
#endif
int add(int ,int );
#ifdef __cplusplus
}
#endif
#endif
/*************************************************************
FileName : myAddLib.c
FileFunc : 定義靜態(tài)庫(kù)實(shí)現(xiàn)文件
Version : V0.1
Author : Sunrier
Date : 2012-04-28
Descp : Linux下實(shí)現(xiàn)靜態(tài)庫(kù)
*************************************************************/
#include <stdio.h>
int add(int iArg1,int iArg2)
{
printf("iArg1= %d , iAgr2= %d \n",iArg1,iArg2);
return (iArg1+iArg2);
}
2.制作靜態(tài)庫(kù)文件
/*************************************************************
FileName : myAddLib.h
FileFunc : 定義頭文件
Version : V0.1
Author : Sunrier
Date : 2012-04-28
Descp : Linux下實(shí)現(xiàn)靜態(tài)庫(kù)
*************************************************************/
#ifndef _MYADDLIB_H_
#define _MYADDLIB_H_
#ifdef __cplusplus
extern "C" {
#endif
int add(int ,int );
#ifdef __cplusplus
}
#endif
#endif
/*************************************************************
FileName : myAddLib.c
FileFunc : 定義靜態(tài)庫(kù)實(shí)現(xiàn)文件
Version : V0.1
Author : Sunrier
Date : 2012-04-28
Descp : Linux下實(shí)現(xiàn)靜態(tài)庫(kù)
*************************************************************/
#include <stdio.h>
int add(int iArg1,int iArg2)
{
printf("iArg1= %d , iAgr2= %d \n",iArg1,iArg2);
return (iArg1+iArg2);
}
1.編譯并生成目標(biāo)文件:gcc -c myAddLib.c -o myAddLib.o
2.生成歸檔文件:ar -rc libmyAddlib.a myAddLib.o
gcc -o myAddLib.o -c myAddLib.c
把源程序文件編譯成*.o。-c :只編譯并生成目標(biāo)文件兆龙。
ar -rc libmyAddLib.a myAddLib.o
執(zhí)行完后會(huì)生成一個(gè)libmyAddLib.a 文件
-c create的意思
-r replace的意思,表示當(dāng)插入的模塊名已經(jīng)在庫(kù)中存在,則替換同名的模塊.如果若干模塊中有一個(gè)模塊在庫(kù)中不存在,ar顯示一個(gè)錯(cuò)誤消息,并不替換其他同名模塊.默認(rèn)的情況下,新的成員增加在庫(kù)的結(jié)尾處,可以使用其他任選項(xiàng)來(lái)改變?cè)黾拥奈恢谩?/p>
3.使用靜態(tài)庫(kù)文件
/*************************************************************
FileName : testAddLib.c
FileFunc : 測(cè)試靜態(tài)庫(kù)文件
Version : V0.1
Author : Sunrier
Date : 2012-04-28
Descp : Linux下實(shí)現(xiàn)靜態(tài)庫(kù)
*************************************************************/
#include <stdio.h>
#include "myAddLib.h"
int main(int argc,char *argv[])
{
int iNumber1,iNumber2,iSum = 0;
iNumber1 = 10;
iNumber2 = 20;
iSum = add(iNumber1,iNumber2);
printf("iSum=%d\n".iSum);
printf("Hello Sunrier!\n");
return 0;
}
編譯:gcc -o testAddLib testAddLib.c -L. -lmyAddLib
-L指定庫(kù)路徑杖爽,-lmyAddLib指定庫(kù)的名稱,不包含lib.a兩部分紫皇。
第二節(jié):動(dòng)態(tài)函數(shù)庫(kù)
動(dòng)態(tài)函數(shù)庫(kù)又叫共享庫(kù)(share lib)慰安。它是在運(yùn)行時(shí),由系統(tǒng)的動(dòng)態(tài)函
數(shù)庫(kù)"lib/ld.so"負(fù)責(zé)動(dòng)態(tài)加載聪铺。
動(dòng)態(tài)函數(shù)庫(kù)也有自己的命名規(guī)則:lib+動(dòng)態(tài)庫(kù)名稱+.so+.+版本號(hào);比如libC++.so.6化焕。
動(dòng)態(tài)函數(shù)庫(kù)有兩種使用方式:動(dòng)態(tài)鏈接(隱式調(diào)用)和動(dòng)態(tài)調(diào)用(顯式調(diào)用,利用lib/ld.so提供的函數(shù)铃剔,利用函數(shù)指針撒桨,動(dòng)態(tài)調(diào)用一個(gè)類庫(kù)中包含的函數(shù),不需要知道動(dòng)態(tài)庫(kù)的頭文件)番宁。
隱式調(diào)用和顯示調(diào)用:
隱式調(diào)用使用方便簡(jiǎn)單, 但其和靜態(tài)庫(kù)相似, 在編譯期就和程序綁定了,靈活性差, 并且其生存期和進(jìn)程一樣, 進(jìn)程開(kāi)始, 調(diào)用開(kāi)始, 進(jìn)程結(jié)束, 動(dòng)態(tài)庫(kù)才卸載. 另外還需要將整個(gè)動(dòng)態(tài)庫(kù)全部加進(jìn)內(nèi)存.
顯式調(diào)用使用起來(lái)比較復(fù)雜, 但是卻可以在運(yùn)行期間選擇所需要調(diào)用的動(dòng)態(tài)鏈接庫(kù), 并且可以控制動(dòng)態(tài)庫(kù)生存期, 需要加載時(shí)候再加載, 用完了就可以卸掉, 而且不用將整個(gè)動(dòng)態(tài)庫(kù)都放進(jìn)內(nèi)存, 只要加載要用到的函數(shù)即可.
隱式調(diào)用:
編寫(xiě)動(dòng)態(tài)庫(kù)文件
/*************************************************************
FileName : myAddLib.h
FileFunc : 定義頭文件
Version : V0.1
Author : Sunrier
Date : 2012-05-02
Descp : Linux下實(shí)現(xiàn)動(dòng)態(tài)庫(kù)
*************************************************************/
#ifndef _MYADDLIB_H_
#define _MYADDLIB_H_
#ifdef __cplusplus
extern "C" {
#endif
int add(int ,int );
#ifdef __cplusplus
}
#endif
#endif
/*************************************************************
FileName : myAddLib.c
FileFunc : 定義動(dòng)態(tài)庫(kù)實(shí)現(xiàn)文件
Version : V0.1
Author : Sunrier
Date : 2012-05-02
Descp : Linux下實(shí)現(xiàn)動(dòng)態(tài)庫(kù)
*************************************************************/
#include <stdio.h>
int add(int iArg1,int iArg2)
{
printf("iArg1= %d , iAgr2= %d \n",iArg1,iArg2);
return (iArg1+iArg2);
}
制作庫(kù)文件:
1.gcc -fipc myAddLib.c -o myAddLib.o
2.gcc -share -o libmyAddLib.so.1 myAddlib.o
或者 gcc -fipc -share -o libmyAddLib.so.1 myAddLib.c
其中-fipc用來(lái)產(chǎn)生和位置無(wú)關(guān)代碼元莫,-share用來(lái)生成動(dòng)態(tài)共享庫(kù)
隱式使用動(dòng)態(tài)庫(kù)文件
/*************************************************************
FileName : testAddLib.c
FileFunc : 測(cè)試動(dòng)態(tài)庫(kù)文件
Version : V0.1
Author : Sunrier
Date : 2012-05-02
Descp : Linux下實(shí)現(xiàn)動(dòng)態(tài)庫(kù)
*************************************************************/
#include <stdio.h>
#include "myAddLib.h"
int main(int argc,char *argv[])
{
int iNumber1,iNumber2,iSum = 0;
iNumber1 = 10;
iNumber2 = 20;
iSum = add(iNumber1,iNumber2);
printf("iSum=%d\n",iSum);
printf("Hello Sunrier!\n");
return 0;
}
編譯目標(biāo)文件
gcc -o testAddLib testAddLib.c -L. -lmyAddLib
-L指定動(dòng)態(tài)函數(shù)庫(kù)的位置供查找,注意L后面還有'.'蝶押,表示動(dòng)態(tài)函數(shù)庫(kù)在本目錄下查找踱蠢。此時(shí)還不能立即./testAddLib,因?yàn)樵趧?dòng)態(tài)函數(shù)庫(kù)使用時(shí),會(huì)查找/usr/lib或/lib目錄下的動(dòng)態(tài)函數(shù)庫(kù),而此時(shí)我們生成的庫(kù)不在里邊棋电。
執(zhí)行可執(zhí)行文件
這個(gè)時(shí)候有好幾種方法可以讓他成功運(yùn)行:
最直接最簡(jiǎn)單的方法就是把libmyAddLib.so放到/usr/lib或/lib中去或者修改LD_LIBRARY_PATH環(huán)境變量文件茎截。
假設(shè)libmyAddLib.so在/home/Sunrier/lib
export LD_LIBRARY_PATH=/home/Sunrier/lib:$LD_LIBRARY_PATH
另外還可以在/etc/ld.so.conf文件里加入我們生成的庫(kù)的目錄,然后/sbin/ldconfig赶盔。
/etc/ld.so.conf是非常重要的一個(gè)配置文件企锌,里面存放的是鏈接器和加載器搜索共享庫(kù)時(shí)要檢查的目錄,默認(rèn)是從/usr/lib或/lib中讀取的,所以想要順利運(yùn)行,我們也可以把我們庫(kù)的目錄加入到這個(gè)文件中并執(zhí)行/sbin/ldconfig。
動(dòng)態(tài)調(diào)用:
根據(jù)前面提到的生成頭文件libmyAddLib.so文件于未。
/*************************************************************
FileName : testAddLib.c
FileFunc : 測(cè)試動(dòng)態(tài)庫(kù)文件
Version : V0.1
Author : Sunrier
Date : 2012-05-03
Descp : Linux下實(shí)現(xiàn)動(dòng)態(tài)庫(kù)
*************************************************************/
#include <stdio.h>
#include <dlfcn.h>
#define SOFILE "./libmyAddLib.so"
int main(int argc,char *argv[])
{
int iNumber1,iNumber2,iSum = 0;
void *hdl = NULL;//動(dòng)態(tài)庫(kù)句柄
hdl = dlopen(SOFILE,RTLD_LAZY);//打開(kāi)動(dòng)態(tài)鏈接庫(kù)
if( NULL==hdl )
{
printf("No libmyAddLib.so file\n");
return 1;
}
/*函數(shù)指針*/
int(*add)(int,int);
add = dlsym(hdl,"add");//查找符號(hào)表,定位共享函數(shù)
char *error = dlerror();//檢測(cè)錯(cuò)誤
if( error )
{
printf("No function!\n");
return 1;
}
iNumber1 = 10;
iNumber2 = 20;
iSum = add(iNumber1,iNumber2);//調(diào)用此共享函數(shù)
//iSum = (*add)(iNumber1,iNumber2);//調(diào)用此共享函數(shù)
printf("iSum=%d\n",iSum);
printf("Hello Sunrier!\n");
dlclose(hdl);//關(guān)閉共享庫(kù)
hdl =NULL;
return 0;
}
dlfcn.h包含了動(dòng)態(tài)調(diào)用函數(shù)庫(kù)的相關(guān)的函數(shù)撕攒。
void *dlopen (const char *file, int arg );
//打開(kāi)一個(gè)動(dòng)態(tài)庫(kù)的文件,arg代表打開(kāi)的方式
/*
RTLD_LAZY
Relocations are performed at an implementation-dependent time.
RTLD_NOW
Relocations are performed when the object is loaded.
RTLD_GLOBAL
All symbols are available for relocation processing of other modules.
RTLD_LOCAL
All symbols are not made available for relocation processing by other modules.*/
void *dlsym(void *handle, const char *name);
void *handle;
int *iptr, (*fptr)(int);
/* open the needed object */
handle = dlopen("/usr/home/me/libfoo.so.1", RTLD_LAZY);
/* find the address of function and data objects */
fptr = (int (*)(int))dlsym(handle, "my_function");
iptr = (int *)dlsym(handle, "my_object");
/* invoke function, passing value of integer as a parameter */
(*fptr)(*iptr);
char *dlerror(void);
/*If successful, dlerror() returns a null-terminated character string. Otherwise, NULL is returned.*/
int dlclose(void *handle);
/*If the referenced object was successfully closed, dlclose() returns 0.
If the object could not be closed, or if handle does not refer to an open object,
dlclose() returns a non-zero value. More detailed diagnostic information will be available through dlerror().*/
編譯和生成目標(biāo)文件:
#gcc testAddLib.c -o testAddLib -ldl
其中-ldl用于加載dl庫(kù)