Windows 下的 Makefile 編寫(一)Makefile的基本規則
作者:cntrump
Makefile對於很多人來說是陌生的,特別是習慣於使用 IDE 的人來說,似乎沒有聽說過 Makefile ,因為Makefile 的工作都由IDE代勞了。但是Makefile 的地位是不可忽略的,從VC誕生到現在Nmake這個實用程序就一直伴隨着VC編譯器一起發行。
很多大的工程都是基於Makefile編譯和維護的,對於開源項目來說,大多數都使用Makefile進行編譯,使用IDE來編譯大型工程是不可想象的。
Makefile是什么?它是一個文本文件,里面記錄着項目由哪些目標構成,以及各個目標的生成方式等信息,Makefile的核心任務是定義一系列的規則,然后由Nmake來解釋執行,任何一個文本編輯器都可以用來編寫Makefile。
先來大概看一下Makefile的基本規則:
代碼:
Target:dependent;command
Command
........
Target 是目標,目標可以是一個文件,也可以是一個標簽,如果Target用作標簽,則稱之為偽目標。Makefile至少要有一個目標。
Dependent是依賴項目,指明目標所依賴的具體項目。依賴項目和目標之間用 : 號分隔。
Command是命令,如果命令和依賴項目在同一行,則需要使用;號與之相隔,各個命令之間使用空格或Tab鍵分開,如果命令是單獨一行,則需要使用Tab縮進。Command命令由Nmake來執行。
上述內容簡單地表明了一個依賴關系,生成Target目標依賴dependent中指定的文件,而生成的規則由Command來定義,Nmake負責執行這些命令。
默認情況下,Nmake會查找當前目錄下任何名稱為Makefile的文件(名稱不區分大小寫,並且沒有后綴),如果你的Makefile文件名稱是其他的,則需要使用 f 參數指定。
以上就是Makefile的核心內容,任何系統的Makefile都是這樣執行的。但是要寫好一個Makefile,僅僅這些還不夠。
對於一個新知識,我更喜歡從做中學。下面舉一個例子來說明上面的規則在實際應用中如何操作:
代碼:
Test.exe:main.obj
Link.exe main.obj /out:Test.exe
main.obj:main.cpp
#僅編譯文件
cl.exe main.cpp
在Makefile中注釋使用 # 號開頭,且僅有這一種注釋方式。它的作用和C++ 語法中的 // 注釋是一樣的。所不同的是 # 號必須放在行首。
上面的Makefile 文件指定了兩個目標,分別是Test.exe 和 main.obj,生成Test.exe需要依賴 main.obj文件,而生成 main.obj文件依賴main.cpp。在目標下方指明了生成該目標方法。
main.cpp 的內容如下:
代碼:
#include <stdio.h>
int main()
{
printf("Hello Makefile!\n");
return 0;
}
將Makefile和main.cpp放置於同一目錄下,在VC的命令提示符窗口中執行 nmake命令,就會自動生成Test.exe和 main.obj兩個文件。再運行生成后的Test.exe測試一下:

在Makefile中定義了兩個目標,Nmake默認只生成Makefile中的第一個目標,由於main.obj是Test.exe 的依賴項,所以main.obj目標也得以執行。
是不是每執行一次namke命令就會重新生成一次目標文件呢?答案:不是。每次都重新生成目標顯然是一種資源浪費,nmake是根據時間戳來決定是否需要重新生成目標。只有在依賴文件不存在或者依賴文件時間高於目標文件時,nmake才會生成目標。
前面的例子已經生成了目標文件,如果修改了main.cpp中的代碼或者刪除了main.obj,都將會重新生成Test.exe。
一般來說,為了使清理中間文件或重新生成目標更加方便,都會在Makefile中加入一個偽目標來清理生成的中間文件。以刪除main.obj為例,Makefile修改如下:
代碼:
Test.exe:main.obj
Link.exe main.obj /out:Test.exe
Main.obj:main.cpp
# 僅編譯文件
cl.exe /c main.cpp
clean:
@del *.obj
@echo Project has clean.
clean是一個偽目標,只是作為標簽使用。clean下的指令是命令行下的刪除文件命令和顯示一個字符串。在命令前加 @ 符號是為了不顯示命令本身。
默認情況下nmake只會生成第一個Test.exe目標,不會執行到clean目標,如果要指定生成目標,需要顯式指定目標名稱:
就指定要執行Makefile中的clean偽目標。執行之后會刪除生成的main.obj並顯示一行文字:

還可以指定多個目標,nmake會從左往右依次生成目標。所以如果要在清除中間之后立即生成Test.exe,可以這么做:
nmake clean Test.exe

一般來說,總是把最終生成的目標放在最前,而把清理中間文件的偽目標放到最后。下一回,我會結合實際的例子再介紹Makefile的其他內容。