重新發(fā)現(xiàn)make: 規(guī)則背后的力量
我過去認為 makefile 只是一種將一組組的 shell 命令列出來的簡便方法;過了一段時間我了解到它們是有多么的強大、靈活以及功能齊全。這篇文章帶你領略其中一些有關規(guī)則的特性。
備注:這些全是針對 GNU Makefile 的,如果你希望支持 BSD Makefile ,你會發(fā)現(xiàn)有些新的功能缺失。感謝 zge 指出這點。
規(guī)則
規(guī)則是指示 make 應該如何并且何時構建一個被稱作為目標的文件的指令。目標可以依賴于其它被稱作為前提的文件。
你會指示 make 如何按步驟構建目標,那就是一套按照出現(xiàn)順序一次執(zhí)行一個的 shell 命令。語法像這樣:
target_name : prerequisitesrecipe
一但你定義好了規(guī)則,你就可以通過從命令行執(zhí)行以下命令構建目標:
$ make target_name
目標一經構建,除非前提改變,否則 make 會足夠聰明地不再去運行該步驟。
關于前提的更多信息
前提表明了兩件事情:
- 當目標應當被構建時:如果其中一個前提比目標更新,
make假定目的應當被構建。 - 執(zhí)行的順序:鑒于前提可以反過來在 makefile 中由另一套規(guī)則所構建,它們同樣暗示了一個執(zhí)行規(guī)則的順序。
如果你想要定義一個順序但是你不想在前提改變的時候重新構建目標,你可以使用一種特別的叫做“唯順序”的前提。這種前提可以被放在普通的前提之后,用管道符(|)進行分隔。
樣式
為了便利,make 接受目標和前提的樣式。通過包含 % 符號可以定義一種樣式。這個符號是一個可以匹配任何長度的文字符號或者空隔的通配符。以下有一些示例:
%:匹配任何文件%.md:匹配所有.md結尾的文件prefix%.go:匹配所有以prefix開頭以.go結尾的文件
特殊目標
有一系列目標名字,它們對于 make 來說有特殊的意義,被稱作特殊目標。
你可以在這個文檔發(fā)現(xiàn)全套特殊目標。作為一種經驗法則,特殊目標以點開始后面跟著大寫字母。
以下是幾個有用的特殊目標:
.PHONY:向make表明此目標的前提可以被當成偽目標。這意味著make將總是運行,無論有那個名字的文件是否存在或者上次被修改的時間是什么。.DEFAULT:被用于任何沒有指定規(guī)則的目標。.IGNORE:如果你指定.IGNORE為前提,make將忽略執(zhí)行步驟中的錯誤。
替代
當你需要以你指定的改動方式改變一個變量的值,替代就十分有用了。
替代的格式是 $(var:a=b),它的意思是獲取變量 var 的值,用值里面的 b 替代詞末尾的每個 a 以代替最終的字符串。例如:
foo := a.obar : = $(foo:.o=.c) # sets bar to a.c
注意:特別感謝 Luis Lavena 讓我們知道替代的存在。
檔案文件
檔案文件是用來一起將多個數(shù)據(jù)文檔(類似于壓縮文件的概念)收集成一個文件。它們由 ar Unix 工具所構建。ar 可以用于為任何目的創(chuàng)建檔案,但除了靜態(tài)庫,它已經被 tar 大量替代。
在 make 中,你可以使用一個檔案文件中的單獨一個成員作為目標或者前提,就像這樣:
archive(member) : prerequisiterecipe
***的想法
關于 make 還有更多可探索的,但是至少這是一個起點,我強烈鼓勵你去查看文檔,創(chuàng)建一個笨拙的 makefile 然后就可以探索它了。

























