時間:2015-06-28 00:00:00 來源:IT貓撲網(wǎng) 作者:網(wǎng)管聯(lián)盟 我要評論(0)
一、為什么要使用庫文件
我們在實際編程工作中肯定會遇到這種情況:有幾個項目里有一些函數(shù)模塊的功能相同,
實現(xiàn)代碼也相同,也是我們所說的重復代碼。比如,很多項目里都有一個用戶驗證的功能。
代碼段如下:
//UserLogin.h文件,提供函數(shù)聲明
int IsValidUser(char* username, int namelen);
//UserLogin.c文件,實現(xiàn)對用戶信息的驗證
int IsValidUser(char* username, int namelen)
{
int IsValid = 0;
/*下面是具體的處理代碼,略去*/
return IsValid
}
如果每個項目都保存著這兩個UserLogin.h和UserLogin.c文件,會有以下幾個
弊端:
1、每個項目里都有重復的模塊,造成代碼重復。
2、代碼的重用性不好,一旦IsValidUser的代碼發(fā)生了變化,為了保持設計的一致性,
我們還要手工修改其他項目里的UserLogin.c文件,既費時又費力,還容易出錯。
庫文件就是對公共代碼的一種組織形式。
為了解決上面兩個弊端,就提出了用庫文件存放公共代碼的解決方案,其要點就是
把公共的(也就是可以被多次復用的)目標代碼從項目中分離出來,統(tǒng)一存放到庫文件中,
項目要用到這些代碼的時候,在編譯或者運行的時候從庫文件中取得目標代碼即可。庫文件
又分兩種:靜態(tài)庫和動態(tài)庫。
二、靜態(tài)庫與動態(tài)庫
如果程序是在編譯時加載庫文件的,就是使用了靜態(tài)庫。如果是在運行時加載目標代碼,
就成為動態(tài)庫。換句話說,如果是使用靜態(tài)庫,則靜態(tài)庫代碼在編譯時就拷貝到了程序的代碼段,
程序的體積會膨脹。如果使用動態(tài)庫,則程序中只保留庫文件的名字和函數(shù)名,在運行時去查找
庫文件和函數(shù)體,程序的體積基本變化不大。
靜態(tài)庫的原則是"以空間換時間",增加程序體積,減少運行時間;
動態(tài)庫則是"以時間換空間",增加了運行時間,但減少了程序本身的體積。
下面我們就以實際例子來看看如何使用這兩種庫.
三、靜態(tài)庫的編寫和使用
1、概述
靜態(tài)庫文件的擴展名一般為.a,其編寫步驟很簡單。
?、啪帉懞瘮?shù)代碼
⑵編譯生成各目標文件
?、怯胊r文件對目標文件歸檔,生成靜態(tài)庫文件。
注意歸檔文件名必須以lib打頭。
使用要點:
?、旁趃cc 的-I參數(shù)后加上靜態(tài)庫頭文件的路徑。
?、圃趃cc 的-L參數(shù)后加上庫文件所在目錄
⑶在gcc 的-l參數(shù)后加上庫文件名,但是要去掉lib和.a擴展名。
比如庫文件名是libtest.a 那么參數(shù)就是 -l test
2、編寫最簡單的靜態(tài)庫文件
編寫如下兩個文件,注意放在同一目錄中
myalib.h?? //靜態(tài)庫頭文件
myalib.c?? //靜態(tài)庫實現(xiàn)文件
//myalib.h 文件的內(nèi)容
void test();
//myalib.c 文件的內(nèi)容
#inlcude
void test()
{
printf("test\n");
}
3、制作庫文件
?、派赡繕宋募?/p>
gcc -c myalib.c
執(zhí)行完后會生成一個myalib.o文件
⑵用ar命令歸檔,格式為ar -rc <生成的檔案文件名> <.o文件名列表>
再次提醒,歸檔文件名一定要以lib打頭, .a結(jié)尾。
ar -rc libtest.a myalib.o
執(zhí)行完后會生成一個libtest.a文件
4、使用庫文件
⑴編寫一個測試程序main.c,內(nèi)容為
//main.c 測試靜態(tài)庫調(diào)用的程序
#include "myalib.h"?? //要把函數(shù)的頭文件包含進來,否則編譯時會報錯
int main(int argc,char* argv[])
{
test();
return 0;
}
?、凭幾g目標文件,注意要把靜態(tài)庫頭文件的路徑加到-I參數(shù)里面
gcc -I /root/exercise -o main.o -c main.c
現(xiàn)在生成了一個main.o文件
⑶生成可執(zhí)行文件,注意要把靜態(tài)庫文件的路徑加到-L參數(shù)里面,
把庫文件名(去掉打頭的lib和結(jié)尾的.a)加到-l參數(shù)后面。如下面所示
gcc -o main -L/root/exercise?? main.o -ltest
此時就會生成一個名為main的可執(zhí)行文件
另外,注意- l參數(shù)好象應該加到輸入文件名的后面,否則會報錯。
比如gcc -o main -L/root/exercise?? -ltest main.o就會提示
main.o(.text+0x11): In function `main'':
: undefined reference to `test''
collect2: ld returned 1 exit status
原因我還不清楚:-)
?、葓?zhí)行可執(zhí)行文件查看效果
執(zhí)行./main, 輸出
test
說明執(zhí)行成功。
四、動態(tài)庫的編寫
1、概述
動態(tài)庫一般以.so結(jié)尾,就是shared object的意思.
其基本生成步驟為
?、啪帉懞瘮?shù)代碼
?、凭幾g生成動態(tài)庫文件,要加上 -shared 和 -fpic 選項 ,
庫文件名以lib開頭, 以.so 結(jié)尾。
使用方式分為兩種: 隱式調(diào)用和顯示調(diào)用
隱式調(diào)用類似于靜態(tài)庫的使用,但需修改動態(tài)鏈接庫的配置文件/etc/ld.so.conf;
顯示調(diào)用則是在主程序里使用dlopen、dlsym、dlerror、dlclose等系統(tǒng)函數(shù)。
具體的調(diào)用方式會在 "五、動態(tài)庫的調(diào)用" 中詳細說明.
2、編寫最簡單的動態(tài)庫文件
為了便于對照, 我們?nèi)匀徊捎渺o態(tài)庫中的文件做例子.
編寫如下兩個文件,注意放在同一目錄中
myalib.h?? //靜態(tài)庫頭文件
myalib.c?? //靜態(tài)庫實現(xiàn)文件
//myalib.h 文件的內(nèi)容
void test();
//myalib.c 文件的內(nèi)容
#inlcude
void test()
{
printf("test\n");
}
3、編譯生成動態(tài)庫 ,庫文件名以lib開頭, 以.so 結(jié)尾。
gcc -fpic -shared -o libtest.so myalib.c
此時就生成一個libtest.so文件
五、動態(tài)庫的隱式調(diào)用
隱式調(diào)用的含義是代碼里不出現(xiàn)庫文件名,就是說這個代碼和
調(diào)用靜態(tài)庫的代碼是類似的。
1、編寫測試文件
//main.c 測試動態(tài)庫隱式調(diào)用的程序
#include "myalib.h"?? //要把函數(shù)的頭文件包含進來,否則編譯時會報錯
int main(int argc,char* argv[])
{
test();
return 0;
}
2、 編譯測試程序,與靜態(tài)庫類似,要把頭文件的路徑加到-I參數(shù)里面
gcc -I /root/exercise -o main.o -c main.c
現(xiàn)在生成了一個main.o文件
3、連接生成測試程序
gcc -o main -L/root/exercise?? main.o -ltest
現(xiàn)在生成了一個main文件
4、執(zhí)行測試程序
./main
此時出現(xiàn)提示
./main: error while loading shared libraries: libtest.so: cannot open shared object file: No such file or directory。
這個原因就是程序運行時并不知道動態(tài)庫所在的路徑,因此自然找不到。
解決這個問題的辦法有三種。見下節(jié)
六、使動態(tài)庫被系統(tǒng)共享的三種辦法
(再次說明: 本節(jié)參考了計算機世界網(wǎng)雨亦奇的文章"LINUX動態(tài)鏈接庫高級應用"
地址http://www.ccw.com.cn/htm/center/prog/02_3_13_3_2.asp)
(1)拷貝動態(tài)鏈接庫到系統(tǒng)共享目錄下,或在系統(tǒng)共享目錄下為該動態(tài)鏈接庫
建立連接(硬連接或符號連接均可,常用符號連接).這里說的系統(tǒng)共享目錄,
指的是LINUX動態(tài)鏈接庫存放的目錄,包括
/lib,/usr/lib以及/etc/ld.so.conf文件內(nèi)所列的一系列目錄.
#p#副標題#e#
實例:執(zhí)行
# cp libtest.so /lib
# ldconfig
或:
# ln -s `pwd`/libtest.so /lib
# ldconfig
注意pwd前后有兩個反引號`,其目的是取得pwd命令的輸出,即當前目錄.
此時再執(zhí)行main,即可成功.
(2)將動態(tài)鏈接庫所在目錄名追加到動態(tài)鏈接庫配置文件/etc/ld.so.conf中.
# pwd >> /etc/ld.so.conf
# ldconfig
此時再執(zhí)行main,即可成功.
(3)利用動態(tài)鏈接庫管理命令ldconfig,強制其搜索指定目錄,并更新緩存文件,便于動態(tài)裝入.
# ldconfig `pwd`
此時再執(zhí)行main,即可成功.
要注意,第三種方法雖然有效,但效果是暫時的,供程序測試還可以,一旦再度運行l(wèi)dconfig,
則緩存文件內(nèi)容可能改變,所需的動態(tài)鏈接庫可能不被系統(tǒng)共享了.
而且無論哪種辦法,其實質(zhì)都是用ldconfig命令把動態(tài)庫文件
所在路徑加入到系統(tǒng)庫列表中,(前兩種永久,第三種臨時)
補充:ldconfig命令的作用(見最后說明)
關鍵詞標簽:linux庫文件相關閱讀
熱門文章 安裝紅帽子RedHat Linux9.0操作系統(tǒng)教程 Tomcat9.0如何安裝_Tomcat9.0環(huán)境變量配置方法 多種操作系統(tǒng)NTP客戶端配置 Linux操作系統(tǒng)修改IP
人氣排行 Linux下獲取CPUID、硬盤序列號與MAC地址 dmidecode命令查看內(nèi)存型號 linux tc實現(xiàn)ip流量限制 安裝紅帽子RedHat Linux9.0操作系統(tǒng)教程 linux下解壓rar文件 lcx.exe、nc.exe、sc.exe入侵中的使用方法 Ubuntu linux 關機、重啟、注銷 命令 查看linux服務器硬盤IO讀寫負載