在編譯源碼的時候,總會遇到這樣的情況:
1、需要運行一串命令,把一個或多個源文件轉換成一個目標文件,但這些源文件也可能是通過其他源文件生成的。
2、當部分文件發生改變時,只需要運行必要(最少)的命令,生成最新的目標文件。
例如(Masm彙編舉例),我們需要編譯一個hello.exe文件,先將asm源碼編譯成obj文件,然後通過link將多個obj文件鏈接成exe文件。
masm main.asm,main.obj;(編譯main.asm,生成main.obj文件)
masm fun.asm,fun.obj;(編譯fun.asm,生成fun.obj文件)
link main.obj fun.obj,hello.exe;(鏈接main.obj和fun.obj,生成hello.exe文件)
編譯多個源碼文件,並將這些文件最終編譯成需要的庫文件或可執行文件將是一件重複且無聊的工作。如果沒有其他工具輔助,你需要編寫長長的命令(當然,這可以通過腳本進行簡化),並且你還需要記住哪些源碼修改過,否則你需要重新編譯並未修改過的源碼,費時且做無用功。
Make工具配合makefile文件,可以大大簡化這項工作(只需要運行make即可),並且幫助你判斷哪些源碼需要重新編譯。make工具通過載入makefile文件,按照makefile中描述的規則,將需要生成的目標文件和生成目標文件需要的源文件對應起來,並且指定通過源文件生成目標文件的命令,makefile核心語法如下:
target : source ...
command
...
...
上面的語法代表一條依賴規則,target爲目標文件,source爲源文件或依賴文件(可以多個,中間空格分隔),command爲把source文件生成target文件的命令(可多個命令)。
核心思想就是:通過檢查目標文件和源文件的修改時間來決定是否執行command,如果源文件(任何一個)比目標的修改時間更接近當前時間,就需要執行對應的command命令。
注意make並不是按照makefile中所有規則的書寫先後順序執行,而是按照依賴關係樹遞歸執行(從根部開始執行),因爲當make檢查源文件的修改時間時,會存在2種情況:
1、源文件也存在依賴規則,即源文件也是某條依賴規則的目標文件,那麼make程序會檢查該文件的依賴關係,並以此類推,直至源文件不存在依賴關係爲止,並且所有的源文件都要遞歸檢查。相當於創建一個依賴關係樹,makefile種的第一條規則是爲了生成最終的目標文件,後續的規則是對最終稿目標文件的源文件的依賴關係進行補充完善。
2、源文件不存在依賴規則,則直接檢查該文件是否存在,如不存在則報錯。
之前的例子可以這樣編寫makefile文件(可以看到依賴關係是樹狀結構,先寫最終目標,然後寫分支依賴):
hello.exe : maim.obj fun.obj
link maim.obj fun.obj,hello.exe;
main.obj : main.asm
masm main.asm,main.obj;
fun.obj : fun.asm
masm fun.asm,fun.obj;
執行順序如下,makefile的最終目標是hello.exe,它依賴maim.obj和fun.obj;maim.obj也存在依賴,其依賴main.asm,main.asm無任何依賴,則檢查main.obj和main.asm的修改時間,決定是否執行command(masm main.asm,main.obj;)。fun.obj也按此流程進行遞歸檢查。隨後檢查hello.exe與maim.obj和fun.obj的修改時間,決定是否執行command(link maim.obj fun.obj,hello.exe;)。如按照makefile中的書寫的規則的先後順序執行,第一次編譯後又修改fun.asm源碼,如果按書寫的順序執行,第二次執行make命令,第一條依賴規則就無需執行,maim.obj和fun.obj都存在且hello.exe的時間比它兩都更新,第二條相同。只有第三條依賴規則需要執行(因fun.asm修改過)。但生成新的fun.obj文件後,本應執行第一條依賴規則,這種情況就無法執行,除非第三次執行make程序。
我接觸的make程序主要有Microsoft系和Linux系兩大陣營,主要思想差不多,區別在高級功能(如宏、變量等)。Microsoft的nmake和Linux(Linux的make和Borland的make)核心思想都一致,但Microsoft在dos時代的編譯器(Masm5.0及之前,Microsoft C 5.0之前)的make程序卻有所不同,其並不生成依賴樹,而是簡單的按makefile的書寫順序執行,則上述例子的makefile文件需修改如下:
main.obj : main.asm
masm main.asm,main.obj;
fun.obj : fun.asm
masm fun.asm,fun.obj;
hello.exe : maim.obj fun.obj #soruce文件之間也可用逗號分割
link maim.obj fun.obj,hello.exe;
Makefile的高級用法,請參考陳皓的《跟我一起寫 Makefile》吧。