安裝
yum install gcc gcc-c++
選項
-E:只進行預(yù)處理,不編譯
-S:只編譯,不匯編
-c:只編譯、匯編,不鏈接
-g:編譯器在編譯的時候產(chǎn)生調(diào)試信息。
-I:指定include包含文件的搜索目錄
-o:輸出成指定文件名,如果缺省則輸出位a.out
-L:搜索庫的路徑
-l:指定程序要鏈接的庫
-w:忽略所有警告
-shared:指定生成動態(tài)鏈接庫。
-static:指定生成靜態(tài)鏈接庫。
-fPIC:表示編譯為位置獨立的代碼,用于編譯共享庫。目標(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ù)庫編譯成的文件比較大,因為整個函數(shù)庫的所有數(shù)據(jù)都會被整合進目標(biāo)代碼中。
優(yōu)點就顯而易見了,即編譯后的執(zhí)行程序不需要外部的函數(shù)庫支持,因為所有使用的函數(shù)都已經(jīng)被編譯進去了。當(dāng)然這也會成為缺點如果靜態(tài)函數(shù)庫改變了,那么你的程序必須重新編譯。
共享函數(shù)庫
這類庫的名字一般是libxxx.so
相對于靜態(tài)函數(shù)庫,共享函數(shù)庫在編譯的時候 并沒有被編譯進目標(biāo)代碼中。當(dāng)程序執(zhí)行到相關(guān)函數(shù)時才調(diào)用共享函數(shù)庫里相應(yīng)的函數(shù),因此共享函數(shù)庫所產(chǎn)生的可執(zhí)行文件比較小。
由于共享函數(shù)庫沒有被整合進你的程序,而是在程序運行時動態(tài)地申請并調(diào)用,所以程序的運行環(huán)境中必須提供相應(yīng)的庫.
共享函數(shù)庫的改變并不影響你的程序,所以共享函數(shù)庫的升級比較方便.
示例
先上頭文件hello.h
#ifndef HELLO_H
#define HELLO_H
void show();
#endif
分別做兩個實現(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然后進行編譯:
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強制使用靜態(tài)庫。當(dāng)然也可以直接指定libhello.a。如:
g++ -o $@ $+ -I. -L. libhello.a
完成Makefile后,就可以進行編譯,執(zhí)行make命令,生成hello_static.o、libhello.a、 libhello.so、main_s、main_d等文件。而main_s是我們靜態(tài)鏈接生成的,main_d是動態(tài)鏈接。我們分別運行后:
[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