主要介紹在ubuntu下利用GNU進行編譯的過程和部分指令的含義, 幫助新手小白入門。
(Part A.)寫在前面的話
step1. 常說到的GNU、gcc和g++什麼關係?
關於這個可能會困擾到你的問題,推薦gcc與g++的關係,博主給出了簡短而詳實的解釋。
總結就是兩句話:1. gcc是GNU的簡稱;2. g++包含gcc。
step2. 安裝GNU的方案網上一大堆,這裏也推薦一篇是我之前自己總結的ubuntu下CPP開發與GNU的安裝。
(Part B.) 下面介紹下在ubuntu下利用g++編譯cpp文件
step1. 寫一個簡單的測試程序,當然要用到hello world啦! 命名爲test.cpp
#include <iostream>
int main()
{
std::cout << "Hello World!" << std::endl;
return 1;
}
step2. 利用下述指令可以直接生成一個可執行文件
$ g++ test.cpp -o test
然後執行就可以看到打印結果啦
$ ./test
Hello World!
(Part C.)過程詳解
上面Part B部分一行指令直接由.cpp源碼文件生成了可執行文件(僅有文件名,沒有擴展名)。這一過程主要包括四個階段:預處理、編譯、彙編、鏈接,下面分別對各個過程進行介紹。
step 0. 首先明確一下g++的命令格式
g++ [指令] 待處理文件 [指令] 輸出文件
step 1. 預處理
預處理主要是針對文件中#include和宏指令進行處理的,處理的方式就是將這些指令對應的內容插入到其對應的地方。指令語句爲:
$ g++ -E test.cpp -o test.i
其中,-E是指的調用預處理指令,用來處理test.cpp文件,處理的目的是生成一個.i的文件,我們用-o test.i來指明(對於cpp的預處理文件,也可以是.ii的後綴)。運行上述指令後,會在同級目錄下生成test.i預處理文件。如下:
#include <iostream>
#define NUM 100
int main()
{
std::cout << NUM << std::endl;
std::cout << "Hello World!" << std::endl;
return 1;
}
上面一段代碼是我們的實驗代碼,運行預處理指令後,會將#include和#define的內容插入到.i文件中,如下圖所示:
宏指令NUM已經被100代替, 同時注意到main函數是從兩萬八千多行開始的, 之前的代碼,其實就是#include的內容。
step 2. 編譯
編譯就是對預處理文件.i進行詞法分析,語法分析,語義分析,最終產生彙編文件.s,可以簡單理解爲將C代碼“翻譯”成彙編代碼。
$ g++ -S test.i -o test.s
運行上述指令後,會在同級目錄下生成test.s彙編文件。
step 3. 彙編
彙編是將彙編代碼翻譯成機器可執行的指令,生成目標文件.o。整個過程較爲簡單,幾乎只是按照彙編指令和機器指令進行一一翻譯。
$ g++ -c test.c -o test.o
運行上述指令後,會在同級目錄下生成test.o目標文件。
step 4.鏈接
鏈接就是將全部的目標文件按照一定規則連接在一起,共同生成可執行文件的過程。
$ g++ test.o -o test
其中,鏈接指令是沒有指令關鍵字的,所以g++後面直接鍵入需要連接的目標文件。之後會生成test可執行文件,一般可執行文件是沒有後綴的。
step 5. 運行
運行可執行文件,即可得到預料的輸出結果,如下所示。
$ ./test
100
Hello World!
(Part D. )總結
四個過程:預處理(.i文件) -> 編譯(.s文件) -> 彙編(.o文件) -> 鏈接(可執行文件)。