linux gcc g++编译命令选项
gcc/g++在執行編譯工作的時候,總共需要4步
1.預處理,生成.i的文件[預處理器cpp]
2.將預處理后的文件不轉換成匯編語言,生成文件.s[編譯器egcs]
3.有匯編變為目標代碼(機器代碼)生成.o的文件[匯編器as]
4.連接目標代碼,生成可執行程序[鏈接器ld]
[參數詳解]
-c
只激活預處理,編譯,和匯編,也就是他只把程序做成obj文件
例子用法:
gcc -c hello.c
他將生成.o的obj文件
-S
只激活預處理和編譯,就是指把文件編譯成為匯編代碼。
例子用法
gcc -S hello.c
他將生成.s的匯編代碼,你可以用文本編輯器察看
-E
只激活預處理,這個不生成文件,你需要把它重定向到一個輸出文件里
面.
例子用法:
gcc -E hello.c > pianoapan.txt
gcc -E hello.c | more
慢慢看吧,一個hello word 也要與處理成800行的代碼
-o
制定目標名稱,缺省的時候,gcc 編譯出來的文件是a.out,很難聽,如果
你和我有同感,改掉它,哈哈
例子用法
gcc -o hello.exe hello.c (哦,windows用習慣了)
-pipe
使用管道代替編譯中臨時文件,在使用非gnu匯編工具的時候,可能有些問
題
gcc -pipe -o hello.exe hello.c
-ansi
關閉gnu c中與ansi c不兼容的特性,激活ansi c的專有特性(包括禁止一
些asm inline typeof關鍵字,以及UNIX,vax等預處理宏,
-fno-asm
此選項實現ansi選項的功能的一部分,它禁止將asm,inline和typeof用作
關鍵字。
-fno-strict-prototype
只對g++起作用,使用這個選項,g++將對不帶參數的函數,都認為是沒有顯式
的對參數的個數和類型說明,而不是沒有參數.
而gcc無論是否使用這個參數,都將對沒有帶參數的函數,認為城沒有顯式說
明的類型
-fthis-is-varialble
就是向傳統c++看齊,可以使用this當一般變量使用.
-fcond-mismatch
允許條件表達式的第二和第三參數類型不匹配,表達式的值將為void類型
-funsigned-char
-fno-signed-char
-fsigned-char
-fno-unsigned-char
這四個參數是對char類型進行設置,決定將char類型設置成unsigned char(前
兩個參數)或者 signed char(后兩個參數)
-include file
包含某個代碼,簡單來說,就是便以某個文件,需要另一個文件的時候,就可以
用它設定,功能就相當于在代碼中使用#include<filename>
例子用法:
gcc hello.c -include /root/pianopan.h
-imacros file
將file文件的宏,擴展到gcc/g++的輸入文件,宏定義本身并不出現在輸入文件
中
-Dmacro
相當于C語言中的#define macro
-Dmacro=defn
相當于C語言中的#define macr
三個文件,一個頭文件,兩個程序文件
/*??d.h?
*/
#include?<iostream>
using?namespace?std;?
class?Dataset
{
??public:
?????int?getdata();
};?
?
/*??d.cpp?
*/
#include?"d.h"?
int?Dataset::getdata()
{
??return?1231;
}?
?
/*??out.cpp?
*/
#include?<iostream>
#include?"d.h"
using?namespace?std;
int?main()
{
??Dataset?Ds;
??cout<<Ds.getdata()<<endl;
??return?1;
}?
?
編譯:?[root@localhost?code]#?g++?-o?test.o?d.cpp?out.cpp
[root@localhost?code]#?./test.o
1231
[root@localhost?code]#?
編譯成動態庫?
[root@localhost?code]#?g++?-o?d.o?-c?d.cpp
[root@localhost?code]#?ar?-r?d.a?d.o
ar:?正在創建?d.a
[root@localhost?code]#?g++?-o?out?out.cpp?./d.a
[root@localhost?code]#?./out
1231
[root@localhost?code]# o=defn
-Umacro
相當于C語言中的#undef macro
-undef
取消對任何非標準宏的定義
-Idir
在你是用#include"file"的時候,gcc/g++會先在當前目錄查找你所制定的頭
文件,如果沒有找到,他回到缺省的頭文件目錄找,如果使用-I制定了目錄,他
回先在你所制定的目錄查找,然后再按常規的順序去找.
對于#include<file>,gcc/g++會到-I制定的目錄查找,查找不到,然后將到系
統的缺省的頭文件目錄查找
-I-
就是取消前一個參數的功能,所以一般在-Idir之后使用
-idirafter dir
在-I的目錄里面查找失敗,講到這個目錄里面查找.
-iprefix prefix
-iwithprefix dir
一般一起使用,當-I的目錄查找失敗,會到prefix+dir下查找
-nostdinc
使編譯器不再系統缺省的頭文件目錄里面找頭文件,一般和-I聯合使用,明確
限定頭文件的位置
-nostdin C++
規定不在g++指定的標準路經中搜索,但仍在其他路徑中搜索,.此選項在創建
libg++庫使用
-C
在預處理的時候,不刪除注釋信息,一般和-E使用,有時候分析程序,用這個很
方便的
-M
生成文件關聯的信息。包含目標文件所依賴的所有源代碼
你可以用gcc -M hello.c來測試一下,很簡單。
-MM
和上面的那個一樣,但是它將忽略由#include<file>造成的依賴關系。
-MD
和-M相同,但是輸出將導入到.d的文件里面
-MMD
和-MM相同,但是輸出將導入到.d的文件里面
-Wa,option
此選項傳遞option給匯編程序;如果option中間有逗號,就將option分成多個選
項,然后傳遞給會匯編程序
-Wl.option
此選項傳遞option給連接程序;如果option中間有逗號,就將option分成多個選
項,然后傳遞給會連接程序.
-llibrary
制定編譯的時候使用的庫
例子用法
gcc -lcurses hello.c
使用ncurses庫編譯程序
-Ldir
制定編譯的時候,搜索庫的路徑。比如你自己的庫,可以用它制定目錄,不然
編譯器將只在標準庫的目錄找。這個dir就是目錄的名稱。
-O0
-O1
-O2
-O3
編譯器的優化選項的4個級別,-O0表示沒有優化,-O1為缺省值,-O3優化級別最
高
-g
只是編譯器,在編譯的時候,產生調試信息。
-gstabs
此選項以stabs格式聲稱調試信息,但是不包括gdb調試信息.
-gstabs+
此選項以stabs格式聲稱調試信息,并且包含僅供gdb使用的額外調試信息.
-ggdb
此選項將盡可能的生成gdb的可以使用的調試信息.
-static
此選項將禁止使用動態庫,所以,編譯出來的東西,一般都很大,也不需要什么
動態連接庫,就可以運行.
-share
此選項將盡量使用動態庫,所以生成文件比較小,但是需要系統由動態庫.
-traditional
試圖讓編譯器支持傳統的C語言特性
g++ 編譯和鏈接
傳統意義上的編譯程序分兩步走 —— 編譯和鏈接:
1.編譯(compile):指用編譯器(compiler)將源代碼(source code)生成二進制目標文件(object file),在Windows下也就是 .obj 文件,UNIX下是 .o 文件。編譯時,編譯器需要的是語法的正確,函數與變量的聲明的正確,編譯器只檢測程序語法,和函數、變量是否被聲明,函數并不需要被定義。
??? UNIX下g++的語法為:
??????? g++ -c file.cpp
??? -c 是compile的意思,此命令將會生成 file.o 的目標文件。
2.鏈接(link):找到所要用到函數所在的目標文件,并把它們鏈接在一起合成為可執行文件(executable file)。鏈接時,要確保編譯器能找到所有被用到了的函數所在的目標文件。
??? g++ file1.o file2.o -o program.exe
??? -o 是指定生成的可執行文件名稱(output)。若不給出,默認的名稱為 a.out
上述兩部通常也可以合在一起完成:
??? g++ file1.cpp file2.cpp -o program.exe
這完全等同于上面兩步的結合,會先生成目標文件,然后鏈接成 file.exe
3. 庫 (library)
對于一個源文件很多的大項目,為了避免重復編譯,也為了方便編譯器鏈接,通常會把一些常用 到的目標文件打包(archive),于是就成為了傳說中的庫文件(library)。在Windows下這種包叫“庫文件”(Library File),也就是 .lib 文件,在UNIX下,是Archive File,也就是 .a 文件。
UNIX 所要用到的命令:
1)ar -- create, modify, and extract from archives.
@Usage: ar cr lib****.a file1.o file2.o
**** 為自定義的庫文件名。
標簽 c (create):如果庫不存在,則創建庫;
標簽 r (replace):如果庫中已存在要添加的對象文件,則舊的對象文件將被替換。
實際上 ar 只是一個打包工具,是archive(打包)的首字母。它將一系列的目標文件首位連接在一起,并內嵌一個索引表,使得編譯器能夠方便地找到所需要的函數。 一般來說,由于函數索引表的存在,對庫的鏈接要比對一般的對象文件的鏈接更快。如果 ar 未能完成此項索引表工作,還可以手動用以下的 ranlib 命令創建索引表。
2) ranlib -- generate index to archive.
@Usage: ranlib lib****.a
3) nm -- list symbols from object files.
nm可以用來顯示 ranlib 所構建的索引表。你將會看到所有庫里的函數名(除了模板函數template function)。
4. 在編譯時鏈接庫
創建了自己的庫,以后要用到相關函數的時候,只需在代碼中聲明所要用的函數(必須和庫中定義得相同)。在鏈接的時候,需要給出庫的名稱和位置:
g++ file1.o file2.o -o program.exe -L**** -l****
-L 后緊跟庫文件所在的目錄地址,-l 后緊跟庫名。
編譯器在鏈接的時候會在所指定的目錄地址下尋找名為 lib****.a 的庫文件。
g++ 編譯多個相關文件
三個文件,一個頭文件,兩個程序文件
/*??d.h?
*/
#include?<iostream>
using?namespace?std;?
class?Dataset
{
??public:
?????int?getdata();
};?
?
/*??d.cpp?
*/
#include?"d.h"?
int?Dataset::getdata()
{
??return?1231;
}?
?
/*??out.cpp?
*/
#include?<iostream>
#include?"d.h"
using?namespace?std;
int?main()
{
??Dataset?Ds;
??cout<<Ds.getdata()<<endl;
??return?1;
}?
?
編譯:?[root@localhost?code]#?g++?-o?test.o?d.cpp?out.cpp
[root@localhost?code]#?./test.o
1231
[root@localhost?code]#?
編譯成靜態庫?
[root@localhost?code]#?g++?-o?d.o?-c?d.cpp
[root@localhost?code]#?ar?-r?d.a?d.o
ar:?正在創建?d.a
[root@localhost?code]#?g++?-o?out?out.cpp?./d.a
[root@localhost?code]#?./out
1231
[root@localhost?code]#
?GCC 可同時用來編譯 C 程序和 C++ 程序。一般來說,C 編譯器通過源文件的后綴名來判斷是 C 程序還是 C++ 程序。
在 linux 中,C 源文件的后綴名為 .c,而 C++ 源文件的后綴名為 .C 或 .cpp。
但是,gcc 命令只能編譯 C++ 源文件,而不能自動和 C++ 程序使用的庫連接。
因此,通常使用 g++ 命令來完成 C++ 程序的編譯和連接,該程序會自動調用 gcc 實現編譯。
假設我們有一個如下的 C++ 源文件(main.cpp):
#include <iostream>
using namespace std;
?
?
int main()
{
??????? cout << "Hello, world!" << endl;
??????? return 0;
}
則可以如下調用 g++ 命令編譯、連接并生成可執行文件:
[root@zeckey hello_world]# g++ -o out main.cpp
[root@zeckey hello_world]# ./out
Hello, world!
[root@zeckey hello_world]#
注解:
1.??? -o out 是生成指定的輸出文件名為out,當然你也可以改用其他你喜歡的名字。用在生成可執行文件時。
2.? 如果你喜歡用 gedit 這個編輯編寫源程序,可能會出現如下錯誤:
[root@zeckey hello_world]# g++ main.cpp -o main.o
main.cpp: In function `int main()':
main.cpp:9: stray '\343' in program
main.cpp:9: stray '\200' in program
main.cpp:9: stray '\200' in program
[root@zeckey hello_world]#
這時你可以用 vi 編輯器查看源程序 main.cpp ,可能是如下所示:
#include <iostream>
using namespace std;
?
?
int main()
{
??????? cout << "Hello, world!" << endl;
??????? return 0;
}
這柯能是 gedit 編輯器自身帶進來的解碼錯誤,所以你最好還是用 vi 這個最經典的編輯器編寫程序代碼,
可以用 gedit 查看程序代碼,如果你確實不習慣的話。
gcc/g++ 編譯器使用簡介
GNU CC(簡稱gcc)是GNU項目中符合ANSI C標準的編譯系統,能夠編譯用C、C++、Object C、Jave等多種語言編寫的程序。gcc又可以作為交叉編譯工具,它能夠在當前CPU平臺上為多種不同體系結構的硬件平臺開發軟件,非常適合在嵌入式領域的開發編譯,如常用的arm-linux-gcc交叉編譯工具
?
通常后跟一些選項和文件名來使用 GCC 編譯器。gcc 命令的基本用法如下:
gcc [options] [filenames]
選項指定編譯器怎樣進行編譯。
?
一、gcc 編譯流程
1.預處理-Pre-Processing
gcc? -E? test.c? -o? test.i? ??//.i文件
?
2.編譯-Compiling
gcc? -S? test.i? -o?? test.s? //.s文件
?
3.匯編-Assembling?????? ??//.o文件
gcc? -c? test.s? -o? test.o
?
4.鏈接-Linking??????? ???//bin文件
gcc? test.o? -o? test
?
二、gcc工程慣用
1.編譯
gcc? -c? test.c????????? //.o文件,匯編
?
gcc? -o? test? test.c? //bin可執行文件
?
gcc?? test.c???????????? //a.out可執行文件
?
如果是c++ 直接將gcc改為g++即可。
?
2.常用參數
?
1)-E參數
?
-E 選項指示編譯器僅對輸入文件進行預處理。當這個選項被使用時, 預處理器的輸出被送到標準輸出而不是儲
存在文件里.
?
2)-S參數
?
-S 編譯選項告訴 GCC 在為 C 代碼產生了匯編語言文件后停止編譯。 GCC 產生的匯編語言文件的缺省擴展名
是 .s 。
?
3)-c參數
?
? -c 選項告訴 GCC 僅把源代碼編譯為目標代碼。缺省時 GCC 建立的目標代碼文件有一個 .o 的擴展名。
?
4)-o參數
?
??????? -o 編譯選項來為將產生的可執行文件用指定的文件名。
?
5)-O參數
?
-O 選項告訴 GCC 對源代碼進行基本優化。這些優化在大多數情況下都會使程序執行的更快。 -O2 選項告訴
GCC 產生盡可能小和盡可能快的代碼。 如-O2,-O3,-On(n 常為0--3);
-O? 主要進行跳轉和延遲退棧兩種優化;
-O2 除了完成-O1的優化之外,還進行一些額外的調整工作,如指令調整等。
-O3 則包括循環展開和其他一些與處理特性相關的優化工作。
選項將使編譯的速度比使用 -O 時慢, 但通常產生的代碼執行速度會更快。
如:
[root@localhost test]# gcc test.c -O3
[root@localhost test]# gcc -O3 test.c
[root@localhost test]# gcc -o tt test.c -O2
[root@localhost test]# gcc -O2 -o tt test.c
?
6)調試選項-g和-pg
?
GCC 支持數種調試和剖析選項,常用到的是 -g 和 -pg 。
-g 選項告訴 GCC 產生能被 GNU 調試器使用的調試信息以便調試你的程序。GCC 提供了一個很多其他 C 編譯
器里沒有的特性, 在 GCC 里你能使-g 和 -O (產生優化代碼)聯用。
-pg 選項告訴 GCC 在編譯好的程序里加入額外的代碼。運行程序時, 產生 gprof 用的剖析信息以顯示你的程序的
耗時情況。
?
7) -l參數和-L參數
????? -l參數就是用來指定程序要鏈接的庫,-l參數緊接著就是庫名,那么庫名跟真正的庫文件名有什么關系呢?
????? 就拿數學庫來說,他的庫名是m,他的庫文件名是libm.so,很容易看出,把庫文件名的頭lib和尾.so去掉就是庫名
了。
如:
?????? gcc? xxx.c?? -lm( 動態數學庫)?-lpthread
8) -include和-I參數
????? -include用來包含頭文件,但一般情況下包含頭文件都在源碼里用#i nclude xxxxxx實現,-include參數很少用。-I參
數是用來指定頭文件目錄,/usr/include目錄一般是不用指定的,gcc知道去那里找,但 是如果頭文件不
在/usr/icnclude里我們就要用-I參數指定了,比如頭文件放在/myinclude目錄里,那編譯命令行就要加上-I/myinclude
參數了,如果不加你會得到一個"xxxx.h: No such file or directory"的錯誤。-I參數可以用相對路徑,比如頭文件在當前
目錄,可以用-I.來指定。上面我們提到的--cflags參數就是用來生成-I參數的。
?
9)-Wall、-w 和 -v參數
???? -Wall 打印出gcc提供的警告信息
???? -w???? 關閉所有警告信息
???? -v????? 列出所有編譯步驟
?
四. 幾個相關的環境變量
????? PKG_CONFIG_PATH:用來指定pkg-config用到的pc文件的路徑,默認是/usr/lib/pkgconfig,pc文件是文本文件,擴展名是.pc,里面定義開發包的安裝路徑,Libs參數和Cflags參數等等。
????? CC:用來指定c編譯器。
????? CXX:用來指定cxx編譯器。
????? LIBS:跟上面的--libs作用差不多。
????? CFLAGS:跟上面的--cflags作用差不多。
????? CC,CXX,LIBS,CFLAGS手動編譯時一般用不上,在做configure時有時用到,一般情況下不用管。
????? 環境變量設定方法:export? ENV_NAME=xxxxxxxxxxxxxxxxx
?
五. 關于交叉編譯
????? 交叉編譯通俗地講就是在一種平臺上編譯出能運行在體系結構不同的另一種平臺上,比如在我們地PC平臺(X86 CPU)上編譯出能運行在arm CPU平臺上的程序,編譯得到的程序在X86 CPU平臺上是不能運行的,必須放到arm? CPU 平臺上才能運行。當然兩個平臺用的都是linux。這種方法在異平臺移植和嵌入式開發時用得非常普遍。相對與交叉編譯,我們平常做的編譯就叫本地編譯,也 就是在當前平臺編譯,編譯得到的程序也是在本地執行。用來編譯這種程序的編譯器就叫交叉編譯器,相對來說,用來做本地編譯的就叫本地編譯器,一般用的都是gcc,但這種gcc跟本地的gcc編譯器是不一樣的,需要在編譯gcc時用特定的configure參數才能得到支持交叉編譯的gcc。為了不 跟本地編譯器混淆,交叉編譯器的名字一般都有前綴,比如armc-xxxx-linux-gnu-gcc,arm-xxxx-linux-gnu- g++ 等等
?
交叉編譯器的使用方法
?
????? 使用方法跟本地的gcc差不多,但有一點特殊的是:必須用-L和-I參數指定編譯器用arm系統的庫和頭文件,不能用本地(X86)的庫(頭文件有時可以用本地的)。
例子:
arm-xxxx-linux-gnu-gcc test.c -L/path/to/sparcLib -I/path/to/armInclude
總結
以上是生活随笔為你收集整理的linux gcc g++编译命令选项的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: DevOps的几个场景
- 下一篇: linux elf文件格式