編譯是將source code轉換為object code的過程,由compiler完成。Compiler會檢查source code的語法或結構錯誤,如果source code沒有錯誤,則生成object code。
C compilation process是將source code當作input,轉成object code or machine code。Compilation process 分成四大步驟, i.e., Pre-processing, Compiling, Assembling, and Linking。
Source code是在文字編輯器中編寫的code,source code file的附檔名為".c"。Source code將會先經過preprocessor處理,preprocessor會將source code中的comments移除掉、引入included file的內容、處理 conditional compilation、macro置換code snippet等。
Compiler將source code轉成assembly code,一般來說分成三階段Front End (Analysis)、IR-Intermediate Representation、Back End (Synthesis)。
Front End (Analysis): Lexical Analyzer、Syntax Analyzer、Semantic Analyzer
Back End (Synthesis): Code Optimizer、Code Generator
分成三階段的好處是,這樣可以reuse components,assembly code是在描述和CPU設計有強烈相關的指令,例如:
我們想從x86指令集執行換到 arm指令集上執行,那就只需要更改Back End (Synthesis),Front End (Analysis)可以reuse。
Assembler將assembly code轉成object code,產出的object file與source file同名,其附檔名為".o/.obj",例如: source file為'hello.c'而object file會是'hello.obj'。
Linker把多個不可執行的object file組合起來(例如.o)變成可執行的object file (例如 .out/.exe),並link被引用的函式庫。例如: hello.c用到的printf是c library (libc.a)的一部分而非在hello.c內實作,所以若只編譯了hello.c會發生link error,因為在hello.c編譯完成之後找不到printf這支function,就會發生link error。
在嵌入式系統上面運行的程式,因為編譯需要的函式庫很大、需要記憶體很多、需要的CPU資源很高,通常不會直接在嵌入式系統裡面編譯,而是透過cross compiler來編譯。
Compiler涉及的系統有三個,這三個系統如果不是同一個,就稱為是cross compiler,如果都相同則稱為native compiler。
Build system: 編譯compiler本身的系統
Host system: 運行compiler的系統
Target system: compiler編譯結果運行的系統
例如: 在build system先編譯出compiler,compiler在host system當中編譯出target system需要的object/machine code。
Cross compiler範例: 用x86系統(native)編譯出在x86系統(host)運行的針對ARM系統(target)的compiler