2014-07-18 23 views
14

我在訂單唯一的先決條件中遇到問題。這些首先根本不執行。我錯誤理解訂單唯一的先決條件的工作方式嗎?只有訂單的先決條件在GNU make中不能正常工作?

下面讓腳本:

.PHONY: mefirst mefirst2 

mefirst: 
    @echo "I'm first!" 

mefirst2: 
    @echo "I'm first too!" 

normaltarget: normaltarget2 | mefirst2 
    @echo "normaltarget done" 

normaltarget2: a b c 
    @echo "normaltarget2 done" 

helloworld: normaltarget | mefirst 
    @echo "helloworld done" 

.DEFAULT_GOAL := go 
go: helloworld 
    @echo "go done" 

a: 
    @echo a 
b: 
    @echo b 
c: 
    @echo c 

...打印出以下幾點:

a 
b 
c 
normaltarget2 done 
I'm first too! 
normaltarget done 
I'm first! 
helloworld done 
go done 

...什麼,而不是我所期望的:

I'm first! 
I'm first too! 
a 
b 
c 
normaltarget2 done 
normaltarget done 
helloworld done 
go done 

上午什麼我做錯了?

回答

33

上午我錯誤理解方式的訂單隻有正常工作的先決條件?

是的,那是什麼樣子。 「只爲了」在有些混亂

名稱。 |背後的先決條件被稱爲「僅限訂單的先決條件」,不是因爲它們改變了單個目標的先決條件列表中的配方執行順序,而是因爲它們唯一的目的是在某些目標之前創建了某些目標,如引導程序。正如下面用戶bobbogo精確解釋的那樣( - 感謝糾正):如果make決定重建目標的先決條件,它將運行該先決條件的配方。現在,對於一個普通的先決條件,這個更新意味着目標已經過時,並且make將不得不運行目標的配方。另一方面,對於僅限訂單的先決條件,make不會將目標標記爲需要更新。

例如參見其中創建該目錄中的對象之前的目錄應創建一個用例的部分Types of Prerequisites

拿這個例子makefile

a: b 
    touch a 

b: c 
    touch b 

c: 
    touch c 

x: | y 
    touch x 

y: | z 
    touch y 

z: 
    touch z 

正如你所看到的,bcab正常的先決條件,而yz是順序只是xy先決條件。從一張白紙開始,他們看起來是一樣的:

:~$ make a 
touch c 
touch b 
touch a 
:~$ make x 
touch z 
touch y 
touch x 
:~$ make a 
make: `a' is up to date. 
:~$ make x 
make: `x' is up to date. 

但是,如果我們現在手動「更新」在鏈(cz)結束的先決條件,我們看到了差距:

:~$ touch c 
:~$ make a 
touch b 
touch a 
:~$ touch z 
:~$ make x 
make: `x' is up to date. 

這顯示瞭如何存在的訂單隻有先決條件,不壞的任何目標,不論其時間戳的。刪除訂單唯一的目標不會導致雖然重建(但只有重建的那些丟失的文件):

:~$ rm c 
:~$ make a 
touch c 
touch b 
touch a 
:~$ rm z 
:~$ make x 
touch z 

有了這樣說,以更改你的食譜的運行順序正確的方法是通過修正依賴在目標之間。例如,如果你想mefirst待建a之前,那麼你需要做mefirst的先決條件爲a,如

a: mefirst 
    @echo a 

這是不可能給整個解決你的問題,因爲你沒有說明詳細說明您希望食譜運行的順序。


有一個快捷方式來回答你的答案,這不是解決方案,但仍然有趣的知道。雖然沒有記錄,但似乎單個目標的先決條件按其出現的順序進行處理。 |符號不會改變這一點。在您簡單的情況下,可以利用這一點來實現,你正在尋找的輸出:

normaltarget: mefirst2 normaltarget2 
    @echo "normaltarget done" 

helloworld: mefirst normaltarget 
    @echo "helloworld done" 

然而,正如指出的自己,這種「解決方案」的假期,因爲-j標誌用於並行運行配方。另外,正如用戶bobbogo指出的,依靠這種訂購機制是不好的做法。引入新的依賴可能會干擾排序。所以不要這樣做:-)

+1

謝謝你澄清Reinier。我首先嚐試了一下,但是在使用-j標誌和嚴格的並行性時它不起作用。 「myfirst」的先決條件將在下面的同時執行,因爲它們都是平行的,並且嘗試製作所有先決條件。 –

+1

在這種情況下,如果你真的需要在y之前(重新)製作x,即使在平行的情況下,也必須使x本身成爲y的先決條件,而不是將它們放在同一行上。這正是前提條件列表的要求:指出哪個目標取決於哪個目標(並因此首先需要(重新)制定哪個目標)。但是,您的問題不夠詳細,無法爲您的案例提供確切的解決方案,因爲不清楚您的不同目標的依賴關係應該是什麼。有很多方法可以實現你的輸出。 –

+3

對不起,但在許多重要方面,這個答案是錯誤的**。正如@喬治指出的那樣,構建的順序不是從左到右。如果你的makefile依賴於這個,那麼它就會被破壞。上述建議的錯誤是錯誤的。而且,'|'之後的前提條件是以完全正常的方式構建的。如果他們不是最新的,那麼他們的食譜將被運行。關鍵的區別在於,在這樣的更新之後,_make_將不會繼續運行原始目標的配方。這與普通的pre-reqs形成鮮明對比 - 如果這些需要更新,那意味着目標已過時。 – bobbogo