一直以來,我們對於GCC的使用就是gcc main.c而已,現在我們終於要來補充更多一點的使用細節了。 GCC,或任何一款編譯器的詳細完整使用方式一定有很多很多東西; 不過請放心,我這裡只會告訴大家一些常用的功能。 這麼做的原因在於,同我先前提過的一樣,編譯器是個工具,我假設讀者們未來可能會去使用各種不同的編譯器。 所以與其專精熟練於GCC的各種細節設定,我認為更重要的是告訴大家那些各種編譯器都大同小異的操作結構。
編譯器設定選項
首先,你可以在終端機執行gcc附帶--help參數,如同下面這樣:
gcc --help
他就會列印出一些說明。請不要被一堆的文字嚇到了,那些文字你有興趣可以再慢慢看,這裡我們要看的只有第一行:
Usage: gcc [options] file...
這一行很簡單的描述了GCC這個程式的用法,那個file就是輸入的檔案,也就是我們前面的main.c。 後面3個點表示輸入檔案可能不只一個,也就是我們可以輸入很多個程式碼檔案,這個以後再談。
中間用中括弧圈起來的options就是我們可以選用的設定參數,注意那個s表達了參數可以不只一個, 而中括弧代表不一定非要輸入參數不可,像我們之前所下的gcc main.c命令就沒有附帶半個設定參數。 這些設定選項可以讓我們更細緻的控制編譯成果,用處很大。 比方說我們先前只能編譯出一個叫作「a」的執行檔,但加上 -o 參數就可以更改編譯成品的檔案名稱, 例如我想要把之前練習的程式碼編譯成叫作myexe的執行檔的話,可以下這樣的指令:
gcc -o myexe main.c
由上可知 -o 這個選項可以設定編譯成品的名稱,該選項後面需要跟著一個參數,而這個參數就是編譯成果的檔案名。 但也並不是所有的選項都需要在後面跟著參數,像用來開啟最佳化功能的-O2就不需要任何參數, 拿我們原來的例子啟用最佳化功能來編譯的話,就需要下這樣的指令:
gcc -O2 -o myexe main.c
以上僅說明編譯選項的使用方式,實際上GCC可以使用的編譯選項有數百個,我們不會、也沒有必要學會全部的設定選項,除非你非常喜愛GCC。 因此,下面將以一個表格介紹一些常用的設定參數。
然而,在看表格前,有些東西要先說明一下:
- 注意這些選項是有區分大小寫的,-o和-O是完全不同的東西。
- 以大括弧「{}」表示的東西代表該選項所需的參數。
- 以中括弧「[]」表示的東西代表是選擇性的,不一定需要。
- 以初學者現在的程度,很多選項現在應該是看不懂他實際的用途,你可以直接忽略他們沒關係。 我他們列在這裡是為了希望在你以後回來參考這個表格時,它能夠提你供相當的資料完整性。
一般通用設定 | ||
---|---|---|
選項 | 說明 | |
--help[={CLASS}] | 印出使用說明。 如果想要知道某些項目的更詳細說明的話,可以把項目分類名稱加在後面, 比方說如果我想知道有關warnings的更多說明則可以輸入--help=warnings; 不過我想你應該更願意看網頁版的說明。 |
|
--version | 印出GCC的版本相關資訊。 | |
-o {FILENAME} | 設定編譯成品的檔案名稱,其中{FILENAME}即為檔案名稱。 若不指定的話,則會使用預設的名稱「a」 (實際上可能是a.out或a.exe等,依作業系統而不同)。 |
|
編譯流程控制 | ||
選項 | 說明 | |
-E | 告訴編譯器把程式碼處理到預處理程序完成即終止。 這個選項預設不會產生檔案,而是在終端機上顯示成果。 |
|
-S | 告訴編譯器把程式碼編譯成組合語言即終止。 這個選項預設會產生一個副檔名為「s」的組合語言程式碼檔。 |
|
-c | 告訴編譯器把程式碼編譯成目的檔即終止。 這個選項預設會產生一個副檔名為「o」的目的檔。 |
|
語言標準設定 | ||
選項 | 說明 | |
-std={STANDARD} | 告訴編譯器要使用什麼版本的程式語言標準來編譯程式碼, 其中{STANDARD}及為語言標準名稱,常用有gnu89、gnu99、gnu11等。 GCC 5以上的版本預設為gnu11,若你的GCC版本不夠新的話, 可以加上-std=gnu11這個設定選項,來享受C11的最新功能。 | |
編譯警告設定 | ||
選項 | 說明 | |
-Wall | 開啟所有的編譯器警告訊息,可以幫程式人員檢查出一些可能潛在的問題。 為了養成良好的寫作習慣,你應該永遠加上這個設定選項。 | |
除錯設定 | ||
選項 | 說明 | |
-g | 在編譯的成品裡插入用來追蹤除錯的標記, 如果想要用Debugger追蹤程式碼的話,就會需要加上這個設定選項。 |
|
最佳化設定 | ||
選項 | 說明 | |
-O0 | 關閉所有的最佳化功能。 | |
-O1 | 開啟初步的最佳化功能。 這個選項會啟用所有不會花費太多編譯時間的最佳化選項, 以兼顧程式的執行速度、空間佔用、以及程式碼編譯時間。 |
|
-O2 | 開啟更多的最佳化功能。 這個選項除了啟用-O1的所有功能外,還會加入所有不會造成Space-Speed兩難的最佳化選項, 而同時也會使編譯過程需要消耗更多的時間。 |
|
-O3 | 開啟最多的最佳化功能。 這個選項除了啟用-O2的所有功能外,還為以執行速度為前提加入能夠加入的全部最佳化選項。 |
|
-Os | 開啟所有以最小空間佔用為前提的最佳化功能。 這個選項會啟用絕大部分-O2選項裡不會造成空間佔用變多的功能外, 還會以減少程式佔用記憶體空間為前提加入能夠加入的全部最佳化選項。 |
|
連結器設定 | ||
選項 | 說明 | |
-l{LIBRARY} | 加入連結某個程式庫,其中{LIBRARY}為該程式庫的名稱。 注意GCC所使用的程式庫檔名必須以lib開頭,而該程式庫的名稱即為該檔名去除lib開頭以及副檔名後的東西。 比方說我要聯結librt.a這個程式庫的話,則該程式庫的名稱應為rt,所以我就應該加入-lrt這樣的設定選項。 |
|
-s | 移除編譯成品中的連結符號表等資訊,通常在建置最終成品時會加入這個選項。 | |
-shared | 編譯程式為動態程式庫,而不是執行檔。 | |
檔案搜索路徑設定 | ||
選項 | 說明 | |
-I{PATH} | 讓編譯器在搜尋標頭檔時也一併到{PATH}這個路徑下搜尋。 請注意設定的檔案路徑和-I中間是接連著的,沒有任何分隔。 |
|
-L{PATH} | 讓編譯器在搜尋程式庫檔案時也一併到{PATH}這個路徑下搜尋。 請注意設定的檔案路徑和-L中間是接連著的,沒有任何分隔。 |
|
前置處理器設定 | ||
選項 | 說明 | |
-D{MACRO}[={VALUE}] | 設定一個全域的預編譯巨集,甚至可以以一個等號來指定該巨集的值。 請注意巨集名稱和-D中間是接連著的,沒有任何分隔。 |
|
Code Generation (我不知道這個該怎麼翻譯好) | ||
選項 | 說明 | |
-fPIC | 編譯出Position-Independent Code,通常是搭配-shared選項一起使用。 |
上面雖然只列出了常用的選項,但我想對初學者也夠多了,尤其又有很多選項還不知實際上是怎麼用的。 所以我把他再整理歸納一下,以我們目前的學習進度以及需求來看,各位只要下這樣的指令來編譯程式碼就可以了:
gcc -Wall -std=gnu11 -o test main.c
注意上面那個test是輸出的執行檔名稱,你可以改為任何你喜歡的; 甚至連程式碼檔案main.c也可以更名為你想要的名稱(不過副檔名還是要c就是了)。 然後如果你的GCC版本夠新(5以上),還可以省略-std=gnu11的選項。
編譯腳本
不知道各位看到這裡有沒有一個疑問,就是我們的編譯指令這麼長,尤其以後可能還會加入更多的編譯選項, 這樣每次要編譯程式的時候都要打這些字不是很累嗎? 這時候就要提到另一個有用的東西叫作指令腳本,在Linux上就是一個副檔名為「sh」的純文字檔、而Windows上就是副檔名為「bat」的純文字檔。 我們只要把我們要下的指令(可以不只一條)像這樣寫在腳本檔裡:
gcc -Wall -std=gnu11 -o test main.c test
我把這個腳本存檔到我們練習寫程式放程式碼的目錄下,並取名叫作「buildrun.sh」,還要記得設定這個檔案屬性為可被執行的(Linux), 接下來我只要在該目錄下面下這樣的指令就可以完成編譯及執行的動作了:
./buildrun.sh
很方便吧! 當然腳本檔的功能絕不只如此,可是以我們的C語言學習需求來說這樣是夠用了, 有興趣的人可以再深入學習有關腳本語言的相關知識技巧。 另外有些人可能會認為我們應該要用Makefile來建置程式而不是用腳本笨笨的做這件事,而我沒要教你們要這樣做有兩個原因: 第一是Makefile本身複雜度也不小,我們C語言都還沒學會就先不要分神太多了; 第二是以我們整個C語言的學習練習需求來看,我們的專案都不會大到哪去,就算每次都從頭到尾重新建置也不會花幾秒鐘。 所以我認為當前我們只要這樣使用腳本檔來代替我們要打的指令群就已足夠, 如果各位還有興趣深入研究Shell Script甚至是Makefile的話就請自行蒐集相關的其他教學資源了!
重點回顧
- 使用GCC編譯程式時請一定要加上-Wall選項來開啟所有的編譯警告訊息。
- 為了享受C11的新功能,GCC 5以下的版本可加上-std=gnu11選項來開啟C11支援模式。
- 我們目前推薦的編譯指令是:gcc -Wall -o test main.c。
- 我們可以把要下的指令群存成腳本檔,就可以很方便的一次執行,而不用累死人的一直打一大堆指令。
練習與討論
請為你先前練習的程式增加設定選項-Wall,並使用-o來更改程式編譯後的檔案名稱, 最後請把你的編譯執行等相關指令存成一個腳本檔,然後使用這個腳本檔重新編譯你的程式。
留言列表