linux C库编译
生活随笔
收集整理的這篇文章主要介紹了
linux C库编译
小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
本文主要解決以下幾個(gè)問(wèn)題
1?為什么要使用庫(kù)?
2?庫(kù)的分類
3?創(chuàng)建自己的庫(kù)
或許大家對(duì)自己初學(xué)linux時(shí)的情形仍記憶尤新吧。如果沒(méi)有一個(gè)能較好的解決依賴關(guān)系的包管理器,在linux下安裝軟件將是一件及其痛苦的工作。你裝a包時(shí),可能會(huì)提示你要先裝b包,當(dāng)你費(fèi)盡心力找到b包時(shí),可能又會(huì)提示你要先安裝c包。我就曾被這樣的事搞的焦頭爛額,至今一提起rpm仍心有余悸,頭皮發(fā)麻。說(shuō)是一朝被蛇咬,十年怕井繩怕也不為過(guò)。
linux下之所以有這許多的依賴關(guān)系,其中一個(gè)開(kāi)發(fā)原則真是功不可沒(méi)。這個(gè)原則就是:盡量不重復(fù)做別人已經(jīng)做過(guò)的事。換句話說(shuō)就是盡量充分利用別人的勞動(dòng)成果。
這就涉及到如何有效的進(jìn)行代碼復(fù)用。
1?為什么要使用庫(kù)?
關(guān)于代碼復(fù)用的途徑,一般有兩種。
粘貼復(fù)制
這是最沒(méi)有技術(shù)含量的一種方案。如果代碼小,則工作量還可以忍受,如果代碼很龐大,則此法不可取。即便有人原意這樣做,但誰(shuí)又能保證所有的代碼都可得到呢?
而庫(kù)的出現(xiàn)很好的解決了這個(gè)問(wèn)題。
庫(kù),是一種封裝機(jī)制,簡(jiǎn)單說(shuō)把所有的源代碼編譯成目標(biāo)代碼后打成的包。
那么用戶怎么能知道這個(gè)庫(kù)提供什么樣的接口呢?難道要用nm等工具逐個(gè)掃描?
不用擔(dān)心,庫(kù)的開(kāi)發(fā)者早以把一切都做好了。除了包含目標(biāo)代碼的庫(kù)外,一般還會(huì)提供一系列的頭文件,頭文件中就包含了庫(kù)的接口。為了讓方便用戶,再加上一個(gè)使用說(shuō)明就差不多完美了。
2?庫(kù)的分類
2.1?庫(kù)的分類
根據(jù)鏈接時(shí)期的不同,庫(kù)又有靜態(tài)庫(kù)和動(dòng)態(tài)庫(kù)之分。
靜態(tài)庫(kù)是在鏈接階段被鏈接的(好像是廢話,但事實(shí)就是這樣),所以生成的可執(zhí)行文件就不受庫(kù)的影響了,即使庫(kù)被刪除了,程序依然可以成功運(yùn)行。
有別于靜態(tài)庫(kù),動(dòng)態(tài)庫(kù)的鏈接是在程序執(zhí)行的時(shí)候被鏈接的。所以,即使程序編譯完,庫(kù)仍須保留在系統(tǒng)上,以供程序運(yùn)行時(shí)調(diào)用。(TODO:鏈接動(dòng)態(tài)庫(kù)時(shí)鏈接階段到底做了什么)
2.2?靜態(tài)庫(kù)和動(dòng)態(tài)庫(kù)的比較
鏈接靜態(tài)庫(kù)其實(shí)從某種意義上來(lái)說(shuō)也是一種粘貼復(fù)制,只不過(guò)它操作的對(duì)象是目標(biāo)代碼而不是源碼而已。因?yàn)殪o態(tài)庫(kù)被鏈接后庫(kù)就直接嵌入可執(zhí)行文件中了,這樣就帶來(lái)了兩個(gè)問(wèn)題。
首先就是系統(tǒng)空間被浪費(fèi)了。這是顯而易見(jiàn)的,想象一下,如果多個(gè)程序鏈接了同一個(gè)庫(kù),則每一個(gè)生成的可執(zhí)行文件就都會(huì)有一個(gè)庫(kù)的副本,必然會(huì)浪費(fèi)系統(tǒng)空間。
再者,人非圣賢,即使是精心調(diào)試的庫(kù),也難免會(huì)有錯(cuò)。一旦發(fā)現(xiàn)了庫(kù)中有bug,挽救起來(lái)就比較麻煩了。必須一一把鏈接該庫(kù)的程序找出來(lái),然后重新編譯。
而動(dòng)態(tài)庫(kù)的出現(xiàn)正彌補(bǔ)了靜態(tài)庫(kù)的以上弊端。因?yàn)閯?dòng)態(tài)庫(kù)是在程序運(yùn)行時(shí)被鏈接的,所以磁盤上只須保留一份副本,因此節(jié)約了磁盤空間。如果發(fā)現(xiàn)了bug或要升級(jí)也很簡(jiǎn)單,只要用新的庫(kù)把原來(lái)的替換掉就行了。
那么,是不是靜態(tài)庫(kù)就一無(wú)是處了呢?
答曰:非也非也。不是有句話么:存在即是合理。靜態(tài)庫(kù)既然沒(méi)有湮沒(méi)在滔滔的歷史長(zhǎng)河中,就必然有它的用武之地。想象一下這樣的情況:如果你用libpcap庫(kù)編了一個(gè)程序,要給被人運(yùn)行,而他的系統(tǒng)上沒(méi)有裝pcap庫(kù),該怎么解決呢?最簡(jiǎn)單的辦法就是編譯該程序時(shí)把所有要鏈接的庫(kù)都鏈接它們的靜態(tài)庫(kù),這樣,就可以在別人的系統(tǒng)上直接運(yùn)行該程序了。
所謂有得必有失,正因?yàn)閯?dòng)態(tài)庫(kù)在程序運(yùn)行時(shí)被鏈接,故程序的運(yùn)行速度和鏈接靜態(tài)庫(kù)的版本相比必然會(huì)打折扣。然而瑕不掩瑜,動(dòng)態(tài)庫(kù)的不足相對(duì)于它帶來(lái)的好處在現(xiàn)今硬件下簡(jiǎn)直是微不足道的,所以鏈接程序在鏈接時(shí)一般是優(yōu)先鏈接動(dòng)態(tài)庫(kù)的,除非用-static參數(shù)指定鏈接靜態(tài)庫(kù)。
2.3?如何判斷一個(gè)程序有沒(méi)有鏈接動(dòng)態(tài)庫(kù)?
答案是用file實(shí)用程序。
file程序是用來(lái)判斷文件類型的,在file命令下,所有文件都會(huì)原形畢露的。
順便說(shuō)一個(gè)技巧。有時(shí)在windows下用瀏覽器下載tar.gz或tar.bz2文件,后綴名會(huì)變成奇怪的tar.tar,到linux有些新手就不知怎么解壓了。但linux下的文件類型并不受文件后綴名的影響,所以我們可以先用命令file?xxx.tar.tar看一下文件類型,然后用tar加適當(dāng)?shù)膮?shù)解壓。
另外,還可以借助程序ldd實(shí)用程序來(lái)判斷。
ldd是用來(lái)打印目標(biāo)程序(由命令行參數(shù)指定)所鏈接的所有動(dòng)態(tài)庫(kù)的信息的,如果目標(biāo)程序沒(méi)有鏈接動(dòng)態(tài)庫(kù),則打印“not?a?dynamic?executable”,ldd的用法請(qǐng)參考manpage。
3?創(chuàng)建自己的庫(kù)
3.1?創(chuàng)建動(dòng)態(tài)庫(kù)
創(chuàng)建文件hello.c,內(nèi)容如下:
#include?
void?hello(void)
{
printf("Hello?World\n");
}
用命令gcc?-shared?hello.c?-o?libhello.so編譯為動(dòng)態(tài)庫(kù)。可以看到,當(dāng)前目錄下多了一個(gè)文件libhello.so。
[leo@leo?test]$?file?libhello.so?
libhello.so:?ELF?32-bit?LSB?shared?object,?Intel?80386,?version?1?(SYSV),?not?stripped
看到了吧,文件類型是shared?object了。
再編輯一個(gè)測(cè)試文件test.c,內(nèi)容如下:
int
main()
{
hello();
return?0;
}
這下可以編譯了:)
[leo@leo?test]$?gcc?test.c
/tmp/ccm7w6Mn.o:?In?function?`main':
test.c:(.text+0x1d):?undefined?reference?to?`hello'
collect2:?ld?returned?1?exit?status
鏈接時(shí)gcc找不到hello函數(shù),編譯失敗:(。原因是hello在我們自己創(chuàng)建的庫(kù)中,如果gcc能找到那才教見(jiàn)鬼呢!ok,再接再厲。
[leo@leo?test]$?gcc?test.c?-lhello
/usr/lib/gcc/i686-pc-linux-gnu/4.0.0/../../../../i686-pc-linux-gnu/bin/ld:?cannot?find?-lhello
collect2:?ld?returned?1?exit?status
[leo@leo?test]$?gcc?test.c?-lhello?-L.
[leo@leo?test]$?
第一次編譯直接編譯,gcc默認(rèn)會(huì)鏈接標(biāo)準(zhǔn)c庫(kù),但符號(hào)名hello解析不出來(lái),故連接階段通不過(guò)了。
現(xiàn)在用gcc?test.c?-lhello?-L.已經(jīng)編譯成功了,默認(rèn)輸出為a.out。現(xiàn)在來(lái)試著運(yùn)行一下:
[leo@leo?test]$?./a.out?
./a.out:?error?while?loading?shared?libraries:?libhello.so:?cannot?open?shared?object?file:?No?such?file?or?directory
咦,怎么回事?原來(lái)雖然鏈接時(shí)鏈接器(dynamic?linker)找到了動(dòng)態(tài)庫(kù)libhello.so,但動(dòng)態(tài)加載器(dynamic?loader,?一般是/lib/ld-linux.so.2)卻沒(méi)找到。再來(lái)看看ldd的輸出:
[leo@leo?test]$?ldd?a.out?
linux-gate.so.1?=>?(0xffffe000)
libhello.so?=>?not?found
libc.so.6?=>?/lib/libc.so.6?(0x40034000)
/lib/ld-linux.so.2?(0x40000000)
果然如此,看到?jīng)]有,libhello.so?=>?not?found。
linux為我們提供了兩種解決方法:
1.可以把當(dāng)前路徑加入/etc/ld.so.conf中然后運(yùn)行l(wèi)dconfig,或者以當(dāng)前路徑為參數(shù)運(yùn)行l(wèi)dconfig(要有root權(quán)限才行)。
2.把當(dāng)前路徑加入環(huán)境變量LD_LIBRARY_PATH中
當(dāng)然,如果你覺(jué)得不會(huì)引起混亂的話,可以直接把該庫(kù)拷入/lib,/usr/lib/等位置(無(wú)可避免,這樣做也要有權(quán)限),這樣鏈接器和加載器就都可以準(zhǔn)確的找到該庫(kù)了。
我們采用第二種方法:
[leo@leo?test]$?export?LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH
[leo@leo?test]$?ldd?a.out?
linux-gate.so.1?=>?(0xffffe000)
libhello.so?=>?./libhello.so?(0x4001f000)
libc.so.6?=>?/lib/libc.so.6?(0x40036000)
/lib/ld-linux.so.2?(0x40000000)
哈哈,這下ld-linux.so.2就可以找到libhello.so這個(gè)庫(kù)了。
現(xiàn)在可以直接運(yùn)行了:
[leo@leo?test]$?./a.out?
Hello?World
3.2?創(chuàng)建靜態(tài)庫(kù)
仍使用剛才的hello.c和test.c。
第一步,生成目標(biāo)文件。
[leo@leo?test]$?gcc?-c?hello.c
[leo@leo?test]$?ls?hello.o?-l
-rw-r--r--?1?leo?users?840?5月?6?12:48?hello.o
第二步,把目標(biāo)文件歸檔。
[leo@leo?test]$?ar?r?libhello.a?hello.o?
ar:?creating?libhello.a
OK,libhello.a就是我們所創(chuàng)建的靜態(tài)庫(kù)了,簡(jiǎn)單吧:)
[leo@leo?test]$?file?libhello.a?
libhello.a:?current?ar?archive
下面一行命令就是教你如何在程序中鏈接靜態(tài)庫(kù)的:
[leo@leo?test]$?gcc?test.c?-lhello?-L.?-static?-o?hello.static
我們來(lái)用file命令比較一下用動(dòng)態(tài)庫(kù)和靜態(tài)庫(kù)鏈接的程序的區(qū)別:
[leo@leo?test]$?gcc?test.c?-lhello?-L.?-o?hello.dynamic
正如前面所說(shuō),鏈接器默認(rèn)會(huì)鏈接動(dòng)態(tài)庫(kù)(這里是libhello.so),所以只要把上個(gè)命令中的-static參數(shù)去掉就可以了。?
用file實(shí)用程序驗(yàn)證一下是否按我們的要求生成了可執(zhí)行文件:
[leo@leo?test]$?file?hello.static?hello.dynamic?
hello.static:?ELF?32-bit?LSB?executable,?Intel?80386,?version?1?(SYSV),?for?GNU/Linux?2.6.6,?statically?linked,?not?stripped
hello.dynamic:?ELF?32-bit?LSB?executable,?Intel?80386,?version?1?(SYSV),?for?GNU/Linux?2.6.6,?dynamically?linked?(uses?shared?libs),?not?stripped
不妨順便練習(xí)一下ldd的用法:
[leo@leo?test]$?ldd?hello.static?hello.dynamic?
hello.static:
not?a?dynamic?executable
hello.dynamic:
linux-gate.so.1?=>?(0xffffe000)
libhello.so?=>?./libhello.so?(0x4001f000)
libc.so.6?=>?/lib/libc.so.6?(0x40034000)
/lib/ld-linux.so.2?(0x40000000)
OK,看來(lái)沒(méi)有問(wèn)題,那就比較一下大小先:
[leo@leo?test]$?ls?-l?hello.[ds]*
-rwxr-xr-x?1?leo?users?5911?5月?6?12:54?hello.dynamic
-rwxr-xr-x?1?leo?users?628182?5月?6?12:54?hello.static
看到區(qū)別了吧,鏈接靜態(tài)庫(kù)的目標(biāo)程序和鏈接動(dòng)態(tài)庫(kù)的程序比起來(lái)簡(jiǎn)直就是一個(gè)龐然大物!
這么小的程序,很難看出執(zhí)行時(shí)間的差別,不過(guò)為了完整起見(jiàn),還是看一下time的輸出吧:
[leo@leo?test]$?time?./hello.static?
Hello?World
real?0m0.001s
user?0m0.000s
sys?0m0.001s
[leo@leo?test]$?time?./hello.dynamic?
Hello?World
real?0m0.001s
user?0m0.000s
sys?0m0.001s
如果程序比較大的話,應(yīng)該效果會(huì)很明顯的。
1?為什么要使用庫(kù)?
2?庫(kù)的分類
3?創(chuàng)建自己的庫(kù)
或許大家對(duì)自己初學(xué)linux時(shí)的情形仍記憶尤新吧。如果沒(méi)有一個(gè)能較好的解決依賴關(guān)系的包管理器,在linux下安裝軟件將是一件及其痛苦的工作。你裝a包時(shí),可能會(huì)提示你要先裝b包,當(dāng)你費(fèi)盡心力找到b包時(shí),可能又會(huì)提示你要先安裝c包。我就曾被這樣的事搞的焦頭爛額,至今一提起rpm仍心有余悸,頭皮發(fā)麻。說(shuō)是一朝被蛇咬,十年怕井繩怕也不為過(guò)。
linux下之所以有這許多的依賴關(guān)系,其中一個(gè)開(kāi)發(fā)原則真是功不可沒(méi)。這個(gè)原則就是:盡量不重復(fù)做別人已經(jīng)做過(guò)的事。換句話說(shuō)就是盡量充分利用別人的勞動(dòng)成果。
這就涉及到如何有效的進(jìn)行代碼復(fù)用。
1?為什么要使用庫(kù)?
關(guān)于代碼復(fù)用的途徑,一般有兩種。
粘貼復(fù)制
這是最沒(méi)有技術(shù)含量的一種方案。如果代碼小,則工作量還可以忍受,如果代碼很龐大,則此法不可取。即便有人原意這樣做,但誰(shuí)又能保證所有的代碼都可得到呢?
而庫(kù)的出現(xiàn)很好的解決了這個(gè)問(wèn)題。
庫(kù),是一種封裝機(jī)制,簡(jiǎn)單說(shuō)把所有的源代碼編譯成目標(biāo)代碼后打成的包。
那么用戶怎么能知道這個(gè)庫(kù)提供什么樣的接口呢?難道要用nm等工具逐個(gè)掃描?
不用擔(dān)心,庫(kù)的開(kāi)發(fā)者早以把一切都做好了。除了包含目標(biāo)代碼的庫(kù)外,一般還會(huì)提供一系列的頭文件,頭文件中就包含了庫(kù)的接口。為了讓方便用戶,再加上一個(gè)使用說(shuō)明就差不多完美了。
2?庫(kù)的分類
2.1?庫(kù)的分類
根據(jù)鏈接時(shí)期的不同,庫(kù)又有靜態(tài)庫(kù)和動(dòng)態(tài)庫(kù)之分。
靜態(tài)庫(kù)是在鏈接階段被鏈接的(好像是廢話,但事實(shí)就是這樣),所以生成的可執(zhí)行文件就不受庫(kù)的影響了,即使庫(kù)被刪除了,程序依然可以成功運(yùn)行。
有別于靜態(tài)庫(kù),動(dòng)態(tài)庫(kù)的鏈接是在程序執(zhí)行的時(shí)候被鏈接的。所以,即使程序編譯完,庫(kù)仍須保留在系統(tǒng)上,以供程序運(yùn)行時(shí)調(diào)用。(TODO:鏈接動(dòng)態(tài)庫(kù)時(shí)鏈接階段到底做了什么)
2.2?靜態(tài)庫(kù)和動(dòng)態(tài)庫(kù)的比較
鏈接靜態(tài)庫(kù)其實(shí)從某種意義上來(lái)說(shuō)也是一種粘貼復(fù)制,只不過(guò)它操作的對(duì)象是目標(biāo)代碼而不是源碼而已。因?yàn)殪o態(tài)庫(kù)被鏈接后庫(kù)就直接嵌入可執(zhí)行文件中了,這樣就帶來(lái)了兩個(gè)問(wèn)題。
首先就是系統(tǒng)空間被浪費(fèi)了。這是顯而易見(jiàn)的,想象一下,如果多個(gè)程序鏈接了同一個(gè)庫(kù),則每一個(gè)生成的可執(zhí)行文件就都會(huì)有一個(gè)庫(kù)的副本,必然會(huì)浪費(fèi)系統(tǒng)空間。
再者,人非圣賢,即使是精心調(diào)試的庫(kù),也難免會(huì)有錯(cuò)。一旦發(fā)現(xiàn)了庫(kù)中有bug,挽救起來(lái)就比較麻煩了。必須一一把鏈接該庫(kù)的程序找出來(lái),然后重新編譯。
而動(dòng)態(tài)庫(kù)的出現(xiàn)正彌補(bǔ)了靜態(tài)庫(kù)的以上弊端。因?yàn)閯?dòng)態(tài)庫(kù)是在程序運(yùn)行時(shí)被鏈接的,所以磁盤上只須保留一份副本,因此節(jié)約了磁盤空間。如果發(fā)現(xiàn)了bug或要升級(jí)也很簡(jiǎn)單,只要用新的庫(kù)把原來(lái)的替換掉就行了。
那么,是不是靜態(tài)庫(kù)就一無(wú)是處了呢?
答曰:非也非也。不是有句話么:存在即是合理。靜態(tài)庫(kù)既然沒(méi)有湮沒(méi)在滔滔的歷史長(zhǎng)河中,就必然有它的用武之地。想象一下這樣的情況:如果你用libpcap庫(kù)編了一個(gè)程序,要給被人運(yùn)行,而他的系統(tǒng)上沒(méi)有裝pcap庫(kù),該怎么解決呢?最簡(jiǎn)單的辦法就是編譯該程序時(shí)把所有要鏈接的庫(kù)都鏈接它們的靜態(tài)庫(kù),這樣,就可以在別人的系統(tǒng)上直接運(yùn)行該程序了。
所謂有得必有失,正因?yàn)閯?dòng)態(tài)庫(kù)在程序運(yùn)行時(shí)被鏈接,故程序的運(yùn)行速度和鏈接靜態(tài)庫(kù)的版本相比必然會(huì)打折扣。然而瑕不掩瑜,動(dòng)態(tài)庫(kù)的不足相對(duì)于它帶來(lái)的好處在現(xiàn)今硬件下簡(jiǎn)直是微不足道的,所以鏈接程序在鏈接時(shí)一般是優(yōu)先鏈接動(dòng)態(tài)庫(kù)的,除非用-static參數(shù)指定鏈接靜態(tài)庫(kù)。
2.3?如何判斷一個(gè)程序有沒(méi)有鏈接動(dòng)態(tài)庫(kù)?
答案是用file實(shí)用程序。
file程序是用來(lái)判斷文件類型的,在file命令下,所有文件都會(huì)原形畢露的。
順便說(shuō)一個(gè)技巧。有時(shí)在windows下用瀏覽器下載tar.gz或tar.bz2文件,后綴名會(huì)變成奇怪的tar.tar,到linux有些新手就不知怎么解壓了。但linux下的文件類型并不受文件后綴名的影響,所以我們可以先用命令file?xxx.tar.tar看一下文件類型,然后用tar加適當(dāng)?shù)膮?shù)解壓。
另外,還可以借助程序ldd實(shí)用程序來(lái)判斷。
ldd是用來(lái)打印目標(biāo)程序(由命令行參數(shù)指定)所鏈接的所有動(dòng)態(tài)庫(kù)的信息的,如果目標(biāo)程序沒(méi)有鏈接動(dòng)態(tài)庫(kù),則打印“not?a?dynamic?executable”,ldd的用法請(qǐng)參考manpage。
3?創(chuàng)建自己的庫(kù)
3.1?創(chuàng)建動(dòng)態(tài)庫(kù)
創(chuàng)建文件hello.c,內(nèi)容如下:
#include?
void?hello(void)
{
printf("Hello?World\n");
}
用命令gcc?-shared?hello.c?-o?libhello.so編譯為動(dòng)態(tài)庫(kù)。可以看到,當(dāng)前目錄下多了一個(gè)文件libhello.so。
[leo@leo?test]$?file?libhello.so?
libhello.so:?ELF?32-bit?LSB?shared?object,?Intel?80386,?version?1?(SYSV),?not?stripped
看到了吧,文件類型是shared?object了。
再編輯一個(gè)測(cè)試文件test.c,內(nèi)容如下:
int
main()
{
hello();
return?0;
}
這下可以編譯了:)
[leo@leo?test]$?gcc?test.c
/tmp/ccm7w6Mn.o:?In?function?`main':
test.c:(.text+0x1d):?undefined?reference?to?`hello'
collect2:?ld?returned?1?exit?status
鏈接時(shí)gcc找不到hello函數(shù),編譯失敗:(。原因是hello在我們自己創(chuàng)建的庫(kù)中,如果gcc能找到那才教見(jiàn)鬼呢!ok,再接再厲。
[leo@leo?test]$?gcc?test.c?-lhello
/usr/lib/gcc/i686-pc-linux-gnu/4.0.0/../../../../i686-pc-linux-gnu/bin/ld:?cannot?find?-lhello
collect2:?ld?returned?1?exit?status
[leo@leo?test]$?gcc?test.c?-lhello?-L.
[leo@leo?test]$?
第一次編譯直接編譯,gcc默認(rèn)會(huì)鏈接標(biāo)準(zhǔn)c庫(kù),但符號(hào)名hello解析不出來(lái),故連接階段通不過(guò)了。
現(xiàn)在用gcc?test.c?-lhello?-L.已經(jīng)編譯成功了,默認(rèn)輸出為a.out。現(xiàn)在來(lái)試著運(yùn)行一下:
[leo@leo?test]$?./a.out?
./a.out:?error?while?loading?shared?libraries:?libhello.so:?cannot?open?shared?object?file:?No?such?file?or?directory
咦,怎么回事?原來(lái)雖然鏈接時(shí)鏈接器(dynamic?linker)找到了動(dòng)態(tài)庫(kù)libhello.so,但動(dòng)態(tài)加載器(dynamic?loader,?一般是/lib/ld-linux.so.2)卻沒(méi)找到。再來(lái)看看ldd的輸出:
[leo@leo?test]$?ldd?a.out?
linux-gate.so.1?=>?(0xffffe000)
libhello.so?=>?not?found
libc.so.6?=>?/lib/libc.so.6?(0x40034000)
/lib/ld-linux.so.2?(0x40000000)
果然如此,看到?jīng)]有,libhello.so?=>?not?found。
linux為我們提供了兩種解決方法:
1.可以把當(dāng)前路徑加入/etc/ld.so.conf中然后運(yùn)行l(wèi)dconfig,或者以當(dāng)前路徑為參數(shù)運(yùn)行l(wèi)dconfig(要有root權(quán)限才行)。
2.把當(dāng)前路徑加入環(huán)境變量LD_LIBRARY_PATH中
當(dāng)然,如果你覺(jué)得不會(huì)引起混亂的話,可以直接把該庫(kù)拷入/lib,/usr/lib/等位置(無(wú)可避免,這樣做也要有權(quán)限),這樣鏈接器和加載器就都可以準(zhǔn)確的找到該庫(kù)了。
我們采用第二種方法:
[leo@leo?test]$?export?LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH
[leo@leo?test]$?ldd?a.out?
linux-gate.so.1?=>?(0xffffe000)
libhello.so?=>?./libhello.so?(0x4001f000)
libc.so.6?=>?/lib/libc.so.6?(0x40036000)
/lib/ld-linux.so.2?(0x40000000)
哈哈,這下ld-linux.so.2就可以找到libhello.so這個(gè)庫(kù)了。
現(xiàn)在可以直接運(yùn)行了:
[leo@leo?test]$?./a.out?
Hello?World
3.2?創(chuàng)建靜態(tài)庫(kù)
仍使用剛才的hello.c和test.c。
第一步,生成目標(biāo)文件。
[leo@leo?test]$?gcc?-c?hello.c
[leo@leo?test]$?ls?hello.o?-l
-rw-r--r--?1?leo?users?840?5月?6?12:48?hello.o
第二步,把目標(biāo)文件歸檔。
[leo@leo?test]$?ar?r?libhello.a?hello.o?
ar:?creating?libhello.a
OK,libhello.a就是我們所創(chuàng)建的靜態(tài)庫(kù)了,簡(jiǎn)單吧:)
[leo@leo?test]$?file?libhello.a?
libhello.a:?current?ar?archive
下面一行命令就是教你如何在程序中鏈接靜態(tài)庫(kù)的:
[leo@leo?test]$?gcc?test.c?-lhello?-L.?-static?-o?hello.static
我們來(lái)用file命令比較一下用動(dòng)態(tài)庫(kù)和靜態(tài)庫(kù)鏈接的程序的區(qū)別:
[leo@leo?test]$?gcc?test.c?-lhello?-L.?-o?hello.dynamic
正如前面所說(shuō),鏈接器默認(rèn)會(huì)鏈接動(dòng)態(tài)庫(kù)(這里是libhello.so),所以只要把上個(gè)命令中的-static參數(shù)去掉就可以了。?
用file實(shí)用程序驗(yàn)證一下是否按我們的要求生成了可執(zhí)行文件:
[leo@leo?test]$?file?hello.static?hello.dynamic?
hello.static:?ELF?32-bit?LSB?executable,?Intel?80386,?version?1?(SYSV),?for?GNU/Linux?2.6.6,?statically?linked,?not?stripped
hello.dynamic:?ELF?32-bit?LSB?executable,?Intel?80386,?version?1?(SYSV),?for?GNU/Linux?2.6.6,?dynamically?linked?(uses?shared?libs),?not?stripped
不妨順便練習(xí)一下ldd的用法:
[leo@leo?test]$?ldd?hello.static?hello.dynamic?
hello.static:
not?a?dynamic?executable
hello.dynamic:
linux-gate.so.1?=>?(0xffffe000)
libhello.so?=>?./libhello.so?(0x4001f000)
libc.so.6?=>?/lib/libc.so.6?(0x40034000)
/lib/ld-linux.so.2?(0x40000000)
OK,看來(lái)沒(méi)有問(wèn)題,那就比較一下大小先:
[leo@leo?test]$?ls?-l?hello.[ds]*
-rwxr-xr-x?1?leo?users?5911?5月?6?12:54?hello.dynamic
-rwxr-xr-x?1?leo?users?628182?5月?6?12:54?hello.static
看到區(qū)別了吧,鏈接靜態(tài)庫(kù)的目標(biāo)程序和鏈接動(dòng)態(tài)庫(kù)的程序比起來(lái)簡(jiǎn)直就是一個(gè)龐然大物!
這么小的程序,很難看出執(zhí)行時(shí)間的差別,不過(guò)為了完整起見(jiàn),還是看一下time的輸出吧:
[leo@leo?test]$?time?./hello.static?
Hello?World
real?0m0.001s
user?0m0.000s
sys?0m0.001s
[leo@leo?test]$?time?./hello.dynamic?
Hello?World
real?0m0.001s
user?0m0.000s
sys?0m0.001s
如果程序比較大的話,應(yīng)該效果會(huì)很明顯的。
總結(jié)
以上是生活随笔為你收集整理的linux C库编译的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 您如何查看MySQL用户权限
- 下一篇: 我创业失败的血泪史