2017-09-29 111 views
2

GNU化妝允許1)並行執行和2)指定在同一調用幾個目標:如何處理多個並行make調用命令的目標

make -j4 clean all 

但是,作爲GNU使並行化的目標,一些競爭條件可能發生。插圖:

$ cat Makefile 
clean: 
    @sleep 1 && rm -f foo 

all: foo 
    @sleep 2 && cat foo 

foo: 
    @echo '[email protected]' > [email protected] 
$ make -j4 clean ; make -j4 all 
foo 
$ make -j4 clean all 
cat: foo: No such file or directory 
Makefile:5: recipe for target 'all' failed 
make: *** [all] Error 1 

有沒有一種很好的方式來強制目標之間的順序,但仍然受益於每個目標的並行加速?在上面的例子中,爲了避免競爭條件,等待cleanall開始之前完成將是很好的。

如圖所示,單獨建立調用按預期工作,但這不是100%滿意:

  1. 有些目標可以同時調用,有些則不能。因此完全禁止多個目標可以被認爲是太嚴格。但是識別所有有效和無效的組合是棘手和容易出錯的。
  2. 爲了完全避免這個問題,可以警告所有這樣的Makefile的潛在用戶在並行模式下不支持多個目標調用,但是這個警告將不可避免地被某些用戶忽略。
  3. 比賽條件並不總是會導致錯誤。有些顯然可以無縫工作,但會產生錯誤的結果。
+0

也許你可以直接調用'make clean && make all -j4'?或者有一個特殊的'rebuild'目標,它的順序是'clean'和'all'作爲先決條件。我不知道其他解決方案。 – Tim

+0

@TimF不幸的是,你的'rebuild'目標不能解決問題。在我的簡單示例中,調用'make -j4 rebuild'時仍然出現錯誤。而單獨的make調用是一個選項(如我原來的問題所示),但我正在尋找一些東西,比指示我的Makefiles的任何潛在用戶不支持多個目標調用... –

+0

那麼我會好奇的看看是否有人有另一種解決方案,因爲我嘗試了我的構建設置和我有同樣的問題。但我真的懷疑有一個解決方案。順便說一下,我也將Makefile分發給一組用戶,他們總是(直觀地)用兩個單獨的命令來創建'clean'和'all',所以在我的情況下這不是問題。 – Tim

回答

1

恕我直言,這似乎是根源於在編程語言(在這種情況下,殼)的問題,我們能夠制定的依賴關係,它們的性質基本上不同於那些可以處理。在您的示例中,clean不存在依賴關係foo,而all具有反向依賴關係。如果你同時使兩個目標都活躍起來,這似乎超過了make的理論基礎 - 我不知道是否存在能夠處理這種關係的合理理論。所有我能想出的是明確的表述:

.PHONY: all clean 

clean: 
    @sleep 1 
    rm -f foo 

all: foo $(filter clean,$(MAKECMDGOALS)) 
    @sleep 2 
    cat foo 

foo: $(filter clean,$(MAKECMDGOALS)) 
    @echo Creating [email protected] 
    @echo '[email protected]' > [email protected] 

我認爲這確實是一個有趣的問題。

+0

是的,我也嘗試使用'MAKECMDGOALS'。但是你的使用看起來比我的好。感謝這個好主意。我們甚至可以用一個額外的規則來改進它:'all foo:$(filter clean,$(MAKECMDGOALS))',其他所有其他規則不變。 –

+0

不錯的黑客,太糟糕了,它不依賴於本地的GNU make功能,因爲它變得依賴於操作系統(和在Unix環境中原生等待2ms一樣簡單的事情成爲Windows環境中的痛苦) – Tim

+0

@TimF uhh ..我想你錯過了我和雷諾茲的觀點。這個劇本就像是依賴性矛盾問題的示範者。 「sleep」僅僅是「任何處理導致評估矛盾依賴樹的並行線程之間的競爭條件」的佔位符。 – Vroomfondel

0

我發現了一種解決方法(但我不是100%確信它是最好的解決方案,並且沒有隱藏的缺點)。我們的想法是使用MAKECMDGOALS GNU make變量和條件語句來強制的多重目標的系列化:

ifeq ($(words $(MAKECMDGOALS)),1) 
.PHONY: all clean 

clean: 
    @sleep 1 && rm -f foo 

all: foo 
    @sleep 2 && cat foo 

foo: 
    @echo '[email protected]' > [email protected] 
else 
.NOTPARALLEL: 

%: 
    @$(MAKE) [email protected] 
endif 

當然,有條件的情況可能會更復雜,比如,舉例來說,如果一個測試目標匹配clean ...

相關問題