gcc參數介紹

假設已經知道編譯流程
[介紹]
gcc and g++分別是gnu的c & c++編譯器 gcc/g++在執行編譯工作的時候,總共需要4步
1.預處理,生成.i的文件[預處理器cpp]
2.將預處理後的文件不轉換成彙編語言,生成文件.s[編譯器egcs]
3.有彙編變為目標代碼(機器代碼)生成.o的文件[彙編器as]
4.連接目標代碼,生成可執行程序[鏈接器ld]

常用參數

參數 功能
-c 編譯但不連結,產生.o檔
-S 輸出組譯碼
-E 顯示預處理(define, macro)的結果
-o filename 指定輸出檔名
-ansi 只支持 ANSI 標準的 C 語法。這一選項將禁止 GNU C 的某些特色 例如 asm 或 typeof 關鍵詞。
-Dmacro 定義指定巨集為有效
-Dmarco=defn 定義指定巨集為defn
-Wa,option 將選項(option)傳給組譯器
-wl,option 將選項(option)傳給連結器
-I 增加include header檔案的搜尋路徑
-L 增加library檔案的搜尋路徑
-l 指定連結的函式庫
-Wall 顯示所有的警告訊息
-g 編入除錯資訊(使用GDB除錯時用)

-IDIRECTORY 指定額外的頭文件搜索路徑DIRECTORY。
-LDIRECTORY 指定額外的函數庫搜索路徑DIRECTORY。
-lLIBRARY 連接時搜索指定的函數庫LIBRARY。
-m486 針對 486 進行代碼優化。
-shared 生成共享目標文件。通常用在建立共享庫時。
-static 禁止使用共享連接。
-UMACRO 取消對 MACRO 宏的定義。
-w 不生成任何警告信息。
-Wall 生成所有警告信息。

最佳化

-Os, -O0, -O1, -O2, -O3,

-O0表示沒有優化,-O1為缺省值,-O3優化級別最高

使用範例

與函式庫連結 :
另一個常用的選項是 -l, 它以一種特殊方式來指定函式庫. 首先它必須放在命令的最後面, 也就是原始檔檔名之後, 而所有其他的選項是指定在檔名之前. 底下是一個典型的命令 ; 因為輸入檔是目的檔, 所以命令僅僅啟動連結器 :
%gcc -o plot main.o plot_line.o -lm

-lm 選項指定使用數學函式庫. 當你指定 -lname, 系統會到存放標準函式庫的目錄中 (通常位於 /usr/lib) 中去尋找 libname.a 檔案. 所以你所尋找的數學函式庫應該是 /usr/lib/libm.a . 和表頭檔一樣, 函式庫有時也放在非標準路徑的目錄下. 你這時必須以 -L 選項來告訴 gcc 到哪裡去找這函式庫, 例如 :
%gcc -o -L/src/local/lib main.o plot_line.o -lm

它告訴gcc 首先到 /src/local/lib 去找函式庫, 然後才是標準路徑下的函式庫. 假如某人把自己版本的函式庫放到 /src/local/lib 下, 在使用順序上, 他的這個版本將超過 /usr/lib 下的同名函式庫

///==================另外還有個Os選項==========================
http://hi.baidu.com/ah__fu/blog/item/cc9fd19b801948bdc9eaf4b3.html
在研究編譯驅動的makefile的時候,發現GCC的命令行裡面有一個-Os的優化選項。
遍查GCC文檔,發現了-O0, -O1, -O2, -O3,就是沒有發現-Os。
祭出GOOGLE大法搜了一下,終於發現這篇文章說明了-Os的作用:
http://www.linuxjournal.com/article/7269

原來-Os相當於-O2.5。是使用了所有-O2的優化選項,但又不縮減代碼尺寸的方法。
詳細的說明如下:
Level 2.5 (-Os)
The special optimization level (-Os or size) enables all -O2 optimizations that do not increase code size; it puts the emphasis on size over speed. This includes all second-level optimizations, except for the alignment optimizations. The alignment optimizations skip space to align functions, loops, jumps and labels to an address that is a multiple of a power of two, in an architecture-dependent manner. Skipping to these boundaries can increase performance as well as the size of the resulting code and data spaces; therefore, these particular optimizations are disabled. The size optimization level is enabled as:
gcc -Os -o test test.c
In gcc 3.2.2, reorder-blocks is enabled at -Os, but in gcc 3.3.2 reorder-blocks is disabled.

==============================
補充:在GCC的官方文檔裡又發現了關於-Os的說明:
http://gcc.gnu.org/onlinedocs/gcc-3.4.6/gcc/Optimize-Options.html#Optimize-Options

//=============================================
http://blog.csdn.net/ison81/archive/2009/05/07/4158576.aspx

backtrace與fomit-frame-pointer選項

事實上gcc的所有級別的優化(-O, -O2, -O3等)都會打開-fomit-frame-pointer,該選項的功能是函數調用時不保存frame指針,在ARM上就是fp,故我們無法按照APCS中的約定來回溯調用棧。但是GDB中仍然可以使用bt命令看到調用棧,為什麼?得知GDB v6之後都是支持DWARF2的,也就意味著它可以不依賴fp來回溯調用棧(詳見http://gcc.gnu.org/ml/gcc/2003-10/msg00322.html)。
看來想在代碼中動態顯示調用棧而又不希望使用GDB的朋友,只能在編譯時關掉-fomit-frame-pointer了。

//==================gcc參數大全:===========================

[參數詳解]
-x language filename
 設定文件所使用的語言,使後綴名無效,對以後的多個有效.也就是根據約定C語言的後綴名稱是.c的,而C++的後綴名是.C或者.cpp,如果你很個性,決定你的C代碼文件的後綴名是.pig 哈哈,那你就要用這個參數,這個參數對他後面的文件名都起作用,除非到了下一個參數的使用。
  可以使用的參數嗎有下面的這些
  c',objective-c’, c-header',c++’, cpp-output',assembler’, and `assembler-with-cpp’.
  看到英文,應該可以理解的。
  例子用法:
  gcc -x c hello.pig
  
-x none filename
  關掉上一個選項,也就是讓gcc根據文件名後綴,自動識別文件類型
  例子用法:
  gcc -x c hello.pig -x none hello2.c
  
-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用習慣了)
  gcc -o hello.asm -S hello.c
-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
  例子用法:
  gcc hello.c -include /root/pianopan.h
  
-imacros file
  將file文件的宏,擴展到gcc/g++的輸入文件,宏定義本身並不出現在輸入文件中
  
-Dmacro
  相當於C語言中的#define macro
  
-Dmacro=defn
  相當於C語言中的#define macro=defn
  
-Umacro
  相當於C語言中的#undef macro
-undef
  取消對任何非標準宏的定義
  
-Idir
  在你是用#include”file”的時候,gcc/g++會先在當前目錄查找你所制定的頭文件,如果沒有找到,他回到缺省的頭文件目錄找,如果使用-I制定了目錄,他
  回先在你所制定的目錄查找,然後再按常規的順序去找.
  對於#include,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造成的依賴關係。
  
-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語言特性

[參考資料]
-Linux/UNIX高級編程
  中科紅旗軟件技術有限公司編著.清華大學出版社出版
-Gcc man page   

其他編譯器

Clang

編譯速度更快、編譯產出更小、出錯提示更友好。尤其是在比較極端的情況下。
最後一點,其他同學也有講到,就是Clang採用的是BSD協議。這是蘋果資助LLVM、FreeBSD淘汰GCC換用Clang的一個重要原因。

從代碼上說,clang結構更簡單。因為clang只需要完成詞法和語法分析,代碼優化和機器代碼的生成工作由llvm完成。所以和全部由自己包下的gcc比起來,clang可以更專注地做好一件事。
這種結構也使clang可以被單獨拿出來用在其他的程序裡。比如vim的clang_complete插件就是利用clang進行語法分析後給出精確的自動補全和語法錯誤

llvm是一個底層虛擬機平台,提供了經過最佳化的IF代碼,也就是有個中間層,在這個中間層可以做很多的事情,比如優化和提供給編譯器更多的信息,理論上可以支持幾乎任何編程語言。llvm默認的前端是clang,當然也可以用gcc做前端。
llvm用c++寫的,模塊化做的很好,因此可以很好的和clang,gcc等等更多的東西合作,能為ide提供更全的有用信息。而gcc則包含的比較全面,整一個是一個宏結構,沒有模塊化設計,用c寫的,對ide也不太友好(實際上linux社區裡似乎對ide一直不感冒)。不過c++版的gcc正在重寫中,為了與llvm/clang更好的競爭,而且gcc從5.0開始打算進行模塊化設計,所以,以後gcc內部可能會分出很多部分。
就現在來看,gcc大體等同於llvm+clang所提供的功能。
很多人特別羨慕clang那強大的錯誤診斷信息,其實gcc4.8部分信息診斷能力已經超過它了,比它更準確,所以競爭真的很好,我們可以用到好的東西了。gcc目前的問題就是缺乏模塊化設計,這是暫時落後於llvm的地方。
freebsd不用gcc是因為gpl協議,llvm/clang的協議更加自由,但llvm/clang目前的兼容性和參數優化等等方面和gcc還有不小差距,雖然編譯後的體積更小了(架構領先優勢),但在性能優化方面相比gcc還有很多事情要做。

======
Several of the -f code generation options are interesting:

The -ftrapv function will cause the program to abort on signed integer overflow (formally “undefined behaviour” in C).
-fverbose-asm is useful if you’re compiling with -S to examine the assembly output - it adds some informative comments.
-finstrument-functions adds code to call user-supplied profiling functions at every function entry and exit point.
http://stackoverflow.com/questions/3375697/useful-gcc-flags-for-c

===============================

pkg-config 的功能與用法

http://calamaryshop.blogspot.com/2011/11/pkg-config.html

當開發C程式時經常使會用到許多系統已安裝的library所提供的function,來加速對程式的開發。在程式中會將含有這些library提供的function宣告的header file加到程式中,但最頭痛的是在compile程式時加上額外的設定來告訴編譯器該去系統中的何處找尋所要使用的header file以及所使用的library file被安裝在何處。所以Linux系統上有個非常好用的工具pkg-config可以查詢library的header file以及library的所在位置及資訊,以及在編譯程式時該使用的編譯參數為何。

這個程式主要讀取系統中位於 /usr/lib/pkgconfig 目錄或是環境變數 PKG_CONFIG_PATH 所設定的路徑中的副檔名為 .pc 的檔案,這些檔案包含系統安裝的library的相關資訊,包括:安裝的目錄、程式編譯的參數等等。
使用方法:
pkg-config –cflags library-name-with-version 就可以得到編譯程式時 pre-processing 動作必須加上的參數設定。
執行 pkg-config –cflags glib-2.0,其結果為-I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include。
pkg-config –libs library-name-with-version就可以得到 linking時所必須傳給編譯器的參數。
執行 pkg-config –libs glib-2.0 得到-lglib-2.0。
另外,我們還可以利用 pkg-config 來簡化 Makefile 的撰寫。
在Makefile中,原來寫在編譯器之後的參數,改成 pkg-config –cflags –libs library-name-with-version 即可。
例如:將Makefile中的這一行
gcc -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -lglib-2.0 program.c
替換成
gcc pkg-config –cflags –libs glib-2.0 program.c

pkg-config 簡單用法

  1. pkg-config –list-all
    列出所有可使用的連結庫,位置在 /usr/lib/pkgconfig 及 /usr/local/lib/pkgconfig 裏面的 xxx.pc 檔,新軟體一般都會安裝 .pc 檔,沒有可以自己建立,並且設定環境變數 PKG_CONFIG_PATH 供 pkg-config 尋找 .pc 檔路徑。
  2. pkg-config –cflags xxxx
    取得該連結庫的 CFLAGS 參數。(Cflags)
  3. pkg-config –libs xxxx
    取得該連結庫的 LDFLAGS 參數。(Libs)
  4. pkg-config –static xxxx
    取得該連結庫供靜態連結的 LDFLAGS 參數。(Libs.private)
  5. pkg-config –version
    取得 pkg-config 版本號。
  6. pkg-config –modversion xxxxx
    取得連結庫的版本號。(Version)

Reference

  • Gcc参数.txt
  • gcc官方文件
  • 安裝 LLVM + Clang