編譯流程

在完成原始碼後,要經過一個名為「編譯」的系列行為,讓原始碼成為可執行檔。

註:此處的「編譯」指的是前置處理、組譯、編譯及連結四項動作的集合,並不單指編譯(Compile)這項動作。

前置處理(Preprocess)

原始碼會先經過前置處理手續,用意是將 前置處理器(Preprocessor)中定義的內容進行處理,方便後續編譯流程。

關於前置處理器會在後面的章節詳細說明,在此處僅需要瞭解 #include <stdio.h>就是前置處理器的一種即可。

在前置處理時,編譯器會去除所有前置處理器,以 #include <stdio.h>為例,前置處理會嘗試取得 C 語言內建的 stdio.h檔案,並將檔案內容經過前置處理後置入我們的原始碼中。

舉例而言,我們擁有上一節所撰寫的程式碼HelloWorld.c

#include <stdio.h>

int main()
{
    puts("Hello World");
    return 0;
}

我們可以利用 gcc 指令將 HelloWorld.c 預處理為 pre.c

gcc -o pre.c -E HelloWorld.c

註:pre.c 為可自行設定之檔案名稱,可以變更 gcc 之參數 -o 後方的值決定輸出的檔案名稱

編譯(Compile)

編譯是將已經過前置處理的原始碼轉化為組合語言(Assembly)的過程。

可能一行 C 語言指令就代表著數十行的組合語言,編譯器也會在此時針對程式進行最佳化(減少記憶體空間使用量、降低時間複雜度)

我們可以利用 gcc 指令將 pre.c 編譯為 asm.s

gcc -o asm.s -S pre.c

組譯(Assemble)

一般來說,組合語言可一對一翻譯為目的程式(Object Program,內容包含 0, 1 的機器語言)。

在組譯階段就是將組合語言組譯為目的程式。

我們可以利用 gcc 指令將 asm.s 組譯為目的程式 HelloWorld.o

gcc -o HelloWorld.o -c asm.s

連結(Link)

有時候一個大型程式可能是由多個元件所組成,這些元件可能來自多個不同的目的程式。

在此時會連結多個目的程式,產生可執行檔。

此階段編譯器也可能會根據編譯指令加入部份作業系統資訊。

我們可以利用 gcc 指令將 HelloWorld.o 連結後產生可執行檔 HelloWorld.out

gcc -o HelloWorld.out HelloWorld.o

如果有多個目的程式,則可以利用下方兩種指令連結並產生可執行檔(擇一即可)

gcc -o HelloWorld.out 1.o 2.o
gcc -o HelloWorld.out *.o

簡化

本節中為了說明各編譯流程行為,故將整個編譯流程拆分為四個動作。

其實可以利用一行指令解決

gcc -o HelloWorld.out HelloWorld.c

如果有多個 .c 檔生成一個可執行檔,則可以利用下列指令

gcc -o HelloWorld.out *.c

然而,在編譯大型程式時,可能會重複利用同一個目的程式,如果每一個目的程式都在被引用時重新編譯,勢必會拖長編譯時間。

故常見的解決方案為:先將全部(或部份使用較頻繁的).c 檔前置處理、編譯及組譯為目的檔案 .o 然後再一起編譯為可執行檔。

目前原始碼的數量並不多,這樣的方法已經足夠,未來我們會用更方便的工具達成多個原始碼的自動化編譯(第十四章:Makefile)。

results matching ""

    No results matching ""