一般咱們用IDE寫完一個程序後,點擊編譯按鈕的時候,內部到底發生了什麼?爲何會生成一個可執行文件?這個過程到底有哪些步驟呢?是很簡單仍是很複雜呢?這篇文章,咱們把這些事情講清linux
首先要明確一點,編譯只是一個統稱,編譯的整個過程有預處理、編譯、彙編和連接的過程函數
咱們給出一個特別簡單的程序優化
//test.c #include <stdio.h> #define max 5 int main() { printf("max = %d\n", max); return 0; }
預處理階段的指令通常都是以#來開頭的,替換#include包含的頭文件,替換#define定義的宏,刪除註釋,去掉#ifdef不符合條件的那一部分,全部#開頭的代碼都會在預處理階段完成處理。spa
預處理命令:gcc -E test.c -o test.i3d
這裏-E的做用是讓程序在預處理完成以後就中止,爲了方便咱們後面的觀察。咱們在當前目錄下ls,就能夠看見多了一個test.i的文件,打開它能夠看到不少變量、函數等等的聲明,這些都是stdio.h這個頭文件展開的結果,拉到最後,能夠看到咱們定義的宏max被替換成5了。code
大學若是學的是計算機專業的童鞋必定會學過一門《編譯原理》的課,這門課幾乎會把不少大學生折騰得死去活來。而這個編譯的過程也正式編譯原理裏面介紹的內容,包括詞法分析、語法分析、語義分析、程序優化等等一系列的過程,這些都是編譯器的核心內容,若是你想開發編譯器,這個過程你要很是很是的精通!這個過程就是把程序編譯成更接近機器語言的彙編語言。平時咱們用IDE編譯的時候,常常看見的錯誤和警告,通常都是在過程發出的。blog
編譯命令:gcc -S test.i -o test.s開發
這裏-S的做用是讓程序在編譯完成以後就中止,爲了方便咱們後面的觀察。咱們在當前目錄下ls,就能夠看見多了一個test.s的文件,打開它看到的一大堆彙編指令。這些指令,我根本看不懂,說實話,沒有接觸過彙編語言的人,幾乎都是看不懂的。可是若是你是想在編譯器這個底層領域翻江倒海的話,彙編語言是必需要懂的。get
彙編語言有些專業人員看得懂,可是計算機是根本就看不懂的。計算機看得懂的僅僅只有010101這種機器語言,因此咱們還要將彙編語言轉換成機器語言,至於這個過程怎麼轉的,不在本文的討論範圍,也討論不了,由於我也不知道。這些都是那些很是厲害的大神的研究領域,真不是我誇大這個難度,能開發出商用編譯器的人,至少在計算機領域絕對都是逆天的天選之子。編譯器
彙編命令:gcc -C test.i -o test.o
咱們在當前目錄下ls,就能夠看見多了一個test.o的文件,打開它看到的一大堆亂碼,實際上這些都是二進制命令,而這些命令纔是計算機能看得懂的。
二進制文件雖然計算機能夠看懂了,可是若是你的源文件中用到了其餘本身寫的頭文件的函數,或者是第三方靜態庫動態庫,這時候還須要進行把它們連接起來生成可執行文件,才能夠正確的被執行。
連接命令:gcc test.o -o test
可是若是引用的頭文件是C/C++語言級別自帶的話,換種說法就是,只有一個源文件,貌似不須要進行連接這一步,直接運行上面編譯生成的.o文件也能夠。反而進行連接操做的話會報這個錯誤,緣由我暫時也沒找到,若是知道的朋友歡迎留言評論。
/opt/rh/devtoolset-9/root/usr/libexec/gcc/x86_64-redhat-linux/9/ld: error in test.o(.eh_frame); no .eh_frame_hdr table will be created
以上就是編譯的幾個步驟,只有比較清晰地掌握好每一個步驟,才能真正地把編譯的整個流程搞清楚。固然,你也能夠用一步到位的方式進行編譯:
gcc test.c -o test
這樣能夠直接生成可執行文件。
更多精彩內容,請關注同名公衆:一點月光(alittle-moon)
相關編譯的文章請閱讀: