gcc的使用簡介與命令行參數說明

(一) gcc的基本用法
(二) 警告提示功能選項
(三) 庫操做選項
(四) 調試選項
(五) 交叉編譯選項
linux



(一) gcc的基本用法
使用gcc編譯器時,必須給出一系列必要的調用參數和文件名稱。不一樣參數的前後順序對執行結果沒有影響,只有在使用同類參數時的前後順序才須要考慮。若是使用了多個 -L 的參數來定義庫目錄,gcc會根據多個 -L 參數的前後順序來執行相應的庫目錄。
由於不少gcc參數都由多個字母組成,因此gcc參數不支持單字母的組合,Linux中常被叫短參數(short options),如 -dr 與 -d -r 的含義不同。gcc編譯器的調用參數大約有100多個,其中多數參數咱們可能根本就用不到,這裏只介紹其中最基本、最經常使用的參數。

gcc最基本的用法是:gcc [options] [filenames]
其中,options就是編譯器所須要的參數,filenames給出相關的文件名稱,最經常使用的有如下參數:

-c    
只編譯,不連接成爲可執行文件。編譯器只是由輸入的 .c 等源代碼文件生成 .o 爲後綴的目標文件,一般用於編譯不包含主程序的子程序文件。
-o output_filename    
肯定輸出文件的名稱爲output_filename。同時這個名稱不能和源文件同名。若是不給出這個選項,gcc就給出默認的可執行文件 a.out 。
-g
產生符號調試工具(GNU的 gdb)所必要的符號信息。想要對源代碼進行調試,就必須加入這個選項。
-O
對程序進行優化編譯、連接。採用這個選項,整個源代碼會在編譯、連接過程當中進行優化處理,這樣產生的可執行文件的執行效率能夠提升,可是編譯、連接的速度就相應地要慢一些,並且對執行文件的調試會產生必定的影響,形成一些執行效果與對應源文件代碼不一致等一些使人「困惑」的狀況。所以,通常在編譯輸出軟件發行版時使用此選項
-O2
比 -O 更好的優化編譯、連接。固然整個編譯連接過程會更慢。
-Idirname
將 dirname 所指出的目錄加入到程序頭文件目錄列表中,是在預編譯過程當中使用的參數。
說明:
C程序中的頭文件包含兩種狀況:
#include <stdio.h>
#include "stdio.h"
其中,使用尖括號(<>),預處理程序 cpp 在系統默認包含文件目錄(如/usr/include)中搜索相應的文件;使用雙引號,預處理程序 cpp 首先在當前目錄中搜尋頭文件,若是沒有找到,就到指定的 dirname 目錄中去尋找。
在程序設計中,若是須要的這種包含文件分別分佈在不一樣的目錄中,就須要逐個使用 -I 選項給出搜索路徑
-Ldirname
將dirname所指出的目錄加入到程序函數庫文件的目錄列表中,是在連接過程當中使用的參數。在默認狀態下,連接程序 ld 在系統默認路徑中(如 /usr/lib)尋找所須要的庫文件。這個選項告訴連接程序,首先到 -L 指定的目錄中去尋找,而後到系統默認路徑中尋找;若是函數庫存放在多個目錄下,就須要依次使用這個選項,給出相應的存放目錄。
-lname
連接時裝載名爲 libname.a 的函數庫。該函數庫位於系統默認的目錄或者由 -L 選項肯定的目錄下。例如,-lm 表示連接名爲 libm.a 的數學函數庫。

例子:假定有一個程序名爲 test.c 的C語言源代碼文件,要生成一個可執行文件。
#include <stdio.h>
int main(void)
{
    printf("Hello world/n");
    return 0;
}
最簡單的辦法:gcc test.c -o test
首先,gcc須要調用預處理程序 cpp,由它負責展開在源文件中定義的宏,並向其中插入「#include」語句所包含的內容;接着,gcc調用 ccl 和 as,將處理後的源代碼編譯成目標代碼;最後,gcc調用連接程序 ld,把生成的目標代碼連接成一個可執行程序。所以,默認狀況下,預編譯、編譯連接一次完成。

編譯過程的分步執行:
爲了更好地理解gcc的工做過程,咱們可讓在gcc工做的4個階段中的任何一個階段中中止下來。相關的參數有:
-E
預編譯後停下來,生成後綴爲 .i 的預編譯文件
-c
編譯後停下來,生成後綴爲 .o 的目標文件
-S
彙編後停下來,生成後綴爲 .s 的彙編源文件

第一步:進行預編譯,使用 -E 參數
gcc -E test.c -o test.i
查看 test.i 文件中的內容,會發現 stdio.h 的內容確實都插到文件裏去了,而其餘應當被預處理的宏定義也都作了相應的處理。
第二步:將 test.i 編譯爲目標代碼,使用 -c 參數
gcc -c test.c -o test.o
第三步:生成彙編源文件
gcc -S test.c -o test.s
第四步:將生成的目標文件連接成可執行文件
gcc test.o - o test

對於稍微複雜的狀況,好比有多個源代碼文件、須要連接庫或有其餘比較特別的要求,就要給定適當的調用選項參數。

例子:整個源代碼程序由兩個文件 testmain.c 和 testsub.c 組成,程序中使用了系統提供的數學庫(全部與浮點相關的數學運算都必須使用數學庫)。
gcc testmain.c testsub.c -lm -o test
其中,-lm 表示連接系統的數學庫 libm.a 

說明:
在編譯一個包含許多源文件的工程時,若只用一條gcc命令來完成編譯是很是浪費時間的。假如項目中有100個源文件須要編譯,而且每一個源文件中都包含一萬行代碼,若是像上面那樣僅用一條gcc命令來完成編譯工做,那麼gcc須要將每一個源文件都從新編譯一遍,而後再所有連接起來。很顯然,這樣浪費的時間至關多,尤爲是當用戶只是修改了其中某個文件的時候,徹底沒有必要將每一個文件都從新編譯一遍,由於不少已經生成的目標文件是不會發生改變的。要解決這個問題,須要藉助像make這樣的工具。

(二) 警告提示功能選項
gcc包含完整的出錯檢查和警告提示功能,它們能夠幫助Linux程序員寫出更加專業的代碼。
(1) -pedantic 選項
當gcc在編譯不符合ANSI/ISO C 語言標準的源代碼時,將產生相應的警告信息。程序員

 

 

[cpp]  view plain  copy
 
 print?
  1. #include <stdio.h>  
  2.   
  3.  void main(void)  
  4.  {  
  5.      long long int var = 1;  
  6.      printf("It is not standard C code!/n");  
  7.  }  

 

pic

 

它有如下問題:
> main 函數的返回值被聲明爲 void,但實際上應該是 int。
> 使用了 GNU 語法擴展,即便用 long long 來聲明64位整數,不符合 ANSI/ISO C 語言標準。
> main 函數在終止前沒有調用 return 語句。

(2) -Wall 選項
除了 -pedantic 以外,gcc 還有一些其餘編譯選項,也可以產生有用的警告信息。這些選項大多以 -W 開頭。其中最有價值的當數 -Wall 了,使用它可以使 gcc 產生儘量多的警告信息。編程

pic

 

gcc 給出的警告信息雖然從嚴格意義上說不能算做錯誤,但卻和可能成爲錯誤來源。一個優秀的程序員應該儘可能避免產生警告信息,使本身的代碼始終保持簡潔、優美和健壯的特性。
建議:gcc 給出的警告信息是頗有價值的,它們不只能夠幫助程序員寫出更加健壯的程序,並且仍是跟蹤和調試程序的有力工具。建議在用 gcc 編譯源代碼時始終帶上 -Wall 選項,並把它逐漸培養成一種習慣,這對找出常見的隱式編程錯誤頗有幫助。

(3) -Werror 選項
在處理警告方面,另外一個經常使用的編譯選項是 -Werror。它要求 gcc 將全部的警告當成錯誤進行處理,這在使用自動編譯工具(如 Make 等)時很是有用。若是編譯時帶上 -Werror 選項,那麼 gcc 會在全部產生警告的地方中止編譯,迫使程序員對本身的代碼進行修改。只有當相應的警告信息消除時,纔可能將編譯過程繼續朝前推動。函數

pic

 

(4) -Wcast-align 選項
當源程序中地址不須要對齊的指針指向一個地址須要對齊的變量地址時,則產生一個警告。例如,char * 指向一個 int * 地址,而一般在機器中 int 變量類型是須要地址能被2或4整除的對齊地址。

(5) 其餘經常使用選項
-v                            輸出 gcc 工做的詳細過程
--target-help       顯示目前所用的gcc支持CPU類型
-Q                           顯示編譯過程的統計數據和每個函數名

(三) 庫操做選項
Linux下開發軟件時,徹底不使用第三方函數庫的狀況是比較少見的,一般來說都須要藉助一個或多個函數庫的支持纔可以完成相應的功能。
從程序員的角度看,函數庫實際上就是一些頭文件(.h)和庫文件(.so 或 .a)的集合。雖然Linux下的大多數函數都默認將頭文件放到 /usr/include/ 目錄下,而庫文件則放到 /usr/lib/ 目錄下,但並非全部的狀況都是這樣。正因如此,gcc 在編譯時必須有本身的辦法來查找所須要的頭文件和庫文件。經常使用的方法有:
(1) -I 
能夠向 gcc 的頭文件搜索路徑中添加新的目錄。
(2) -L 
若是使用了不在標準位置的庫文件,那麼能夠經過 -L 選項向 gcc 的庫文件搜索路徑中添加新的目錄。
(3) -l 
Linux下的庫文件在命名時有一個約定,就是應該以 lib 這3個字母開頭,因爲全部的庫文件都遵循了一樣的規範,所以在用 -l 選項指定連接的庫文件名時能夠省去 lib 這3個字母。例如,gcc 在對 -lfoo 進行處理時,會自動去連接名爲 libfoo.so 的文件。
(4) -static
Linux下的庫文件分爲兩大類,分別是:動態連接庫(一般以 .so 結尾)和靜態連接庫(一般以 .a 結尾)。
二者的差異僅在程序執行時所需的代碼是在運行時動態加載的,仍是在編譯時靜態加載的。
默認狀況下,gcc 在連接時優先使用動態連接庫,只有當動態連接庫不存在時才考慮使用靜態連接庫。
若是須要的話,能夠在編譯時加上 -static 選項,強制使用靜態連接庫。
(5) -shared
生成一個共享的目標文件,它可以與其餘的目標一塊兒連接生成一個可執行的文件。
 
(四) 調試選項
對於Linux程序員來說,gdb(GNU Debugger)經過與 gcc 的配合使用,爲基於Linux的軟件開發提供了一個完善的調試環境。經常使用的有:
(1) -g 和 -ggdb
默認狀況下,gcc 在編譯時不會將調試符號插入到生成的二進制代碼中,由於這樣會增長可執行文件的大小。若是須要在編譯時生成調試符號信息,可使用 gcc 的 -g 或 -ggdb 選項。
gcc 在產生調試符號時,一樣採用了分級的思路,開發人員能夠經過在 -g 選項後附加數字一、二、3指定在代碼中加入調試信息的多少。默認的級別是2(-g2),此時產生的調試信息包括:擴展的符號表、行號、局部或外部變量信息。
級別3(-g3)包含級別2中的全部調試信息以及源代碼中定義的宏。
級別1(-g1)不包含局部變量和與行號有關的調試信息,所以只可以用於回溯跟蹤和堆棧轉儲。
回溯追蹤:指的是監視程序在運行過程當中函數調用歷史。
堆棧轉儲:則是一種以原始的十六進制格式保存程序執行環境的方法。

注意:使用任何一個調試選項都會使最終生成的二進制文件的大小急劇增長,同時增長程序在執行時的開銷,所以,調試選項一般僅在軟件的開發和調試階段使用。

(2) -p 和 -pg
會將剖析(Profiling)信息加入到最終生成的二進制代碼中。剖析信息對於找出程序的性能瓶頸頗有幫助,是協助Linux程序員開發出高性能程序的有力工具。

(3) -save-temps
保存編譯過程當中生成的一些列中間文件。
# gcc test.c -o test -save-temps
除了生成執行文件test以外,還保存了test.i 和 test.s 中間文件,供用戶查詢調試。

(五) 交叉編譯選項
一般狀況下使用 gcc 編譯的目標代碼都與使用的機器是一致的,但 gcc 也支持交叉編譯的功能,可以編譯其餘不一樣CPU的目標代碼
使用 gcc 開發嵌入式系統,咱們幾乎都是以通用的PC機(X86)平臺來作宿主機,經過 gcc 的交叉編譯功能對其餘嵌入式CPU的開發任務。
(具體的選項設置,此處省略)工具

相關文章
相關標籤/搜索