Makefile 編輯一個工程中的原始檔不計其數,其按類型、功能、模組分別放在若干個目錄中,makefile定義了一系列的規則來指定,哪些檔案需要先編譯,甚至於進行更複雜的功能操作,因為makefile就像一個Shell腳本一樣,其中也可以執行作業系統的命令。
所要完成的Makefile 檔案描述了整個工程的編譯、連線等規則。其中包括:工程中的哪些原始檔案需要編譯以及如何編譯、需要建立那些函式庫檔案以及如何建立這些函式庫檔案、如何最後產生我們想要的可執行檔。儘管看起來可能是很複雜的事情,但是為工程編寫Makefile 的好處是能夠使用一行命令來完成“自動化編譯”,一旦提供一個(通常對於一個工程來說會是多個)正確的 Makefile。編譯整個工程你要做的唯一的一件事就是在shell 提示字元下輸入make指令。整個工程完全自動編譯,大大提高了效率。
make是一個指令工具,它解釋Makefile 中的指令(應該說是規則)。在Makefile檔案中描述了整個工程所有檔案的編譯順序、編譯規則。 Makefile 有自己的書寫格式、關鍵字、函數。像C 語言有自己的格式、關鍵字和函數一樣。而且在Makefile 中可以使用系統shell所提供的任何指令來完成想要的工作。 Makefile(在其它的系統上可能是另外的檔名)在絕大多數的IDE 開發環境中都在使用,已經成為一種工程的編譯方法。
makefile帶來的好處是——“自動化編譯”,一旦寫好,只需要一個make命令,整個工程完全自動編譯,極大的提高了軟體開發的效率。 make是指令工具,是解釋makefile中指令的指令工具,一般來說,大多數的IDE都有這個指令,例如:Delphi的make,Visual C++的nmake,Linux下GNU的make。可見,makefile都成為了工程上的編譯方法。
Make工具最主要也是最基本的功能就是透過makefile檔案來描述原始程式之間的相互關係並自動維護編譯工作。而makefile 文件則需要按照某種語法進行編寫,文件中需要說明如何編譯各個原始檔並連接產生可執行文件,並要求定義原始檔之間的依賴關係。 makefile 檔案是許多編譯器--包含 Windows NT 下的編譯器--維護編譯資訊的常用方法,只是在整合開發環境中,使用者透過友善的介面修改 makefile 檔案而已。 在 UNIX 系統中,習慣使用 Makefile 作為 makefile 檔案。如果要使用其他檔案作為makefile,則可利用類似下面的make 指令選項指定makefile 檔案:
$ make -f Makefile.debug _例如,一個名為prog的程式由三個C原始檔filea.c、fileb .c和filec.c以及函式庫檔LS編譯生成,這三個檔也分別包含自己的頭檔a.h 、b.h和c.h。通常情況下,C編譯器將會輸出三個目標檔filea.o、fileb.o和filec.o。假設filea.c和fileb.c都要宣告用到一個名為defs的文件,但filec.c不用。即在filea.c和fileb.c裡都有這樣的聲明:
include "defs"
那麼下面的文檔就描述了這些文件之間的相互聯繫:
0 #It is a example for describing makefile
0 #It is a example for describing makefile註解行
1 prog : filea.o fileb.o filec.o #指定prog由三個目標檔案filea.o、fileb.o和filec.o連結產生
2 cc filea.o fileb.o filec.o -LS -o prog #如何從prog所依賴的文件建立可執行檔
3 filea.o : filea.c a.h defs #指定filea.o目標文件,以及它們所依賴的.c和.h文件以及defs檔案
4 cc -c filea.c #如何從目標所依賴的檔案建立目標,即如何從filea.c建立filea.o
5 fileb.o : fileb.c b.h defs #指定fileb.o目標檔案,以及它們所依賴的.c和.h檔案以及defs檔案
6 cc -c fileb.c #如何從目標所依賴的檔案建立目標,即如何從fileb.c建立fileb.o
7 filec. o : filec.c c.h #指定filec.o目標文件,以及它們所依賴的.c和.h文件
🎜8 cc -c filec.c #如何從目標所依賴的文件建立目標,即如何從filec. c建立filec.o🎜這個描述文檔就是一個簡單的makefile文件,採用深度優先的原則來執行編譯指令。我們針對上例的程式碼方面進行一些基礎性說明:CC 是一個全域變量,它指定你的Makefile所用的編譯器,一般預設是gcc;.o文件是unix下的中間程式碼目標文件,就如同在windows下的.obj檔一樣,在unix下產生.o檔的過程叫編譯(compile),將無數.o檔集合產生可執行檔的過程叫連結(link);有時會在unix介面下看到.a文件,那是Archive File,相當於windows下的庫文件Library File,.a文件作用是:由於源文件太多(上例是指.c和.h文件過多),編譯生成的中間目標文件( .o檔)太多,而在連結時需要明顯指出中間目標檔名,這對於編譯很不方便,所以,我們要給中間目標檔打個包,這個包就是.a檔。
當filea.c或a.h檔案在編譯之後又被修改,則make 工具可自動重新編譯filea.o,如果在前後兩次編譯之間,filea.c 和a.h 都沒有被修改,而且filea.o還存在的話,就沒有必要重新編譯。這種依賴關係在多原始檔的程式編譯中尤其重要。透過這種依賴關係的定義,make 工具可避免許多不必要的編譯工作。當然,利用Shell腳本也可以達到自動編譯的效果,但是,Shell 腳本將全部編譯任何源文件,包括哪些不必要重新編譯的源文件,而make 工具則可根據目標上一次編譯的時間和目標所依賴的原始檔的更新時間而自動判斷應編譯哪個原始檔。 _
讓我們先來粗略地看一看Makefile的規則。 [3] target ... : prerequisites ... command ... ... 目標:依賴 執行指令 ... target也就是一個目標文件,可以是Object File,也可以是執行文件。也可以是一個標籤(Label)。 ① prerequisites就是,要產生那個target所需的檔案或是目標。 ② command也就是make需要執行的指令。 (任意的Shell指令) 這是一個檔案的依賴關係,也就是說,target這一個或多個的目標檔案依賴prerequisites中的文件,其產生規則定義在command中。說白一點就是說,prerequisites中如果有一個以上的檔案比target檔要新的話,command所定義的指令就會被執行(command一定要以Tab鍵開始,否則編譯器無法辨識command),減少重複編譯,提高了其軟體工程管理效率。
Makefile中允許使用簡單的宏指涉原始檔及其相關編譯訊息,在Linux中也稱宏為變數。在引用巨集時只需在變數前加$符號,但值得注意的是,如果變數名的長度超過一個字符,在引用時就必須加圓括號()。 有效的巨集引用 $(CFLAGS) $Z $(Z) 其中最後兩個引用是完全一致的。 要注意的是一些巨集的預定義變量,在Unix系統中,$*、$@、$?和$
GNU make 的主要預定義變數 預定義變數 意義 $* 不包含副檔名的目標檔案名稱。 $+ 所有的依賴文件,以空格分開,並以出現的先後為序,可能包含重複的依賴文件。 $