GCC常用参数详解
簡介
gcc and g++現(xiàn)在是gnu中最主要和最流行的c & c++編譯器 .gcc/g++在執(zhí)行編譯工作的時候,總共需要以下幾步:
1.預(yù)處理,生成.i的文件[預(yù)處理器cpp]
2.將預(yù)處理后的文件不轉(zhuǎn)換成匯編語言,生成文件.s[編譯器egcs]
3.有匯編變?yōu)槟繕?biāo)代碼(機(jī)器代碼)生成.o的文件[匯編器as]
4.連接目標(biāo)代碼,生成可執(zhí)行程序[鏈接器ld]
GCC能夠處理的后綴有:
a. *.c *.C (C語言)
b. *.cxx *.cc (C++語言)
c. *.m (面向?qū)ο蟮腃)
d. *.i (預(yù)處理后的C語言源文件)
e. *.ii (預(yù)處理后的C++語言源文件)
f. *.s *.S (匯編語言)
h. *.h (頭文件)
目標(biāo)文件可以是:
a. *.o 編譯連接后的目標(biāo)文件
b. *.a 庫文件?
?
gcc與g++有什么區(qū)別??
gcc和g++都是GNU(組織)的一個編譯器。
誤區(qū)一:gcc只能編譯c代碼,g++只能編譯c++代碼
兩者都可以,但是請注意:
1.后綴為.c的,gcc把它當(dāng)作是C程序,而g++當(dāng)作是c++程序;后綴為.cpp的,兩者都會認(rèn)為是c++程序,注意,雖然c++是c的超集,但是兩者對語法的要求是有區(qū)別的。C++的語法規(guī)則更加嚴(yán)謹(jǐn)一些。
2.編譯階段,g++會調(diào)用gcc,對于c++代碼,兩者是等價的,但是因為gcc命令不能自動和C++程序使用的庫聯(lián)接,所以通常用g++來完成鏈接,為了統(tǒng)一起見,干脆編譯/鏈接統(tǒng)統(tǒng)用g++了,這就給人一種錯覺,好像cpp程序只能用g++似的。
?
誤區(qū)二:gcc不會定義__cplusplus宏,而g++會
實際上,這個宏只是標(biāo)志著編譯器將會把代碼按C還是C++語法來解釋,如上所述,如果后綴為.c,并且采用gcc編譯器,則該宏就是未定義的,否則,就是已定義。
?
誤區(qū)三:編譯只能用gcc,鏈接只能用g++
嚴(yán)格來說,這句話不算錯誤,但是它混淆了概念,應(yīng)該這樣說:編譯可以用gcc/g++,而鏈接可以用g++或者gcc -lstdc++。因為gcc命令不能自動和C++程序使用的庫聯(lián)接,所以通常使用g++來完成聯(lián)接。但在編譯階段,g++會自動調(diào)用gcc,二者等價
參數(shù)詳解
無選項編譯鏈接
? ? 將test.c預(yù)處理、匯編、編譯并鏈接形成可執(zhí)行文件。這里未指定輸出文件,默認(rèn)輸出為a.out。
? ? 例子用法:
? ? gcc test.c
無選項鏈接
? ? gcc test.o -o test
? ? 將編譯輸出文件test.o鏈接成最終可執(zhí)行文件test。
-x language filename ?
設(shè)定文件所使用的語言,使后綴名無效,對以后的多個有效.也就是根據(jù)約定C語言的后綴名稱是.c的,而C++的后綴名是.C或者.cpp,如果你很個性,決定你的C代碼文件的后綴名是.pig 哈哈,那你就要用這個參數(shù),這個參數(shù)對他后面的文件名都起作用,除非到了下一個參數(shù)的使用。 ?
可以使用的參數(shù)嗎有下面的這些 ?
`c', `objective-c', `c-header', `c++', `cpp-output', `assembler', and `assembler-with-cpp'. ?
看到英文,應(yīng)該可以理解的。 ?
例子用法: ?
gcc -x c hello.pig ?
?
-x none filename ?
關(guān)掉上一個選項,也就是讓gcc根據(jù)文件名后綴,自動識別文件類型 ?
例子用法: ?
gcc -x c hello.pig -x none hello2.c ?
?
-c ?
只激活預(yù)處理,編譯,和匯編,也就是他只把程序做成obj文件 ?
例子用法: ?
gcc -c hello.c ?
他將生成.o的obj文件
? ? ? gcc -c test.s
? ? ? 將匯編輸出文件test.s編譯輸出test.o文件。 ?
-S ?
只激活預(yù)處理和編譯,就是指把文件編譯成為匯編代碼。 ?
例子用法: ?
gcc -S hello.c ?
他將生成.s的匯編代碼,你可以用文本編輯器察看
? ? ? gcc -S test.i ?
? ? ? 將預(yù)處理輸出文件test.i匯編成test.s文件?
-E ?
只激活預(yù)處理,這個不生成文件,你需要把它重定向到一個輸出文件里面. ?
例子用法:?
gcc -E hello.c >; pianoapan.txt ?
gcc -E hello.c | more ?
慢慢看吧,一個hello word 也要與處理成800行的代碼
? ? ?gcc -E test.c -o test.i ?
-o ?
制定目標(biāo)名稱,缺省的時候,gcc 編譯出來的文件是a.out,很難聽,如果你和我有同感,改掉它,哈哈 ?
例子用法: ?
gcc -o hello.exe hello.c (哦,windows用習(xí)慣了) ?
gcc -o hello.asm -S hello.c ?
-pipe ?
使用管道代替編譯中臨時文件,在使用非gnu匯編工具的時候,可能有些問題 ?
gcc -pipe -o hello.exe hello.c ?
-ansi ?
關(guān)閉gnu c中與ansi c不兼容的特性,激活ansi c的專有特性(包括禁止一些asm inline typeof關(guān)鍵字,以及UNIX,vax等預(yù)處理宏, ?
-fno-asm ?
此選項實現(xiàn)ansi選項的功能的一部分,它禁止將asm,inline和typeof用作關(guān)鍵字。 ?
-fno-strict-prototype ?
只對g++起作用,使用這個選項,g++將對不帶參數(shù)的函數(shù),都認(rèn)為是沒有顯式的對參數(shù)的個數(shù)和類型說明,而不是沒有參數(shù). ?
而gcc無論是否使用這個參數(shù),都將對沒有帶參數(shù)的函數(shù),認(rèn)為城沒有顯式說明的類型 ?
?
-fthis-is-varialble ?
就是向傳統(tǒng)c++看齊,可以使用this當(dāng)一般變量使用. ?
?
-fcond-mismatch ?
允許條件表達(dá)式的第二和第三參數(shù)類型不匹配,表達(dá)式的值將為void類型 ?
?
-funsigned-char ?
-fno-signed-char ?
-fsigned-char ?
-fno-unsigned-char ?
這四個參數(shù)是對char類型進(jìn)行設(shè)置,決定將char類型設(shè)置成unsigned char(前兩個參數(shù))或者 signed char(后兩個參數(shù)) ?
?
-include file ?
包含某個代碼,簡單來說,就是便以某個文件,需要另一個文件的時候,就可以用它設(shè)定,功能就相當(dāng)于在代碼中使用#include<filename>; ?
例子用法: ?
gcc hello.c -include /root/pianopan.h ?
?
-imacros file ?
將file文件的宏,擴(kuò)展到gcc/g++的輸入文件,宏定義本身并不出現(xiàn)在輸入文件中 ?
?
-Dmacro?
? ? 以字符串“1”定義 MACRO 宏?
相當(dāng)于C語言中的#define macro ?
?
-Dmacro=defn
? ? 以字符串“DEFN”定義 MACRO 宏 ?
相當(dāng)于C語言中的#define macro defn ?
??
-Umacro?
? ? 取消對 MACRO 宏的定義?
相當(dāng)于C語言中的#undef macro ?
-undef ?
取消對任何非標(biāo)準(zhǔn)宏的定義 ?
?
-Idir ?
在你是用#include"file"的時候,gcc/g++會先在當(dāng)前目錄查找你所制定的頭文件,如果沒有找到,他回到缺省的頭文件目錄找,如果使用-I制定了目錄,他 ?
回先在你所制定的目錄查找,然后再按常規(guī)的順序去找. ?
對于#include<file>;,gcc/g++會到-I制定的目錄查找,查找不到,然后將到系統(tǒng)的缺省的頭文件目錄查找 ?
?
-I- ?
就是取消前一個參數(shù)的功能,所以一般在-Idir之后使用 ?
?
-idirafter dir ?
在-I的目錄里面查找失敗,講到這個目錄里面查找. ?
?
-iprefix prefix ?
-iwithprefix dir ?
一般一起使用,當(dāng)-I的目錄查找失敗,會到prefix+dir下查找 ?
?
-nostdinc ?
使編譯器不再系統(tǒng)缺省的頭文件目錄里面找頭文件,一般和-I聯(lián)合使用,明確限定頭文件的位置 ?
?
-nostdin C++ ?
規(guī)定不在g++指定的標(biāo)準(zhǔn)路經(jīng)中搜索,但仍在其他路徑中搜索,.此選項在創(chuàng)libg++庫使用 ?
?
-C ?
在預(yù)處理的時候,不刪除注釋信息,一般和-E使用,有時候分析程序,用這個很方便的 ?
?
-M ?
生成文件關(guān)聯(lián)的信息。包含目標(biāo)文件所依賴的所有源代碼你可以用gcc -M hello.c來測試一下,很簡單。 ?
?
-MM ?
和上面的那個一樣,但是它將忽略由#include<file>;造成的依賴關(guān)系。 ?
?
-MD ?
和-M相同,但是輸出將導(dǎo)入到.d的文件里面 ?
?
-MMD ?
和-MM相同,但是輸出將導(dǎo)入到.d的文件里面 ?
?
-Wa,option ?
此選項傳遞option給匯編程序;如果option中間有逗號,就將option分成多個選項,然后傳遞給會匯編程序 ?
?
-Wl.option ?
此選項傳遞option給連接程序;如果option中間有逗號,就將option分成多個選項,然后傳遞給會連接程序. ?
?
-llibrary ?
制定編譯的時候使用的庫 ?
例子用法 ?
gcc -lcurses hello.c ?
使用ncurses庫編譯程序 ?
?
-Ldir ?
制定編譯的時候,搜索庫的路徑。比如你自己的庫,可以用它制定目錄,不然 ?
編譯器將只在標(biāo)準(zhǔn)庫的目錄找。這個dir就是目錄的名稱。 ?
?
-O0 ?
-O1 ?
-O2 ?
-O3 ?
編譯器的優(yōu)化選項的4個級別,-O0表示沒有優(yōu)化,-O1為缺省值,-O3優(yōu)化級別最高
? ? 例子用法:
? ? gcc -O1 test.c -o test
? ? 使用編譯優(yōu)化級別1編譯程序。級別為1~3,級別越大優(yōu)化效果越好,但編譯時間越長
?
-g ?
只是編譯器,在編譯的時候,產(chǎn)生調(diào)試信息。 ?
?
-gstabs ?
此選項以stabs格式聲稱調(diào)試信息,但是不包括gdb調(diào)試信息. ?
?
-gstabs+ ?
此選項以stabs格式聲稱調(diào)試信息,并且包含僅供gdb使用的額外調(diào)試信息. ?
?
-ggdb ?
此選項將盡可能的生成gdb的可以使用的調(diào)試信息. ?
-static ?
此選項將禁止使用動態(tài)庫,所以,編譯出來的東西,一般都很大,也不需要什么 ?
動態(tài)連接庫,就可以運行. ?
-share ?
此選項將盡量使用動態(tài)庫,所以生成文件比較小,但是需要系統(tǒng)由動態(tài)庫. ?
-traditional ?
試圖讓編譯器支持傳統(tǒng)的C語言特性?
?
-IDIRECTORY?
? ? 指定額外的頭文件搜索路徑DIRECTORY
-LDIRECTORY?
? ? 指定額外的函數(shù)庫搜索路徑DIRECTORY
??
-lLIBRARY?
? ? 連接時搜索指定的函數(shù)庫LIBRARY
-m486
? ? 針對 486 進(jìn)行代碼優(yōu)化?
-shared?
? ? 生成共享目標(biāo)文件。通常用在建立共享庫時 ?
-static
? ? 禁止使用共享連接
??
-w?
? ? 不生成任何警告信息
??
-Wall?
? ? 生成所有警告信息
?
-save-temps
? ? 一次獲得全部的中文輸出文件,正常的進(jìn)行編譯連接,.i、.s、.o為后綴,文件名相同
-fsyntax-only
? ? 不會執(zhí)行預(yù)處理、編譯、匯編、連接,只會測試輸入文件的語法是否正確
? ?
-std
? ? 指定C方言,如:-std=c99,gcc默認(rèn)的方言是GNU C?
多源文件的編譯方法
如果有多個源文件,基本上有兩種編譯方法:
[假設(shè)有兩個源文件為test.c和testfun.c]
1. 多個文件一起編譯
用法:#gcc testfun.c test.c -o test
作用:將testfun.c和test.c分別編譯后鏈接成test可執(zhí)行文件。
2. 分別編譯各個源文件,之后對編譯后輸出的目標(biāo)文件鏈接。
用法:
#gcc -c testfun.c //將testfun.c編譯成testfun.o
#gcc -c test.c //將test.c編譯成test.o
#gcc -o testfun.o test.o -o test //將testfun.o和test.o鏈接成test
以上兩種方法相比較,第一中方法編譯時需要所有文件重新編譯,而第二種方法可以只重新編譯修改的文件,未修改的文件不用重新編譯。?
FAQ
1、為什么會出現(xiàn)undefined reference to 'xxxxx'錯誤?
首先這是鏈接錯誤,不是編譯錯誤,也就是說如果只有這個錯誤,說明你的程序源碼本身沒有問題,是你用編譯器編譯時參數(shù)用得不對,你沒有指定鏈接程序要用到得庫,比如你的程序里用到了一些數(shù)學(xué)函數(shù),那么你就要在編譯參數(shù)里指定程序要鏈接數(shù)學(xué)庫,方法是在編譯命令行里加入-lm。
2、-l參數(shù)和-L參數(shù)
-l參數(shù)就是用來指定程序要鏈接的庫,-l參數(shù)緊接著就是庫名,那么庫名跟真正的庫文
件名有什么關(guān)系呢?
就拿數(shù)學(xué)庫來說,他的庫名是m,他的庫文件名是libm.so,很容易看出,把庫文件名的頭lib和尾.so去掉就是庫名了。
好了現(xiàn)在我們知道怎么得到庫名了,比如我們自已要用到一個第三方提供的庫名字叫l(wèi)ibtest.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就派上用場了,比如常用的X11的庫,它放在/usr/X11R6/lib目錄下,我們編譯時就要用-L/usr/X11R6/lib -lX11參數(shù),-L參數(shù)跟著的是庫文件所在的目錄名。
再比如我們把libtest.so放在/aaa/bbb/ccc目錄下,那鏈接參數(shù)就是-L/aaa/bbb/ccc -ltest
另外,大部分libxxxx.so只是一個鏈接,以RH9為例,比如libm.so它鏈接到/lib/libm.so.x,/lib/libm.so.6又鏈到/lib/libm-2.3.2.so,如果沒有這樣的鏈接,還是會出錯,因為ld只會找libxxxx.so,所以如果你要用到xxxx庫,而只有l(wèi)ibxxxx.so.x或者libxxxx-x.x.x.so,做一個鏈接就可以了ln -s libxxxx-x.x.x.so libxxxx.so,手工來寫鏈接參數(shù)總是很麻煩的,還好很多庫開發(fā)包提供了生成鏈接參數(shù)的程序,名字一般叫xxxx-config,一般放在/usr/bin目錄下,比如gtk1.2的鏈接參數(shù)生成程序是gtk-config,執(zhí)行g(shù)tk-config --libs就能得到以下輸出"-L/usr/lib -L/usr/X11R6/lib -lgtk -lgdk -rdynamic -lgmodule -lglib -ldl -lXi -lXext -lX11 -lm",這就是編譯一個gtk1.2程序所需的gtk鏈接參數(shù),xxx-config除了--libs參數(shù)外還有一個參數(shù)是--cflags用來生成頭文件包含目錄的,也就是-I參數(shù),在下面我們將會講到。你可以試試執(zhí)行g(shù)tk-config --libs --cflags,看看輸出結(jié)果。現(xiàn)在的問題就是怎樣用這些輸出結(jié)果了,最笨的方法就是復(fù)制粘貼或者照抄,聰明的辦法是在編譯命令行里加入這個`xxxx-config --libs --cflags`,比如編譯一個gtk程序:gcc gtktest.c `gtk-config --libs --cflags`這樣就差不多了。注意`不是單引號,而是1鍵左邊那個鍵。除了xxx-config以外,現(xiàn)在新的開發(fā)包一般都用pkg-config來生成鏈接參數(shù),使用方法跟xxx-config類似,但xxx-config是針對特定的開發(fā)包,但pkg-config包含很多開發(fā)包的鏈接參數(shù)的生成,用pkg-config --list-all命令可以列出所支持的所有開發(fā)包,pkg-config的用法就是pkg-config pagName --libs --cflags,其中pagName是包名,是pkg-config--list-all里列出名單中的一個,比如gtk1.2的名字就是gtk+,pkg-config gtk+ --libs --cflags的作用跟gtk-config --libs --cflags是一樣的。比如:gcc gtktest.c `pkg-config gtk+ --libs --cflags`。
?
?
3、-include和-I參數(shù)
-include用來包含頭文件,但一般情況下包含頭文件都在源碼里用#include xxxxxx實現(xiàn),-include參數(shù)很少用。-I參數(shù)是用來指定頭文件目錄,/usr/include目錄一般是不用指定的,gcc知道去那里找,但是如果頭文件不在/usr/include里我們就要用-I參數(shù)指定了,比如頭文件放在/myinclude目錄里,那編譯命令行就要加上-I/myinclude參數(shù)了,如果不加你會得到一個"xxxx.h: No such file or directory"的錯誤。-I參數(shù)可以用相對路徑,比如頭文件在當(dāng)前目錄,可以用-I.來指定。上面我們提到的--cflags參數(shù)就是用來生成-I參數(shù)的。
4、幾個相關(guān)的環(huán)境變量
PKG_CONFIG_PATH:用來指定pkg-config用到的pc文件的路徑,默認(rèn)是/usr/lib/pkgconfig,pc文件是文本文件,擴(kuò)展名是.pc,里面定義開發(fā)包的安裝路徑,Libs參數(shù)和Cflags參數(shù)等等。
CC:用來指定c編譯器。
CXX:用來指定cxx編譯器。
LIBS:跟上面的--libs作用差不多。
CFLAGS:跟上面的--cflags作用差不多。
CC,CXX,LIBS,CFLAGS手動編譯時一般用不上,在做configure時有時用到,一般情況下不用管。
環(huán)境變量設(shè)定方法:export ENV_NAME=xxxxxxxxxxxxxxxxx
CPATH、C_INCLUDE_PATH ?
用逗號隔開的目錄列表,提供頭文件搜索位置
COMPILER_PATH
用逗號隔開的目錄列表,以提供GCC子程序的搜索位置
GCC_EXEC_PREFIX
當(dāng)GCC調(diào)用子程序時,需要“加在前面”的前置名稱
LIBRARY_PATH
用逗號隔開的目錄列表,以提供連接庫的位置
LD_LIBRARY_PATH
用逗號隔開的目錄列表,以提供共享庫文件的搜索位置
TMPDIR
臨時文件所使用的目錄
?
5、關(guān)于交叉編譯
交叉編譯通俗地講就是在一種平臺上編譯出能運行在體系結(jié)構(gòu)不同的另一種平臺上,比如在我們地PC平臺(X86 CPU)上編譯出能運行在sparc CPU平臺上的程序,編譯得到的程序在X86 CPU平臺上是不能運行的,必須放到sparc CPU平臺上才能運行。當(dāng)然兩個平臺用的都是linux。
這種方法在異平臺移植和嵌入式開發(fā)時用得非常普遍。
總結(jié)
- 上一篇: Kafka 不停机修改某一个topic数
- 下一篇: Hbase Memstore刷新方式与R