之前在linux下開發,太過於依賴ide了,結果導致出現了某些編譯依賴問題的時候,解決的效率太低,因此特別寫了這一系列的筆記,作為學習的參考,也希望幫助有需要的孩砸。
計算機最終只能識別機器碼, 所以編譯的最終目的是把c、c++源**轉換到機器碼,實現這個過程的最核心的工具是編譯器,linux平台下最主流的編譯器無非就是gcc和clang這兩個;當然也有除錯過程和除錯工具gdb,不過在這裡不在敘述了。
編譯分為3個過程,分別是:
編譯預處理
生成目標檔案和編譯
執行鏈結
編譯預處理主要是為了處理預處理的指令,比如#include
、#define
、ifdef
和ifndef
等。
#define
的內容,會在與處理過程中進行替換。#include
會替換成相應的原始檔內容;ifndef
和ifdef
是為了處理重複編譯引用的問題,這一般在標頭檔案中進行使用。
預處理完成後,所有的原始檔內容會進行相應的替換操作。之後,預處理過程會把上述的處理過程,生成乙個單獨的輸出流,這裡面也會包括每一行的**,方便編譯器出錯時,顯示出錯位置。
這一步的任務是把預處理的流轉換到機器碼。因為有很多不同的標頭檔案和原始檔,所以會生成很多的目標檔案(比如.o
或.obj
等),這些目標檔案是二進位制型別。
目標檔案可以引用未定義的符號,這些是我們宣告了但是沒有定義的函式或者類等。但是,編譯器不會管這些,只要原始檔沒有語法等錯誤,就可以產生相應的目標檔案。但是,一般編譯器在遇到這類錯誤時,會停止編譯的過程。
上述做法非常有用,因為我們如果只改變了乙個單獨的檔案,編譯器就不會每次都重新編譯整個專案。生成的目標檔案會被放在乙個稱為靜態鏈結庫的特殊文件中,這使得編譯器可以非常容易的重複使用它們。這些目標檔案雖然是二進位制檔案,但是現在還無法被計算機作業系統直接執行,還需要執行下一步的鏈結操作才可以。
鏈結的核心步驟就是把多個分散的目標檔案轉換成乙個可執行檔案或者動態鏈結庫之類的,這比如windows下的.exe
可執行檔案或者linux下的.so
動態鏈結檔案等。連線過程中,會處理上一步中生成的目標檔案,比如尋找目標檔案中標註的宣告等,如果在乙個目標 檔案中找不到相應的宣告,鏈結器會查詢目標檔案宣告的那些檔案,如果都找不到,會報錯。如果都找到相應的目標檔案,沒有任何錯誤,那麼編譯器會最終生成乙個可執行檔案或者鏈結庫等。
在上面,我們描述了乙個完整的編譯過程,依次是:編譯預處理->編譯->鏈結。通過上述的描述,我們知道,預處理僅是處理#
後面包含的內容,編譯是把每個源**檔案轉換成相應的目標檔案,而鏈結是把目標檔案進行組合等的處理,最終生成乙個可執行檔案或者鏈結庫。
在這裡,有乙個問題,鏈結的過程中,我們需要引用不同的檔案,或者說有些檔案依賴於其他的編譯完的檔案。舉個例子b.cc
編譯出b.o
,a.cc
編譯出a.o
,而b.cc
檔案引用了a.cc
的檔案,在鏈結的過程中,如果最終需要 生成final
可執行檔案,需要組合a.o
與b.o
,而且必須使得編譯器知道b.o
是依賴a.o
的,否則會編譯出錯。
而make的作用,就是乙個自動化的構建工具,它用來告知編譯器正確的處理順序,保證每個依賴都得到了處理,最後生成相應的工程。而makefile的作用,相當於是乙個圖紙,它用來告訴make,具體怎樣處理編譯過程。
不使用make也可以直接利用編譯器處理整個專案,如果只是個小型的工程,比如就幾個源**檔案,那麼依靠編譯器並新增幾個指令完全可以處理。但是,如果是個較大的專案,裡面有複雜的依賴關係,此時再靠編譯器新增幾個處理指令的方式,已經不太現實了,此時使用make和makefile來進行自動化構建才是正確的選擇。
上文中提到了make是用來處理編譯順序和依賴關係並構建最終專案的工具,但是問題來了,不同的平台會有不同的構建方式。比如,linux生成最終的二進位制程式和.so
動態鏈結,而windows生成.exe
程式和.lib
動態鏈結;同時兩者的依賴可能還不同。如果在不同的平台寫不同的makefile,會相當麻煩;而且makefile檔案本身的寫法就很複雜,大型工程下,較難閱讀和理解。cmake就是為了解決這些問題的。
cmake本身不執行make過程,而是根據不同平台的特性,生成對應平台的makefie,這樣我們每個工程只要寫乙個cmake檔案即可了,其餘的交給不同平台的處理器來產生不同的makefile檔案即可。而且cmake的語法也更加簡答,適合閱讀。
make編譯器的使用
makefile 變數toolpath tools nasm toolpath nasm nasm.exe make toolpath make.exe r objects boot.asm make後面接檔名 build make img 目標檔案 依賴檔案 會檢測如果 依賴檔案有乙個以上比目標檔...
用make實現的小型c c 可復用編譯器
dir src src 源 資料夾名 dir inc inc 標頭檔案資料夾名 type inc h type src c 當為c 檔案是改為.cpp type obj o cc gcc 編譯c 是改為g lflags 如有編譯選項,則在這裡新增,如 pthread cflags i dir inc...
編譯器自舉和移植
有個著名的問題 mommy,where do compilers comefrom?要解決這個問題,首先來看看t diagram。可以將編譯器用乙個t形圖來表示 其中,s表示souce language,t表示target language,i表示implementationlanguage。根據這...