當(dāng)前位置:首頁 > 智能硬件 > 智能硬件
[導(dǎo)讀]自學(xué)c編譯器的朋友都知道。c編譯器作為常用軟件之一,并非具備無法逾越難度。對于c編譯器的學(xué)習(xí),往往需要具備一定耐心。本文對c編譯器的講解基于gcc c編譯器,同時本文承接“c編譯器so easy,gcc c編譯器生成、使用動靜態(tài)庫(上篇)”一文而談,不了解的朋友可以先回顧一番哦。

自學(xué)c編譯器的朋友都知道。c編譯器作為常用軟件之一,并非具備無法逾越難度。對于c編譯器的學(xué)習(xí),往往需要具備一定耐心。本文對c編譯器的講解基于gcc c編譯器,同時本文承接“c編譯器so easy,gcc c編譯器生成、使用動靜態(tài)庫(上篇)”一文而談,不了解的朋友可以先回顧一番哦。此外,本文主要內(nèi)容為gcc生成靜態(tài)和動態(tài)鏈接庫的示例,一起來了解下吧。

我們通常把一些公用函數(shù)制作成函數(shù)庫,供其它程序使用。函數(shù)庫分為靜態(tài)庫和動態(tài)庫兩種。

靜態(tài)庫在程序編譯時會被連接到目標(biāo)代碼中,程序運(yùn)行時將不再需要該靜態(tài)庫。

動態(tài)庫在程序編譯時并不會被連接到目標(biāo)代碼中,而是在程序運(yùn)行是才被載入,因此在程序運(yùn)行時還需要動態(tài)庫存在。

本文主要通過舉例來說明在Linux中如何創(chuàng)建靜態(tài)庫和動態(tài)庫,以及使用它們。

為了便于闡述,我們先做一部分準(zhǔn)備工作。

1.準(zhǔn)備好測試代碼hello.h、hello.c和main.c

hello.h(見程序1)為該函數(shù)庫的頭文件。

hello.c(見程序2)是函數(shù)庫的源程序,其中包含公用函數(shù)hello,該函數(shù)將在屏幕上輸出“Hello XXX!”。

main.c(見程序3)為測試庫文件的主程序,在主程序中調(diào)用了公用函數(shù)hello。

程序1: hello.h

#ifndef HELLO_H

#define HELLO_H

void hello(const char *name);

#endif

程序2:hello.c#include

void hello(const char *name) {

printf(“Hello %s!\n”, name);

}

程序3:main.c#include “hello.h”

int main()

{

hello(“everyone”);

return 0;

}

2.問題的提出

注意:這個時候,我們編譯好的hello.o是無法通過gcc –o 編譯的,這個道理非常簡單,

hello.c是一個沒有main函數(shù)的.c程序,因此不夠成一個完整的程序,如果使用gcc –o 編譯并連接它,GCC將報錯。

無論靜態(tài)庫,還是動態(tài)庫,都是由.o文件創(chuàng)建的。因此,我們必須將源程序hello.c通過gcc先編譯成.o文件。

這個時候我們有三種思路:

1) 通過編譯多個源文件,直接將目標(biāo)代碼合成一個.o文件。

2) 通過創(chuàng)建靜態(tài)鏈接庫libmyhello.a,使得main函數(shù)調(diào)用hello函數(shù)時可調(diào)用靜態(tài)鏈接庫。

3) 通過創(chuàng)建動態(tài)鏈接庫libmyhello.so,使得main函數(shù)調(diào)用hello函數(shù)時可調(diào)用靜態(tài)鏈接庫。

3.思路一:編譯多個源文件

在系統(tǒng)提示符下鍵入以下命令得到hello.o文件。

# gcc -c hello.c

為什么不使用gcc–o hello hello.cpp 這個道理我們之前已經(jīng)說了,使用-c是什么意思呢?這涉及到gcc 編譯選項(xiàng)的常識。

我們通常使用的gcc –o 是將.c源文件編譯成為一個可執(zhí)行的二進(jìn)制代碼(-o選項(xiàng)其實(shí)是制定輸出文件文件名,如果不加-c選項(xiàng),gcc默認(rèn)會編譯連接生成可執(zhí)行文件,文件的名稱有-o選項(xiàng)指定),這包括調(diào)用作為GCC內(nèi)的一部分真正的C編譯器(ccl),以及調(diào)用GNU C編譯器的輸出中實(shí)際可執(zhí)行代碼的外部GNU匯編器(as)和連接器工具(ld)。

而gcc –c是使用GNU匯編器將源文件轉(zhuǎn)化為目標(biāo)代碼之后就結(jié)束,在這種情況下,只調(diào)用了C編譯器(ccl)和匯編器(as),而連接器(ld)并沒有被執(zhí)行,所以輸出的目標(biāo)文件不會包含作為Linux程序在被裝載和執(zhí)行時所必須的包含信息,但它可以在以后被連接到一個程序。

我們運(yùn)行l(wèi)s命令看看是否生存了hello.o文件。

# ls

hello.c hello.h hello.o main.c

在ls命令結(jié)果中,我們看到了hello.o文件,本步操作完成。

同理編譯main

#gcc –c main.c

將兩個文件鏈接成一個.o文件。

#gcc –o hello hello.o main.o

運(yùn)行

# 。/hello

Hello everyone!

4.思路二:靜態(tài)鏈接庫

下面我們先來看看如何創(chuàng)建靜態(tài)庫,以及使用它。

靜態(tài)庫文件名的命名規(guī)范是以lib為前綴,緊接著跟靜態(tài)庫名,擴(kuò)展名為.a。例如:我們將創(chuàng)建的靜態(tài)庫名為myhello,則靜態(tài)庫文件名就是libmyhello.a。在創(chuàng)建和使用靜態(tài)庫時,需要注意這點(diǎn)。創(chuàng)建靜態(tài)庫用ar命令。

在系統(tǒng)提示符下鍵入以下命令將創(chuàng)建靜態(tài)庫文件libmyhello.a。

# ar rcs libmyhello.a hello.o

我們同樣運(yùn)行l(wèi)s命令查看結(jié)果:

# ls

hello.c hello.h hello.o libmyhello.a main.c

ls命令結(jié)果中有l(wèi)ibmyhello.a。

靜態(tài)庫制作完了,如何使用它內(nèi)部的函數(shù)呢?只需要在使用到這些公用函數(shù)的源程序中包含這些公用函數(shù)的原型聲明,然后在用gcc命令生成目標(biāo)文件時指明靜態(tài)庫名,gcc將會從靜態(tài)庫中將公用函數(shù)連接到目標(biāo)文件中。注意,gcc會在靜態(tài)庫名前加上前綴lib,然后追加擴(kuò)展名.a得到的靜態(tài)庫文件名來查找靜態(tài)庫文件,因此,我們在寫需要連接的庫時,只寫名字就可以,如libmyhello.a的庫,只寫:-lmyhello

在程序3:main.c中,我們包含了靜態(tài)庫的頭文件hello.h,然后在主程序main中直接調(diào)用公用函數(shù)hello。下面先生成目標(biāo)程序hello,然后運(yùn)行hello程序看看結(jié)果如何。

# gcc -o hello main.c -static -L. -lmyhello

# 。/hello

Hello everyone!

我們刪除靜態(tài)庫文件試試公用函數(shù)hello是否真的連接到目標(biāo)文件 hello中了。

# rm libmyhello.a

rm: remove regular file `libmyhello.a‘? y

# 。/hello

Hello everyone!

程序照常運(yùn)行,靜態(tài)庫中的公用函數(shù)已經(jīng)連接到目標(biāo)文件中了。

靜態(tài)鏈接庫的一個缺點(diǎn)是,如果我們同時運(yùn)行了許多程序,并且它們使用了同一個庫函數(shù),這樣,在內(nèi)存中會大量拷貝同一庫函數(shù)。這樣,就會浪費(fèi)很多珍貴的內(nèi)存和存儲空間。使用了共享鏈接庫的Linux就可以避免這個問題。

共享函數(shù)庫和靜態(tài)函數(shù)在同一個地方,只是后綴有所不同。比如,在一個典型的Linux系統(tǒng),標(biāo)準(zhǔn)的共享數(shù)序函數(shù)庫是/usr/lib/libm.so。

當(dāng)一個程序使用共享函數(shù)庫時,在連接階段并不把函數(shù)代碼連接進(jìn)來,而只是鏈接函數(shù)的一個引用。當(dāng)最終的函數(shù)導(dǎo)入內(nèi)存開始真正執(zhí)行時,函數(shù)引用被解析,共享函數(shù)庫的代碼才真正導(dǎo)入到內(nèi)存中。這樣,共享鏈接庫的函數(shù)就可以被許多程序同時共享,并且只需存儲一次就可以了。共享函數(shù)庫的另一個優(yōu)點(diǎn)是,它可以獨(dú)立更新,與調(diào)用它的函數(shù)毫不影響。

5.思路三、動態(tài)鏈接庫(共享函數(shù)庫)

我們繼續(xù)看看如何在Linux中創(chuàng)建動態(tài)庫。我們還是從.o文件開始。

動態(tài)庫文件名命名規(guī)范和靜態(tài)庫文件名命名規(guī)范類似,也是在動態(tài)庫名增加前綴lib,但其文件擴(kuò)展名為.so。例如:我們將創(chuàng)建的動態(tài)庫名為myhello,則動態(tài)庫文件名就是libmyhello.so。用gcc來創(chuàng)建動態(tài)庫。

在系統(tǒng)提示符下鍵入以下命令得到動態(tài)庫文件libmyhello.so。

# gcc -shared -fPIC -o libmyhello.so hello.o

“PIC”命令行標(biāo)記告訴GCC產(chǎn)生的代碼不要包含對函數(shù)和變量具體內(nèi)存位置的引用,這是因?yàn)楝F(xiàn)在還無法知道使用該消息代碼的應(yīng)用程序會將它連接到哪一段內(nèi)存地址空間。這樣編譯出的hello.o可以被用于建立共享鏈接庫。建立共享鏈接庫只需要用GCC的”-shared”標(biāo)記即可。

我們照樣使用ls命令看看動態(tài)庫文件是否生成。

# ls

hello.cpp hello.h hello.o libmyhello.so main.cpp

調(diào)用動態(tài)鏈接庫編譯目標(biāo)文件。

在程序中使用動態(tài)庫和使用靜態(tài)庫完全一樣,也是在使用到這些公用函數(shù)的源程序中包含這些公用函數(shù)的原型聲明,然后在用gcc命令生成目標(biāo)文件時指明動態(tài)庫名進(jìn)行編譯。我們先運(yùn)行g(shù)cc命令生成目標(biāo)文件,再運(yùn)行它看看結(jié)果。

如果直接用如下方法進(jìn)行編譯,并連接:

# gcc -o hello main.c -L. -lmyhello

(使用”-lmyhello”標(biāo)記來告訴GCC驅(qū)動程序在連接階段引用共享函數(shù)庫libmyhello.so。”-L.”標(biāo)記告訴GCC函數(shù)庫可能位于當(dāng)前目錄。否則GNU連接器會查找標(biāo)準(zhǔn)系統(tǒng)函數(shù)目錄:它先后搜索1.elf文件的 DT_RPATH段—2.環(huán)境變量LD_LIBRARY_PATH—3./etc/ld.so.cache文件列表—4./lib/,/usr/lib目錄找到庫文件后將其載入內(nèi)存,但是我們生成的共享庫在當(dāng)前文件夾下,并沒有加到上述的4個路徑的任何一個中,因此,執(zhí)行后會出現(xiàn)錯誤)

# 。/hello

。/hello: error while loading shared libraries: libmyhello.so: cannot open shared object file: No such file or directory

#

錯誤提示,找不到動態(tài)庫文件libmyhello.so。程序在運(yùn)行時,會在/usr/lib和/lib等目錄中查找需要的動態(tài)庫文件。若找到,則載入動態(tài)庫,否則將提示類似上述錯誤而終止程序運(yùn)行。有多種方法可以解決,

(1)我們將文件 libmyhello.so復(fù)制到目錄/usr/lib中,再試試。

# mv libmyhello.so /usr/lib

# 。/hello

成功!

(2)既然連接器會搜尋LD_LIBRARY_PATH所指定的目錄,那么我們可以將這個環(huán)境變量設(shè)置成當(dāng)前目錄:

先執(zhí)行:

export LD_LIBRARY_PATH=$(pwd)

再執(zhí)行:

。/hello

成功!

(3)執(zhí)行:

ldconfig /usr/zhsoft/lib

注: 當(dāng)用戶在某個目錄下面創(chuàng)建或拷貝了一個動態(tài)鏈接庫,若想使其被系統(tǒng)共享,可以執(zhí)行一下“ldconfig 目錄名”這個命令。此命令的功能在于讓ldconfig將指定目錄下的動態(tài)鏈接庫被系統(tǒng)共享起來,意即:在緩存文件/etc/ld.so.cache中追加進(jìn)指定目錄下的共享庫。本例讓系統(tǒng)共享了/usr/zhsoft/lib目錄下的動態(tài)鏈接庫。該命令會重建/etc/ld.so.cache文件。

以上便是此次小編帶來的“c編譯器”相關(guān)內(nèi)容,通過本文,希望大家對gcc生成靜態(tài)和動態(tài)鏈接庫的過程具備一定的了解。如果你喜歡本文,不妨持續(xù)關(guān)注我們網(wǎng)站哦,小編將于后期帶來更多精彩內(nèi)容。最后,十分感謝大家的閱讀,have a nice day!

本站聲明: 本文章由作者或相關(guān)機(jī)構(gòu)授權(quán)發(fā)布,目的在于傳遞更多信息,并不代表本站贊同其觀點(diǎn),本站亦不保證或承諾內(nèi)容真實(shí)性等。需要轉(zhuǎn)載請聯(lián)系該專欄作者,如若文章內(nèi)容侵犯您的權(quán)益,請及時聯(lián)系本站刪除。
換一批
延伸閱讀

9月2日消息,不造車的華為或?qū)⒋呱龈蟮莫?dú)角獸公司,隨著阿維塔和賽力斯的入局,華為引望愈發(fā)顯得引人矚目。

關(guān)鍵字: 阿維塔 塞力斯 華為

加利福尼亞州圣克拉拉縣2024年8月30日 /美通社/ -- 數(shù)字化轉(zhuǎn)型技術(shù)解決方案公司Trianz今天宣布,該公司與Amazon Web Services (AWS)簽訂了...

關(guān)鍵字: AWS AN BSP 數(shù)字化

倫敦2024年8月29日 /美通社/ -- 英國汽車技術(shù)公司SODA.Auto推出其旗艦產(chǎn)品SODA V,這是全球首款涵蓋汽車工程師從創(chuàng)意到認(rèn)證的所有需求的工具,可用于創(chuàng)建軟件定義汽車。 SODA V工具的開發(fā)耗時1.5...

關(guān)鍵字: 汽車 人工智能 智能驅(qū)動 BSP

北京2024年8月28日 /美通社/ -- 越來越多用戶希望企業(yè)業(yè)務(wù)能7×24不間斷運(yùn)行,同時企業(yè)卻面臨越來越多業(yè)務(wù)中斷的風(fēng)險,如企業(yè)系統(tǒng)復(fù)雜性的增加,頻繁的功能更新和發(fā)布等。如何確保業(yè)務(wù)連續(xù)性,提升韌性,成...

關(guān)鍵字: 亞馬遜 解密 控制平面 BSP

8月30日消息,據(jù)媒體報道,騰訊和網(wǎng)易近期正在縮減他們對日本游戲市場的投資。

關(guān)鍵字: 騰訊 編碼器 CPU

8月28日消息,今天上午,2024中國國際大數(shù)據(jù)產(chǎn)業(yè)博覽會開幕式在貴陽舉行,華為董事、質(zhì)量流程IT總裁陶景文發(fā)表了演講。

關(guān)鍵字: 華為 12nm EDA 半導(dǎo)體

8月28日消息,在2024中國國際大數(shù)據(jù)產(chǎn)業(yè)博覽會上,華為常務(wù)董事、華為云CEO張平安發(fā)表演講稱,數(shù)字世界的話語權(quán)最終是由生態(tài)的繁榮決定的。

關(guān)鍵字: 華為 12nm 手機(jī) 衛(wèi)星通信

要點(diǎn): 有效應(yīng)對環(huán)境變化,經(jīng)營業(yè)績穩(wěn)中有升 落實(shí)提質(zhì)增效舉措,毛利潤率延續(xù)升勢 戰(zhàn)略布局成效顯著,戰(zhàn)新業(yè)務(wù)引領(lǐng)增長 以科技創(chuàng)新為引領(lǐng),提升企業(yè)核心競爭力 堅持高質(zhì)量發(fā)展策略,塑強(qiáng)核心競爭優(yōu)勢...

關(guān)鍵字: 通信 BSP 電信運(yùn)營商 數(shù)字經(jīng)濟(jì)

北京2024年8月27日 /美通社/ -- 8月21日,由中央廣播電視總臺與中國電影電視技術(shù)學(xué)會聯(lián)合牽頭組建的NVI技術(shù)創(chuàng)新聯(lián)盟在BIRTV2024超高清全產(chǎn)業(yè)鏈發(fā)展研討會上宣布正式成立。 活動現(xiàn)場 NVI技術(shù)創(chuàng)新聯(lián)...

關(guān)鍵字: VI 傳輸協(xié)議 音頻 BSP

北京2024年8月27日 /美通社/ -- 在8月23日舉辦的2024年長三角生態(tài)綠色一體化發(fā)展示范區(qū)聯(lián)合招商會上,軟通動力信息技術(shù)(集團(tuán))股份有限公司(以下簡稱"軟通動力")與長三角投資(上海)有限...

關(guān)鍵字: BSP 信息技術(shù)
關(guān)閉
關(guān)閉