GCC 簡介#
GCC(GNU Compiler Collection)原本稱為 GNU C Compiler,隨著時代演進陸續支援 Fortran、Pascal、Objective-C、Java、Ada、Go 等程式語言後,才改稱 GNU Compiler Collection。
本篇文章只會探討 C 語言的部分,不會對其他程式語言多做介紹。
關於 GNU 計畫,可參考相關介紹文章。
C 語言的編譯流程#
要將 C 語言編譯成可執行檔,需要經過多個流程:
預處理
將
include、macro 擴展成真正的內容,經過這一步驟後,檔案會變大許多。使用 GCC 進行預處理的方式如下:gcc -E -I./src main.c -o main.i-E會讓 gcc 僅對 C 程式做預處理。-I用來指定自定義標頭檔的優先搜尋目錄,若你定義的標頭檔與程式碼同目錄,就可以忽略該參數。-o指定輸出檔案的檔名與格式。
編譯
將預處理過的程式碼編譯成組合語言,而組合語言又會因為不同的處理器架構出現差異,如果要在 x86 平台編譯出 ARM 平台能執行的程式碼,就會需要做交叉編譯。使用 GCC 進行編譯的方法:
gcc -S -I./src main.c -o main.s-S僅輸出 C 程式對應的組合語言。
組譯
經過編譯後,我們會得到組合語言檔案,也就是
*.s檔案。不過,若要讓電腦能夠執行我們的程式碼,我們仍需要將其轉換成機器碼。gcc -c main.s -o main.o-c僅編譯 C 程式,但不連結,即輸出對應的目標碼。
連結
連結會將多個目標檔或是 library 連結成可執行檔。
gcc -o main main.o得到可執行檔後,可以在 shell command 輸入以下命令執行程式:
./main如果有多個機器碼最後會被連結成一個可執行檔案,也可以這麼做:
gcc -o main a.o b.o c.o這樣一來,如果開發者更動了其中一個檔案,我們只需對有更動的檔案進行編譯再連結起來,可以大幅節省編譯的時間。
其他常見參數#
除了最基本的編譯,當然還要學習其他 GCC 內建的強大功能!
程式最佳化#
GCC 可以針對不同的處理器架構對程式進行最佳化:
O0O1O2(常用)OsO3(最佳化)
gcc -O2 -o main main.c顯示錯誤資訊#
考慮以下程式碼:
#include <stdio.h>
int main(){
int n;
printf("number is %d\n", n);
return 0;
}該程式中,n 並沒有被正確初始化,不過 GCC 預設是不會有錯誤提示的,若開發者有需要,可以使用 -Wall 參數:
gcc -Wall -o main main.c使用 GNU Debugger#
若我們需要使用 GDB(GNU Debugger)進行除錯,在編譯之前,我們需要添加 -g 參數告知 GCC 要盡可能地提供資訊給 GDB:
gcc -Wall -g -o main main.cVerbose Mode#
我們可以使用 -v 參數啟用 verbose mode,獲得詳細的編譯訊息:
gcc -v main.cMacro#
假設開發者在程式中埋了一段程式碼,該程式碼只被用於除錯:
#include <stdio.h>
int main(){
int n = 0;
for(int i = 0; i < 1000; i++){
n += i;
#ifdef DEBUG
printf("n is %d\n", n);
#endif
}
return 0;
}我們除了可以在程式碼中加入 #define DEBUG 外,還可以直接對 GCC 下 -D 參數:
gcc -DDEBUG -o main main.c除了可以用 -D 定義 Macro,GCC 還允許開發者使用 -U 參數取消定義:
gcc -UDEBUG -o main main.c標頭檔目錄#
剛剛已經在「預處理」的部分提到 -I 的用途。此外,GCC 在編譯程式時只預設引入一部份的標頭檔,如果程式需要使用特別的 Library 進行編譯,可以使用 -l 與 -L 參數:
-l告知 GCC 編譯程式時需要使用這個 Library,以 POSIX Thread 為例:gcc -lpthread -o main.out main.c需要注意的是,這裡的 Library name 不等於檔案名稱,在 Linux 下的函式庫都要使用
lib開頭,其中*.so是動態連結函式庫,*.a是靜態連結函式庫。由此可知,把 File name 的lib和.so去掉就是 Library name 了。-L:只要函式庫的存放路徑為:/lib/usr/lib/usr/local/lib
都可以直接使用
-l進行連結;換句話說,如果 Library 的位置並非上述的目錄,我們就需要用-L告知 GCC Library File 所在的目錄位置:gcc -lsum -L/home/gtwang/lib -o main.out main.c
查找依賴關係#
Makefile 可以讓開發者省略複雜的編譯選項及參數,考慮以下專案結構:
|-- project
|-- src/
| |-- main.c
| |-- linked-list.c
| |-- linked-list.h
| |-- node.c
| |-- node.h並且,在 main.c 中引用了 linked-list.h,當我們使用下面命令,就可以查找出 main.c 的依賴關係:
gcc -MM main.c輸出:
main.o: main.c linked-list.h再假設 linked-list.h 中有使用到 node.h,輸出就會是:
main.o: main.c linked-list.h node.h如果希望將標準庫的依賴關係也列出來,使用 -M 即可:
gcc -M main.c關於依賴關係,還有相當多種參數可以玩,詳細資訊可以參考原文 Reference。
原文出處#
- 原書/iThome:https://ithelp.ithome.com.tw/articles/10271608