C/C++編譯流程
編譯的基本流程
graph TD
A(預處理) --> B(編譯)
B --> C(匯編)
C --> D(鏈接)
詳細過程
#include <stdio.h>
int main(int argc, char *argv[])
{
printf("Hello World!\n");
return 0;
}
預處理(cpp)
gcc -E hello.c -o hello.i
預處理,主要處理以下指令:宏定義指令,條件編譯指令,頭文件包含指令。 預處理所完成的基本上是對源程序的“替代”工作。經過此種替代,生成一個沒有宏定義、沒有條件編譯指令,頭文件都被展開(遞歸展開)的文件。
編譯(ccl)
gcc -S hello.i -o hello.s
編譯,就是把C/C++代碼“翻譯”成匯編代碼。
匯編(as)
gcc -c hello.s -o hello.o
匯編,就是將生成的匯編代碼翻譯成符合一定格式的機器代碼,在Linux上一般表現為ELF目標文件。
鏈接(ld)
gcc hello.o -o hello
鏈接,將生成的目標文件和系統庫文件進行鏈接,最終生成了可以在特定平臺運行的可執行文件。為什麽還要鏈接系統庫中的某些目標文件(crt1.o, crti.o等)呢?這些目標文件都是用來初始化或者回收C運行時環境的,比如說堆內存分配上下文環境的初始化等,實際上crt也正是C RunTime的縮寫。這也暗示了另外一點:程序並不是從main函數開始執行的,而是從crt中的某個入口開始的,在Linux上此入口是_start。而且默認情況下,ld是將這些系統庫文件(本身也是動態庫)都是以動態鏈接方式加入應用程序的,如果要以靜態連接的方式進行,需要顯示的指定ld命令的參數-static。
其它
此外,還有一個優化階段。優化處理是編譯系統中一項比較艱深的技術。它涉及到的問題不僅同編譯技術本身有關,而且同機器的硬件環境也有很大的關系。優化一部分是對中間代碼的優化。 這種優化不依賴於具體的計算機。另一種優化則主要針對目標代碼的生成而進行的。對於前一種優化,主要的工作是刪除公共表達式、循環優化(代碼外提、強度削弱、變換循環控制條件、已知量的合並等)、復寫傳播,以及無用賦值的刪除,等等。 後 一種類型的優化同機器的硬件結構密切相關,最主要的是考慮是如何充分利用機器的各個硬件寄存器存放的有關變量的值,以減少對於內存的訪問次數。另外,如何 根據機器硬件執行指令的特點(如流水線、RISC、CISC、VLIW等)而對指令進行一些調整使目標代碼比較短,執行的效率比較高。
參考
- C/C++程序編譯流程(預處理->編譯->匯編->鏈接)
- C++編譯鏈接過程
C/C++編譯流程