日本搞逼视频_黄色一级片免费在线观看_色99久久_性明星video另类hd_欧美77_综合在线视频

國內(nèi)最全I(xiàn)T社區(qū)平臺 聯(lián)系我們 | 收藏本站
阿里云優(yōu)惠2
您當(dāng)前位置:首頁 > php開源 > 綜合技術(shù) > gcc編譯解析

gcc編譯解析

來源:程序員人生   發(fā)布時(shí)間:2016-07-26 13:06:41 閱讀次數(shù):2626次

簡介

本文通過如何調(diào)用庫文件來說述gcc程序編譯

正文

甚么是庫
在windows平臺和linux平臺下都大量存在著庫。本質(zhì)上來講庫是1種可履行代碼的2進(jìn)制情勢,可以被操作系統(tǒng)載入內(nèi)存履行。由于windows和linux的平臺不同(主要是編譯器、匯編器和連接器的不同),因此2者庫的2進(jìn)制是不兼容的。
本文僅限于介紹linux下的庫。
庫的種類
linux下的庫有兩種:靜態(tài)庫和同享庫(動(dòng)態(tài)庫)。2者的不同點(diǎn)在于代碼被載入的時(shí)刻不同。靜態(tài)庫的代碼在編譯進(jìn)程中已被載入可履行程序,因此體積較大。同享庫的代碼是在可履行程序運(yùn)行時(shí)才載入內(nèi)存的,在編譯進(jìn)程中僅簡單的援用,因此代碼體積較小。
庫存在的意義
庫是他人寫好的現(xiàn)有的,成熟的,可以復(fù)用的代碼,你可使用但要記得遵照許可協(xié)議。現(xiàn)實(shí)中每一個(gè)程序都要依賴很多基礎(chǔ)的底層庫,不可能每一個(gè)人的代碼都從零開始,因此庫的存在乎義非同尋常。
庫文件是如何產(chǎn)生的在linux下
靜態(tài)庫的后綴是.a,它的產(chǎn)生分兩步
1. 由源文件編譯生成1堆.o,每一個(gè).o里都包括這個(gè)編譯單元的符表
2. ar命令將很多.o轉(zhuǎn)換成.a,成為靜態(tài)庫動(dòng)態(tài)庫的后綴是.so,它由gcc加特定參數(shù)編譯產(chǎn)生。
具體方法參見后文實(shí)例。
庫文件是如何命名的,有無甚么規(guī)范
在linux下,庫文件1般放在/usr/lib和/lib下,靜態(tài)庫的名字1般為libxxxx.a,其中xxxx是該lib的名稱。動(dòng)態(tài)庫的名字1般為libxxxx.so.major.minor,xxxx是該lib的名稱,major是主版本號,minor是副版本號
如何知道1個(gè)可履行程序依賴哪些庫
ldd命令可以查看1個(gè)可履行程序依賴的同享庫,
比如查看ln程序的依賴庫$ ldd /bin/ls

$ ldd /bin/ls
linux-vdso.so.1 => (0x00007ffd22c47000)
libselinux.so.1 => /lib/x86_64-linux-gnu/libselinux.so.1 (0x00007ff5f2a6f000)
librt.so.1 => /lib/x86_64-linux-gnu/librt.so.1 (0x00007ff5f2867000)
libacl.so.1 => /lib/x86_64-linux-gnu/libacl.so.1 (0x00007ff5f265f000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007ff5f22a1000)
libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007ff5f209d000)
/lib64/ld-linux-x86⑹4.so.2 (0x00007ff5f2c8e000)
libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007ff5f1e80000)
libattr.so.1=>/lib/x86_64-linux-gnu/libattr.so.1(0x00007ff5f1c7b000)

可以看到ls命令依賴于librt.so.1庫,libc.so.6庫。。。

用gcc生成靜態(tài)和動(dòng)態(tài)連接庫的示例

我們通常把1些公用函數(shù)制作成函數(shù)庫,供其它程序使用。函數(shù)庫分為靜態(tài)庫和動(dòng)態(tài)庫兩種。靜態(tài)庫在程序編譯時(shí)會(huì)被連接到目標(biāo)代碼中,程序運(yùn)行時(shí)將不再需要該靜態(tài)庫。動(dòng)態(tài)庫在程序編譯時(shí)其實(shí)不會(huì)被連接到目標(biāo)代碼中,而是在程序運(yùn)行是才被載入,因此在程序運(yùn)行時(shí)還需要?jiǎng)討B(tài)庫存在。
本文主要通過舉例來講明在Linux中如何創(chuàng)建靜態(tài)庫和動(dòng)態(tài)庫,和使用它們。為了便于論述,我們先做1部份準(zhǔn)備工作。
準(zhǔn)備好測試代碼hello.h、hello.c和main.c;
hello.h(見程序1)為該函數(shù)庫的頭文件。
hello.c(見程序2)是函數(shù)庫的源程序,其中包括公用函數(shù)hello,該函數(shù)將在屏幕上輸出”HelloXXX!”。
main.c(見程序3)為測試庫文件的主程序,在主程序中調(diào)用了公用函數(shù)hello。
程序1:hello.h

#ifndefHELLO_H #defineHELLO_H void hello(constchar*name); #endif

程序2:hello.c

#include<stdio.h> void hello(constchar*name){ printf(“Hello%s!\n”,name); }

程序3:main.c

#include“hello.h” int main() { hello(“everyone”); return0; }

問題的提出
注意:這個(gè)時(shí)候,我們編譯好的hello.o是沒法通過gcc -o編譯的,這個(gè)道理非常簡單,hello.c是1個(gè)沒有main函數(shù)的.c程序,因此不夠成1個(gè)完全的程序,如果使用gcc -o編譯并連接它,GCC將報(bào)錯(cuò)。編譯main.c也會(huì)出錯(cuò),由于找不到hello的函數(shù)原型及實(shí)現(xiàn)。不管靜態(tài)庫,還是動(dòng)態(tài)庫,都是由.o文件創(chuàng)建的。因此,我們必須將源程序hello.c通過gcc先編譯成.o文件。
這個(gè)時(shí)候我們有3種思路:
1. 通過編譯多個(gè)源文件,直接將目標(biāo)代碼合成1個(gè).o文件。
2. 通過創(chuàng)建靜態(tài)連接庫libmyhello.a,使得main函數(shù)調(diào)用hello函數(shù)時(shí)可調(diào)用靜態(tài)連接庫.
3. 通過創(chuàng)建動(dòng)態(tài)連接庫libmyhello.so,使得main函數(shù)調(diào)用hello函數(shù)時(shí)可調(diào)用靜態(tài)連接庫。
思路1:編譯多個(gè)源文件
在系統(tǒng)提示符下鍵入以下命令得到hello.o文件。
$ gcc-chello.c
為何不使用gcc -o hello hello.cpp這個(gè)道理我們之前已說了,使用-c是甚么意思呢?
這觸及到gcc編譯選項(xiàng)的常識。我們通常使用的gcc –o是將.c源文件編譯成為1個(gè)可履行的2進(jìn)制代碼(-o選項(xiàng)實(shí)際上是制定輸出文件文件名,如果不加-c選項(xiàng),gcc默許會(huì)編譯連接生成可履行文件,文件的名稱有-o選項(xiàng)指定),這包括調(diào)用作為GCC內(nèi)的1部份真實(shí)的C編譯器(ccl),和調(diào)用GNU C編譯器的輸出中實(shí)際可履行代碼的外部GNU匯編器(as)和連接器工具(ld)。而gcc -c是使用GNU匯編器將源文件轉(zhuǎn)化為目標(biāo)代碼以后就結(jié)束,在這類情況下,只調(diào)用了C編譯器(ccl)和匯編器(as),而連接器(ld)并沒有被履行,所以輸出的目標(biāo)文件不會(huì)包括作為Linux程序在被裝載和履行時(shí)所必須的包括信息,但它可以在以后被連接到1個(gè)程序。
我們運(yùn)行l(wèi)s命令看看是不是生成了hello.o文件。

$ ls hello.c hello.h hello.o main.c

在ls命令結(jié)果中,我們看到了hello.o文件,本步操作完成。
同理編譯main
$ gcc–cmain.c
將兩個(gè)文件連接成1個(gè).o文件。
$gcc –o hello hello.o main.o
運(yùn)行
$./hello
Hello everyone!
完成^^
思路2:靜態(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)庫時(shí),需要注意這點(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)文件時(shí)指明靜態(tài)庫名,gcc將會(huì)從靜態(tài)庫中將公用函數(shù)連接到目標(biāo)文件中。注意,gcc會(huì)在靜態(tài)庫名前加上前綴lib,然后追加擴(kuò)大名.a得到的靜態(tài)庫文件名來查找靜態(tài)庫文件,因此,我們在寫需要連接的庫時(shí),只寫名字就能夠,如libmyhello.a的庫,只寫-lmyhello。其實(shí)也能夠直接在調(diào)用靜態(tài)庫的全名即libmyhello.a
在程序3:main.c中,我們包括了靜態(tài)庫的頭文件hello.h,然后在主程序main中直接調(diào)用公用函數(shù)hello。下面生成目標(biāo)程序hello,然后運(yùn)行hello程序看看結(jié)果如何。

方式1:$ gcc -o hellomain.c –static –L ./ -lmyhello 方式2:$ gcc -o hellomain.c –static –L ./ -libmyhello.a

兩種方式都可以生成已連接靜態(tài)庫的hello程序

$./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ù)已連接到目標(biāo)文件中了。
靜態(tài)連接庫的1個(gè)缺點(diǎn)是,如果我們同時(shí)運(yùn)行了許多程序,并且它們使用了同1個(gè)庫函數(shù),這樣,在內(nèi)存中會(huì)大量拷貝同1庫函數(shù)。這樣,就會(huì)浪費(fèi)很多珍貴的內(nèi)存和存儲(chǔ)空間。使用了同享連接庫的Linux就能夠避免這個(gè)問題。
同享函數(shù)庫和靜態(tài)函數(shù)在同1個(gè)地方,只是后綴有所不同。比如,在1個(gè)典型的Linux系統(tǒng),標(biāo)準(zhǔn)的同享數(shù)序函數(shù)庫是/usr/lib/libm.so。
當(dāng)1個(gè)程序使用同享函數(shù)庫時(shí),在連接階段其實(shí)不把函數(shù)代碼連接進(jìn)來,而只是連接函數(shù)的1個(gè)援用。當(dāng)終究的函數(shù)導(dǎo)入內(nèi)存開始真正履行時(shí),函數(shù)援用被解析,同享函數(shù)庫的代碼才真正導(dǎo)入到內(nèi)存中。這樣,同享連接庫的函數(shù)就能夠被許多程序同時(shí)同享,并且只需存儲(chǔ)1次就能夠了。同享函數(shù)庫的另外一個(gè)優(yōu)點(diǎn)是,它可以獨(dú)立更新,與調(diào)用它的函數(shù)絕不影響。
思路3、動(dòng)態(tài)連接庫(同享函數(shù)庫)
我們繼續(xù)看看如何在Linux中創(chuàng)建動(dòng)態(tài)庫。我們還是從.o文件開始。動(dòng)態(tài)庫文件名命名規(guī)范和靜態(tài)庫文件名命名規(guī)范類似,也是在動(dòng)態(tài)庫名增加前綴lib,但其文件擴(kuò)大名為.so。例如:我們將創(chuàng)建的動(dòng)態(tài)庫名為myhello,則動(dòng)態(tài)庫文件名就是libmyhello.so。用gcc來創(chuàng)建動(dòng)態(tài)庫。
在系統(tǒng)提示符下鍵入以下命令得到動(dòng)態(tài)庫文件libmyhello.so。

$ gcc -c -fPIC -o hello.o hello.c $ gcc –shared –o libmyhello.so hello.o

“PIC”命令行標(biāo)記告知GCC產(chǎn)生的代碼不要包括對函數(shù)和變量具體內(nèi)存位置的援用,這是由于現(xiàn)在還沒法知道使用該消息代碼的利用程序會(huì)將它連接到哪1段內(nèi)存地址空間。這樣編譯出的hello.o可以被用于建立同享連接庫。建立同享連接庫只需要用GCC的”-shared”標(biāo)記便可。
我們照樣使用ls命令看看動(dòng)態(tài)庫文件是不是生成。

$ls hello.cpphello.hhello.olibmyhello.somain.cpp

在程序中使用動(dòng)態(tài)庫和使用靜態(tài)庫完全1樣,也是在使用到這些公用函數(shù)的源程序中包括這些公用函數(shù)的原型聲明,然后在用gcc命令生成目標(biāo)文件時(shí)指明動(dòng)態(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ū)動(dòng)程序在連接階段援用同享函數(shù)庫libmyhello.so。“-L ./”標(biāo)記告知GCC函數(shù)庫可能位于當(dāng)前目錄。否則GNU連接器會(huì)查找標(biāo)準(zhǔn)系統(tǒng)函數(shù)目錄:它前后搜索
1. elf文件的DT_RPATH段
2. 環(huán)境變量LD_LIBRARY_PATH
3. /etc/ld.so.cache文件列表
4. /lib/
5. /usr/lib目錄
找到庫文件后將其載入內(nèi)存,但是我們生成的同享庫在當(dāng)前文件夾下,并沒有加到上述的4個(gè)路徑的任何1個(gè)中,因此,履行后會(huì)出現(xiàn)毛病)

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

毛病提示,找不到動(dòng)態(tài)庫文件libmyhello.so。程序在運(yùn)行時(shí),會(huì)在/usr/lib和/lib等目錄中查找需要的動(dòng)態(tài)庫文件。若找到,則載入動(dòng)態(tài)庫,否則將提示類似上述毛病而終止程序運(yùn)行。有多種方法可以解決,
我們將文件libmyhello.so復(fù)制到目錄/usr/lib中,再試試。

$mv libmyhello.so /usr/lib $./hello

成功!
既然連接器會(huì)搜索LD_LIBRARY_PATH所指定的目錄,那末我們可以將這個(gè)環(huán)境變量設(shè)置成當(dāng)前目錄:
先履行:
$exportLD_LIBRARY_PATH=$(pwd)
再履行:
$./hello
成功!
履行:
sudo ldconfig /usr/local/lib
注:當(dāng)用戶在某個(gè)目錄下面創(chuàng)建或拷貝了1個(gè)動(dòng)態(tài)連接庫,若想使其被系統(tǒng)同享,可以履行1下”ldconfig目錄名“這個(gè)命令.此命令的功能在于讓ldconfig將指定目錄下的動(dòng)態(tài)連接庫被系統(tǒng)同享起來,意即:在緩存文件/etc/ld.so.cache中追加進(jìn)指定目錄下的同享庫.本例讓系統(tǒng)同享了/usr/local/lib目錄下的動(dòng)態(tài)連接庫.該命令會(huì)重建/etc/ld.so.cache文件
成功!
這也進(jìn)1步說明了動(dòng)態(tài)庫在程序運(yùn)行時(shí)是需要的。
可以查看程序履行時(shí)調(diào)用動(dòng)態(tài)庫的進(jìn)程:
$ld dhello
履行test,可以看到它是如何調(diào)用動(dòng)態(tài)庫中的函數(shù)的。

$lddhello linux-gate.so.1=>(0x00110000) libmyhello.so=>/usr/lib/libmyhello.so(0x00111000) libc.so.6=>/lib/libc.so.6(0x00859000) /lib/ld-linux.so.2(0x0083a000)

ok,程序調(diào)用動(dòng)態(tài)庫的功能完成。

gcc編譯解析

C和C++編譯器是集成的,它們都需要1個(gè)或多個(gè)處理輸入文件:預(yù)處理(perprocessing),編譯(compilation),匯編(assembly)和連接(linking)。
整體選項(xiàng)
-c :編譯或匯編文件,但是不做連接。缺省情況下,GCC通過使用‘.o’來替換源文件名后綴‘.c’,‘.i’,‘.s’等等
-o file: 指定輸出的可履行文件為file且只能輸出1個(gè)可履行文件,如果沒有使用‘-o’選項(xiàng)及命令為gcc xx.c。
連接器選項(xiàng)
-shared:生成1個(gè)同享目標(biāo)文件,它可以和其它目標(biāo)文件連接產(chǎn)生可履行文件。
-llibrary: 連接名為library的庫文件。連接器會(huì)在標(biāo)準(zhǔn)搜索目錄中尋覓這個(gè)庫文件。搜索目錄除1些標(biāo)準(zhǔn)的搜索目錄外還包括用戶使用‘-L’選項(xiàng)指定的路徑
目錄選項(xiàng)
-Ldir:在‘-L’選項(xiàng)的搜索連接列表主功能添加dir目錄
LD_LIBRARY_PATH:這個(gè)環(huán)境變量唆使動(dòng)態(tài)連接器可以裝載動(dòng)態(tài)庫的路徑。
代碼生成選項(xiàng):
-fPIC:表示編譯為位置獨(dú)立的代碼(適用于同享庫),不用此選項(xiàng)的話編譯后的代碼是位置相干的所以動(dòng)態(tài)載入時(shí)是通過代碼拷貝的方式來滿足不同進(jìn)程的需要,而不能到達(dá)真正代碼段同享的目的。
正告選項(xiàng)
-Wall:顯示大部份常見的正告,如:定義了變量沒有使用,變量未初始化等等
調(diào)試選項(xiàng)
-g:以操作系統(tǒng)的本地格式產(chǎn)生調(diào)試信息,GDB能夠使用這些調(diào)試信息,進(jìn)行程序調(diào)試

參考文章:Linux下Gcc生成和使用靜態(tài)庫和動(dòng)態(tài)庫詳解(轉(zhuǎn))

生活不易,碼農(nóng)辛苦
如果您覺得本網(wǎng)站對您的學(xué)習(xí)有所幫助,可以手機(jī)掃描二維碼進(jìn)行捐贈(zèng)
程序員人生
------分隔線----------------------------
分享到:
------分隔線----------------------------
關(guān)閉
程序員人生
主站蜘蛛池模板: 欧美 日韩 国产 成人 在线 | 91一区二区三区 | 国产精品爱啪在线线免费观看 | 国产成人欧美一区二区三区八 | 精品视频在线一区 | 日韩精品久久 | 国产精品久久久久久久久久久久久久 | 国产精品美女久久久久 | a在线观看 | 国产日韩一区二区 | 国产成人免费视频 | 亚洲精品国产区欧美区在线 | a天堂在线 | 黄色一及视频 | 欧美中文 | 久久综合伊人77777 | 在线播放国产视频 | 国产精品一区久久 | 久久成人在线视频 | 久久99国产精一区二区三区 | 亚洲精品一二区 | 中文字幕在线不卡视频 | 精品一区二区在线播放 | 亚洲视频在线免费观看 | 偷自拍视频区综合视频区 | 午夜欧美一区二区三区在线播放 | 久久久久久国产精品 | av最新网址 | 黄色录像a级| 免费国产一区二区 | 亚洲综合国产 | 国内精品视频在线 | 国产精品久久久久婷婷二区次 | 成人深夜视频 | 最近中文字幕在线视频 | 国产乱人伦 | 久久久国产一区二区三区 | 国产玖玖| 欧美在线一区二区三区 | 岛国视频在线 | 国产激情网 |