目標、前置條件與配方
這三個詞就是一條 Makefile 規則的全部文法。想像做一份三明治:三明治是你想要的(目標 target),麵包和餡料是它由什麼做成(前置條件 prerequisites),而「把餡料夾進兩片麵包之間」是你怎麼把它做出來(配方 recipe)。Makefile 裡的每條規則都有這同樣的形狀。
寫出來,一條規則在一行上長得像「target: prerequisite1 prerequisite2」,後面接一行或多行配方,每行以 TAB 縮排,內含 shell 指令。目標通常是 Make 該建立的檔案名稱(像 app 或 main.o),但也可以是個標籤。前置條件是該目標所相依的檔案;只要其中任何一個比目標新,Make 就認為目標已過時。配方則是 Make 用來(重新)建構目標的確切指令。這就叫做相依規則:一個目標相依於它的前置條件,並由它的配方從這些前置條件建出。
為什麼重要:只要你誠實地寫出每個部分的前置條件,就能讓 Make 建立起一幅完整的相依圖,並以正確順序、只動真正需要動的部分來重建。經典的錯誤是漏掉一個前置條件,例如沒列出某個原始碼檔以 #include 引入的標頭檔;這樣當那個標頭改變時 Make 不會重建,於是你得到一個過時、不一致的程式,卻沒有任何錯誤訊息。
app: main.o util.o <- 目標 : 前置條件 gcc main.o util.o -o app <- 配方(TAB 縮排) 只有當 main.c(或它需要的標頭檔)比 main.o 新時,main.o 才會被重建。
一張圖看懂相依規則:一個目標、它賴以建出的前置條件,以及把它建出來的配方。
漏掉前置條件是無聲的臭蟲:若某個原始碼相依的標頭檔沒被列出,Make 在標頭改變時不會重建,產出過時的二進位檔。真實專案會自動產生標頭相依(例如 gcc -MMD)來避免這點。