2012-12-13 64 views
10

這裏是我的Makefile的簡化版本:Makefile的依賴沒有爲假目標工作

.PHONY: all 

all: src/server.coffee 
    mkdir -p bin 
    ./node_modules/.bin/coffee -c -o bin src/server.coffee 

我想運行make,只有把它重新編譯時src/server.coffee發生了變化。然而,重新編譯每次運行make時間:

$ make 
mkdir -p bin 
./node_modules/.bin/coffee -c -o bin src/server.coffee 
$ make 
mkdir -p bin 
./node_modules/.bin/coffee -c -o bin src/server.coffee 

如果我改變我的Makefile中不使用假目標,它按預期工作。新的Makefile:

bin/server.js: src/server.coffee 
    mkdir -p bin 
    ./node_modules/.bin/coffee -c -o bin src/server.coffee 

結果:

$ make 
mkdir -p bin 
./node_modules/.bin/coffee -c -o bin src/server.coffee 
$ make 
make: `bin/server.js' is up to date. 

爲什麼不尊重它與假目標我的依賴呢?我問的原因是因爲在現實中,我不會僅僅將一個文件編譯到一個單獨的文件中,所以我不想跟蹤所有輸出文件的名稱作爲目標。

回答

8

比假目標相反(其中作爲@cmotley指出,正在努力正是因爲它應該),你可能會使用什麼,當你想避免額外的工作是"empty target"

空的目標是假目標的變體;它用於保存您不時要求明確請求的操作的配方。與假目標不同,這個目標文件可以真正存在;但文件的內容並不重要,通常都是空的。

空目標文件的目的是用最後修改時間記錄規則的配方上次執行的時間。它是這樣做的,因爲配方中的一個命令是更新目標文件的觸摸命令。

然而,在這種情況下,實在沒有必要添加額外的空輸出文件 - 你已經有你的CoffeeScript編譯輸出!這適合更典型的Makefile模式,正如你已經在你的問題中演示的那樣。你可以做的就是重構這個方法:

.PHONY: all 
all: bin/server.js 

bin/server.js: src/server.coffee 
    mkdir -p bin 
    ./node_modules/.bin/coffee -c -o bin src/server.coffee 

現在你有兩件事情:一個很好的傳統的「所有」目標是正確的假,但不會做額外的工作。你也是一個更好的位置,以使這更通用的,因此您可以輕鬆地添加多個文件:

.PHONY: all 
all: bin/server.js bin/other1.js bin/other2.js 

bin/%.js: src/%.coffee 
    mkdir -p bin 
    ./node_modules/.bin/coffee -c -o bin $< 
+3

要清楚,一個**空目標**必須是一個文件,真的只是用於它的時間戳嗎?是否還有其他類型的'.PHONY'允許目標規則擁有一個配方體(使用執行的命令)*和*僅在依賴關係需要更新時才運行?它看起來很破碎,因爲根據它是否有配方體,'.PHONY'做了不同的事情。 – jozxyqk

4

需要有一些目標文件與server.coffee文件的修改時間進行比較。既然你沒有一個具體的目標make無法知道輸出是否更新,那麼依賴或不,因此它總是會建立all

+0

啊,謝謝。我沒有意識到這是如何計算需要重新編譯哪些文件。非常有幫助 –

9

按照製作文檔:

The prerequisites of the special target .PHONY are considered 
to be phony targets. When it is time to consider such a target, 
make will run its recipe unconditionally, regardless of whether 
a file with that name exists or what its last-modification time is. 

http://www.gnu.org/software/make/manual/html_node/Special-Targets.html

製作運行的僞目標配方無條件地 - 的先決條件並不重要。

+0

好的,這非常簡單。你知道有什麼好的解決方法來實現不必顯式聲明依賴於一組源文件的輸出文件的目標嗎? –

+0

你可以聲明一些變量來跟蹤源文件和目標文件。例如,SRC = $(通配符./src/*.c)和OBJECTS = $(patsubst%.c,%.o,$(SRC))。然後,$(OBJECTS)可能是您的目標的先決條件。我想這就是你想要做的。 – cmotley

1

正如其他人所說,使着眼於文件的時間戳弄清楚,如果依賴已經改變。

如果您想「模擬」具有依賴關係的假目標,則必須創建一個具有該名稱的實際文件並使用touch命令(在Unix系統上)。

我需要一個解決方案,只在makefile被修改時清除目錄(即編譯器標誌被改變了,所以需要重新編譯目標文件)。

下面是我用什麼(編譯每次運行前)與一個名爲makefile_clean文件:

makefile_clean: makefile 
    @rm '*.o' 
    @sudo touch makefile_clean 

touch命令更新的最後修改的時間戳到當前的時間。