安裝
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
.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.o
、libhello.a
、 libhello.so
、main_s
、main_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