gcc用法以及靜態(tài)/動態(tài)鏈接

安裝

yum install gcc gcc-c++

選項

-E:只進(jìn)行預(yù)處理,不編譯
-S:只編譯,不匯編
-c:只編譯、匯編,不鏈接
-g:編譯器在編譯的時候產(chǎn)生調(diào)試信息。
-I:指定include包含文件的搜索目錄
-o:輸出成指定文件名,如果缺省則輸出位a.out
-L:搜索庫的路徑
-l:指定程序要鏈接的庫
-w:忽略所有警告
-shared:指定生成動態(tài)鏈接庫。
-static:指定生成靜態(tài)鏈接庫。
-fPIC:表示編譯為位置獨(dú)立的代碼,用于編譯共享庫。目標(biāo)文件需要創(chuàng)建成位置無關(guān)碼,概念上就是在可執(zhí)行程序裝載它們的時候,它們可以放在可執(zhí)行程序的內(nèi)存里的任何地方。

-l參數(shù)和-L參數(shù)

  • -l參數(shù)就是用來指定程序要鏈接的庫,-l參數(shù)緊接著就是庫名。那么庫名跟真正的庫文件名有什么關(guān)系呢?
    就拿數(shù)學(xué)庫來說,他的庫名是m,他的庫文件名是libm.so,很容易看出,把庫文件名的頭lib和尾.so去掉就是庫名了。好了現(xiàn)在我們知道怎么得到庫名,當(dāng)我們自已要用到一個第三方提供的庫名字libtest.so,那么我們只要把libtest.so拷貝到/usr/lib里,編譯時加上-ltest參數(shù),我們就能用上libtest.so庫了(當(dāng)然要用libtest.so庫里的函數(shù),我們還需要與libtest.so配套的頭文件)。
    放在/lib/usr/lib/usr/local/lib里的庫直接用-l參數(shù)就能鏈接了,但如果庫文件沒放在這三個目錄里,而是放在其他目錄里,這時我們只用-l參數(shù)的話,鏈接還是會出錯,出錯信息大概是:“/usr/bin/ld: cannot find -lxxx”,也就是鏈接程序ld在那3個目錄里找不到libxxx.so,這時另外一個參數(shù)-L就派上用場了。

  • -L 比如常用的X11的庫,它在/usr/X11R6/lib目錄下,我們編譯時就要用-L/usr/X11R6/lib -lX11參數(shù),-L參數(shù)跟著的是庫文件所在的目錄名。再比如我們把libtest.so放在/aaa/bbb/ccc目錄下,那鏈接參數(shù)就是-L/aaa/bbb/ccc -ltest。 gcc默認(rèn)會在程序當(dāng)前目錄、/lib/usr/lib/usr/local/lib下找對應(yīng)的庫

-I參數(shù)

  • -include和-I參數(shù)

    在你是用#include '***.h'的時候,gcc/g++會先在當(dāng)前目錄查找你所制定的頭文件,如果沒有找到,他回到缺省的頭文件目錄找,如果使用-I制定了目錄,他回先在你所制定的目錄查找,然后再按常規(guī)的順序去找.對于#include,gcc/g++會到-I制定的目錄查找,查未找到,然后將到系統(tǒng)的缺省的頭文件目錄查找。
    #include有兩種方式

  • 使用<>包含的頭文件一般會先搜索-I選項后的路徑(即用gcc編譯時的-I選項),之后就是標(biāo)準(zhǔn)的系統(tǒng)頭文件路徑。

  • 而用""號包含的頭文件會首先搜索當(dāng)前的工作目錄,之后的搜索路徑才是和<>號包含的頭文件所搜索的路徑一樣的路徑。

Linux下的標(biāo)準(zhǔn)頭文件路徑為/usr/include/usr/local/include

2.png
1.png

.a 和.so

靜態(tài)函數(shù)庫

靜態(tài)函數(shù)庫,這類庫的名字一般是libxxx.a
利用靜態(tài)函數(shù)庫編譯成的文件比較大,因?yàn)檎麄€函數(shù)庫的所有數(shù)據(jù)都會被整合進(jìn)目標(biāo)代碼中。
優(yōu)點(diǎn)就顯而易見了,即編譯后的執(zhí)行程序不需要外部的函數(shù)庫支持,因?yàn)樗惺褂玫暮瘮?shù)都已經(jīng)被編譯進(jìn)去了。當(dāng)然這也會成為缺點(diǎn)如果靜態(tài)函數(shù)庫改變了,那么你的程序必須重新編譯。

共享函數(shù)庫

這類庫的名字一般是libxxx.so
相對于靜態(tài)函數(shù)庫,共享函數(shù)庫在編譯的時候 并沒有被編譯進(jìn)目標(biāo)代碼中。當(dāng)程序執(zhí)行到相關(guān)函數(shù)時才調(diào)用共享函數(shù)庫里相應(yīng)的函數(shù),因此共享函數(shù)庫所產(chǎn)生的可執(zhí)行文件比較小。
由于共享函數(shù)庫沒有被整合進(jìn)你的程序,而是在程序運(yùn)行時動態(tài)地申請并調(diào)用,所以程序的運(yùn)行環(huán)境中必須提供相應(yīng)的庫.
共享函數(shù)庫的改變并不影響你的程序,所以共享函數(shù)庫的升級比較方便.

示例

先上頭文件hello.h

#ifndef HELLO_H
#define  HELLO_H
void show();
#endif

分別做兩個實(shí)現(xiàn),hello_static.cpp和hello_dynamic.cpp。代碼很簡單就是打印一句話做一個區(qū)分,方便我們后面測試鏈接的哪個庫。
hello_static.cpp

#include "hello.h"
#include <iostream>
using namespace std;
void show(){
  cout<<"hello static"<<endl;
}

hello_dynamic.cpp

#include "hello.h"
#include <iostream>
using namespace std;
void show(){
  cout<<"hello dynamic"<<endl;
}

測試主程序main.cpp

#include "hello.h"
int main(){
  show();
  return 0;
}

下面我們寫Makefile然后進(jìn)行編譯:

all : hello_static.o libhello.a libhello.so  main_s main_d

hello_static.o : hello_static.cpp
    g++ -c hello_static.cpp
    
libhello.a : hello_static.o
    ar crs libhello.a hello_static.o

libhello.so : hello_dynamic.cpp
    g++ -o $@ $+  -fPIC -shared

main_s : main.cpp
    g++  -static -o $@ $+ -I. -lhello -L.

main_d : main.cpp
    g++ -o $@ $+ -I. -lhello -L.

.PHONY : clean
clean :
    -rm hello_static.o libhello.a libhello.so main_s main_d

在鏈接hello時,會以共享庫文件優(yōu)先. 如果同時存在靜態(tài)庫和共享庫,可以使用-static強(qiáng)制使用靜態(tài)庫。當(dāng)然也可以直接指定libhello.a。如:

g++ -o $@ $+ -I.  -L.  libhello.a

完成Makefile后,就可以進(jìn)行編譯,執(zhí)行make命令,生成hello_static.olibhello.alibhello.somain_smain_d等文件。而main_s是我們靜態(tài)鏈接生成的,main_d是動態(tài)鏈接。我們分別運(yùn)行后:

[root@localhost gcc]# ./main_d 
hello dynamic
[root@localhost gcc]# ./main_s
hello static

與我們預(yù)期一致。

問題

靜態(tài)鏈接使用-static出現(xiàn)錯誤:
/usr/bin/ld: cannot find -lm
collect2: ld 返回 1
make: *** [main_s] 錯誤 1

安裝glibc-devel即可

找不到動態(tài)庫
./main_d: error while loading shared libraries: libhello.so: cannot open shared object file: No such file or directory

這里是需要設(shè)置環(huán)境變量,可參考Linux環(huán)境變量介紹和區(qū)別。也就是我們需要將so文件設(shè)置到環(huán)境變量中。直接編輯.bashrc文件

vim ~/.bashrc

添加:

export LD_LIBRARY_PATH=/code/gcc

保存退出后,使其生效。

source ~/.bashrc
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,936評論 6 535
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,744評論 3 421
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,879評論 0 381
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,181評論 1 315
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 71,935評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,325評論 1 324
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,384評論 3 443
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,534評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,084評論 1 335
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 40,892評論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 43,067評論 1 371
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,623評論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,322評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,735評論 0 27
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,990評論 1 289
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,800評論 3 395
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 48,084評論 2 375

推薦閱讀更多精彩內(nèi)容