2012-12-27 67 views
6

Makefile s中編寫可重用代碼的最佳做法是什麼?編寫可重複使用代碼的最佳做法

假設我有一個Makefile:

.PHONY: all task01-all task01-clean task01-run task02-all task02-clean task02-run 

all: task01-all task02-all 

############################################################################### 
task01-all: task01-clean task01 task01-run 

task01-clean: 
    rm task01 task01.{exi,o} -f 

task01: 
    compiler task01.ext -O2 --make 

task01-run: 
    ./task01 

############################################################################### 
task02-all: task02-clean task02 task02-run 

task02-clean: 
    rm task02 task02.{exi,o} -f 

task02: 
    compiler task02.ext -O2 --make 

task02-run: 
    ./task02 

現在我想添加任務(task03)的新的家庭,我需要copypaste整段,使s/02/03/它並將其添加到.PHONY節 - 這是嘈雜,噁心,只是不正確。

我該如何避免這種情況?我可以用模板重新定義所有任務,以便在一行中添加新的任務組嗎?

回答

9

由於問題是關於在Makefile文件編寫可重用的代碼,我就給瞭如何使用模式規則在GNU做一個例子(它看起來就像你提到.PHONY的目標那樣)。但是,如果你不使用任何品牌的依賴檢查的,它可能是簡單的用一個shell腳本來做到這一點 - 是這樣的:

#!/bin/sh 
TASKS="task01 task02 task03" 

for i in $TASKS; do 
    rm $i $i.ext $i.o -f; 
    compiler $i.ext -O2 --make; 
    ./$i; 
done 

但是,擴大的原則,使我們有另外一個問題解決。表格的行數:

task01-all: task01-clean task01 task01-run 

不說讓什麼樣的順序建立的先決條件 - 只是,他們都需要前task01-all被建造工作要做。相反,每一步的運行應該依賴於它之前的步驟。事情是這樣的:

TASKS=task01-run task02-run task03-run 

.PHONY: all $(TASKS) $(TASKS:run=clean) 

all: $(TASKS) 

$(TASKS:run=clean): %-clean: 
    rm $* $*.ext $*.o -f 

%: %.ext | %-clean 
    compiler $< -O2 --make 

$(TASKS): %-run: % 
    ./$< 

%的規則被稱爲「模式規則」,而且它們避免重新編寫相同的規則多次針對不同的目標一個偉大的工具。一個需要注意的是,Make通常不檢查.PHONY目標的模式規則;我們通過在這些規則前加上目標列表和第二個冒號(例如,$(TASKS):)來告訴Make來明確這一點。

由於task01-run需要task01爲了工作,我們使%-run目標取決於%。另外,你的Makefile顯示你想每次運行乾淨,所以我們使%取決於%-clean。由於%-clean實際上並不產生任何輸出,因此我們將其設置爲「僅限訂單」依賴關係 - Make不會查找時間戳或任何內容,它只會在需要運行%時首先運行%-clean規則規則。 「僅適用於訂單」依賴放置後|

%: %.ext | %-clean 

值得一提的是,製作的最大的優勢之一是它可以通過不重複並不需要重複工作,節省時間 - 也就是說,它只有依賴關係比目標更新時才運行規則。所以,你可以離開關上%-clean的依賴,這將導致使運行僅compiler $< -O2 --make如果%.ext較新,%

%: %.ext 
    compiler $< -O2 --make 

然後,您可以添加規則只是爲了運行所有的%-clean目標:

.PHONY: all $(TASKS) $(TASKS:run=clean) clean 

clean: $(TASKS:run=clean) 

最後一件事:我在食譜中使用了一些特殊變量。 [email protected]代表正在構建的目標。 $<代表第一個依賴項。 $*表示模式規則的「詞幹」(即,與%匹配的部分)。

+0

很好的解釋。謝謝! –

+0

提供「|」的示例很好,謝謝。 –

2

看起來像什麼,我在尋找:

ALLS=task01-all task02-all 
BUILDS=${ALLS:-all=-build} 
CLEANS=${ALLS:-all=-clean} 
RUNS=${ALLS:-all=-run} 

.PHONY: all $(ALLS) $(CLEANS) $(BUILDS) $(RUNS) 

all: $(ALLS) 

############################################################################### 
$(ALLS): $(CLEANS) $(BUILDS) $(RUNS) 

$(CLEANS): 
     rm ${@:-clean=} ${@:-clean=}.{ext,o} -f 

$(BUILDS): 
     compiler ${@:-build=}.ext -O2 --make 

$(RUNS): 
     ./${@:-run=}