2009-10-14 144 views
47

自從我瞭解了-j我已經用了-j8 blithely。有一天我正在編譯一個地圖集安裝程序,並且失敗。最終,我追蹤到了無序的事情 - 一旦我回到單線程製造,它就運行良好。這讓我緊張。在編寫我自己的make文件時,我需要注意什麼樣的條件,以避免使用make -j做出意想不到的事情?GNU make的-j選項

+4

你確定這是做的錯嗎?編寫正確的makefile很容易出錯。 – 2009-10-14 04:38:35

+1

呃,即使是autotools生成的makefiles也是buggy。嘗試使用-j2或更高版本編譯GCC。 – LiraNuna 2009-10-14 04:46:57

回答

36

我認爲make -j會尊重您在Makefile中指定的依賴關係;即如果您指定objA依賴於objB和objC,則在objB和objC完成之前,make將不會開始在objA上工作。

最有可能你的Makefile不指定操作的必要爲了嚴格夠了,這只是運氣它發生了,你在單線程的情況下工作。

+10

這是正確的。我的代碼庫大約有2000萬行,大部分都是C語言,並且帶有一點C++。它分成數百個組件,其中大約一半使用了make,其中一半使用了jam。我總是使用-j選項進行並行編譯;否則,構建需要數小時。 Jam產生它自己的依賴關係,所以使用它的組件總是成功的。但是使用手工構建的makefile的組件總是會因爲依賴不足而窒息。 – 2009-10-14 05:36:51

+0

我在網上看到很多'-j'指的是你想編譯多少個CPU。我已經在我的8核心機器上運行了一個測試,並且'make'工作到了包括'-j8'(並且超出了所有內核的100%使用率,類似於'-j8')。在每個整數增量處,我會看到另一個核心使用率大約增加了* 100%*。你會說這是一個很好的經驗法則,可以知道要指定爲'-j'的值嗎? – Jacksonkr 2016-04-27 22:01:38

+0

我知道的唯一的經驗法則就是在你的程序上做一個「make clean; time make -jn」,用(n)的各種值,看看每個版本需要多長時間,然後用完成的任何設置最少的時間。有太多變量(CPU速度,RAM速度,RAM大小,硬盤驅動器速度,操作系統進程開銷等)能夠做出有用的概括。 – 2016-04-27 23:34:59

22

總之 - 確保你的依賴是正確和完整的。

如果您使用的是單線程的化妝那麼你可以忽略盲目目標之間隱含的依賴關係。 使用並行make時,不能依賴隱式依賴關係。他們都應該明確。這可能是最常見的陷阱。特別是如果使用.phony目標作爲依賴關係。

This鏈接是一些與並行make的問題的很好的入門。

+0

+1對於良好的鏈接。我現在覺得我也可以信賴make -j,以及在出現問題時如何解決問題。值得一讀。 – 2009-10-14 04:51:28

7

如果你有一個遞歸make,事情可以很容易地中斷。如果你沒有做遞歸構造,那麼只要你的依賴是正確和完整的,你不應該遇到任何問題(除了make中的bug)。請參閱Recursive Make Considered Harmful,以更全面地描述遞歸make的問題。

8

下面是我碰到了,當我開始使用並行構建了問題的一個例子。我有一個名爲「新鮮」的目標,我用它從頭開始重建目標(「新鮮」構建)。在過去,我通過簡單地指出「乾淨」,然後「構建」作爲依賴性來編寫「新鮮」目標。

build: ## builds the default target 
clean: ## removes generated files 
fresh: clean build ## works for -j1 but fails for -j2 

直到我開始使用並行工作正常建立,但與並行編譯,它試圖做到既「乾淨」和「建」並舉。所以我改變了「新鮮」的定義如下,以保證操作的正確順序。

fresh: 
    $(MAKE) clean 
    $(MAKE) build 

這基本上只是正確指定依賴關係的問題。訣竅是並行構建比單線程構建更嚴格。我的示例演示了給定目標的依賴項列表不一定表示執行順序。

+2

遞歸make,yuk !.正確的方法來說,使_please總是乾淨之前,build_當然是'build:clean'。 – bobbogo 2011-04-08 15:53:41

+1

@bobbogo:我不想在構建之前總是乾淨 - 在大多數情況下這是不必要的。我描述的「新鮮」目標基本上只是一個簡單的腳本,它運行「make clean」,然後是「make build」(對於那些很少的時候,我想這樣做)。在這種情況下,我沒有看到任何遞歸執行make的危害。 – nobar 2011-04-10 02:01:01

+2

如何使用條件來保護它:'ifeq($(MAKECMDGOALS),fresh);建立:清潔; endif'(用換行符替換分號)? – eriktous 2011-04-21 10:08:40

1

它是有一個自動化測試來測試所有的make文件的-j選項是個好主意。即使是最好的開發者也會遇到使用make的-j選項的問題。最常見的問題是最簡單的。

myrule: subrule1 subrule2 
    echo done 

subrule1: 
    echo hello 

subrule2: 
    echo world 

在正常製作中,您將看到hello - > world - > done。 隨着make -j 4,你可能會看到世界 - >你好 - >完成

我在哪裏看到這種情況發生最多的是創建輸出目錄。例如:

build: $(DIRS) $(OBJECTS) 
    echo done 

$(DIRS): 
    [email protected] -p [email protected] 

$(OBJECTS): 
    $(CC) ... 
0

只是想我會添加到subsetbrew的答案,因爲它不顯示效果清晰。但是,添加一些睡眠命令會。那麼它適用於Linux。

然後運行make顯示了差異:

  • 使
  • 使-j4

all: toprule1 

toprule1: botrule2 subrule1 subrule2 
    @echo toprule 1 start 
    @sleep 0.01 
    @echo toprule 1 done 

subrule1: botrule1 
    @echo subrule 1 start 
    @sleep 0.08 
    @echo subrule 1 done 

subrule2: botrule1 
    @echo subrule 2 start 
    @sleep 0.05 
    @echo subrule 2 done 

botrule1: 
    @echo botrule 1 start 
    @sleep 0.20 
    @echo "botrule 1 done (good prerequiste in sub)" 

botrule2: 
    @echo "botrule 2 start" 
    @sleep 0.30 
    @echo "botrule 2 done (bad prerequiste in top)"