System software需要build成machine code (executable file) 後才能執行,因此我們會先介紹system software的build flow。
Preprocessor : 將source code當中的註解去除、macro與include展開等,獲得一個展開後的source code (expanded source code)
Compiler: 將expanded source code分析分析語意與邏輯之後,轉換成邏輯相同的assembly code file
Assembler: 將assembly code轉換成machine code並生成object file
Linker: 將多個object files或library(將object files歸檔的檔案)連結在一起,成為可執行檔
Large-scale software的source code架構通常會是一個複雜的檔案結構,.c檔會被分門別類放在不同的路徑下,.h檔會分成public與private放在不同的路徑,所以每一支C file要build的時候,為了private .h檔,include path需要置換,同一份C檔的會依照不同目的、設定,build出不一樣的object file。
會耗費大量人力時間,只要有檔案被修改,因為沒有方法可以追蹤受這支檔案影響的相關檔案,需要把整個software project重新build。
可以利用自動化的build automation tool來協助build flow,例如: make
makefile
是一種特定格式的文字檔案,告訴make編譯的命令、流程如何被執行
makefile
當中會定義目標 (target)、先決條件檔案(prerequisite)、以及命令(commands),而每一個prerequisite也可以是另一個target並定義它的prerequisite及commands
make會檢查target和prerequisite的關係,如果prerequisite的修改時間比targe晚,make就會執行這項targe底下的commands
如果prerequisite本身也是一個target,則make會先往下檢查這個prerequisite當作target時和自己的prerequisite的修改時間關係,如需要執行command則會先執行這一層的command,以此類推 (dependency tree traversal)
如果修改了一支檔案,只有被修改檔案及所有和被修改檔案有關係的檔案要被重新build (稱為: incremental build)
Makefile可以使用變數與邏輯判斷語法,能程式化地管理build flow
在嵌入式系統上面運行的程式,因為編譯需要的函式庫很大、需要記憶體很多、需要的CPU資源很高,通常不會直接在嵌入式系統裡面編譯,而是透過cross compiler來編譯。
Compiler涉及的系統有三個,這三個系統如果不是同一個,就稱為是cross compiler,如果都相同則稱為native compiler。
Build system: 編譯compiler本身的系統 (compile ARM compiler source code to ARM compiler executable)
Host system: compiler運行的系統 (use ARM compiler executable to compile a software souce code to ARM system executable software)
Target system: 運行compiler編譯結果的系統 (run ARM system executable software)
Cross compiler範例: 用x86系統(native)編譯出在x86系統(host)運行的針對ARM系統(target)的compiler
我們今天認識system software的build flow以及協助它的工具,而其中最重要的工具: compiler toolchain也是需要被開發的,所以我們明天會簡單介紹如何開發compiler toolchain。