2017-06-06 28 views
1

下面的Makefile必須創建(多個)輸出目錄,並在這些目錄中生成輸出,從上面目錄中的輸入。因此,在輸入時,目錄n存在,並且目錄n /file.foo存在。構建必須創建目錄n /out/file.bar。多作業的依賴性排序錯誤

這個Makefile在作爲單個作業運行時工作(請注意,它會在$(shell)中創建兩個必需的源目錄和文件)。推測可能是因爲makedirsall的第一個/最左邊的先決條件。但是,它不適用於多工作制(即make -j4 /無)。

有關如何解決依賴性以確保輸出目錄在需要之前生成的任何想法?

編輯

我應該明確表示,我曾嘗試過各種順序,唯一的先決條件的解決方案,但我不能做到這一點,並保證目標實際上重建(順序僅是點一般到阻止重建,不強制依賴性排序)。如果您有OO解決方案,請檢查它!謝謝。

# expected output: 
# made directories 
# copying dir1/out/../file.foo to dir1/out/file.bar 
# copying dir2/out/../file.foo to dir2/out/file.bar 
# created all output files 
# done 

    $(shell mkdir dir1 >& /dev/null; touch dir1/file.foo; \ 
      mkdir dir2 >& /dev/null; touch dir2/file.foo) 

    OUTDIRS = dir1/out dir2/out 
    OUTPUTS = dir1/out/file.bar dir2/out/file.bar 

    .DEFAULT_GOAL := all 

    .PHONY: makedirs $(OUTDIRS) 

    .SUFFIXES: .foo .bar 

    %.bar : ../%.foo 
     @echo "copying $< to [email protected]" 
     @cp $< [email protected] 

    all : makedirs outputs 
     @echo "done" 

    outputs : $(OUTPUTS) 
     @echo "created all output files" 

    makedirs : $(OUTDIRS) 
     @mkdir -p $(OUTDIRS) 
     @echo "made directories" 

    clean : 
     @rm -rf dir1 dir2 

回答

2

使$(OUTPUTS)對目錄本身的order-only依賴性:

$(OUTDIRS) : 
     mkdir -p [email protected] 

$(OUTPUTS) : | $(OUTDIRS) 

這將機制保障,該目錄$(OUTPUTS)之前創建的,但不會導致輸出重建如果目錄是比新目標(這很重要,因爲每次將文件添加到目錄時都會設置目錄的時間戳)。

注意:您也可以在輸出配方中添加mkdir -p,該配置會在每次運行輸出規則時都創建該目錄,但我更喜歡上述方法。

注2:在現有makefile,你也可以只添加一行:$(OUTPUTS): makedirs,這將迫使makedirs規則任何輸出都內置前運行,但同樣,我更喜歡:-)

上述方案

----編輯:-----

東西是奇數,那麼 - 您使用的是什麼版本的make?我只是跑了以下內容:製作目錄,如果有一個併發的問題,這意味着,當注意到sleep 1的,它肯定會擊中:

$(shell mkdir dir1 >& /dev/null; touch dir1/file.foo; \ 
     mkdir dir2 >& /dev/null; touch dir2/file.foo) 


OUTDIRS = dir1/out dir2/out 
OUTPUTS = dir1/out/file.bar dir2/out/file.bar 

.DEFAULT_GOAL := all 

$(OUTPUTS) : | $(OUTDIRS) 

$(OUTDIRS) : 
     @echo "making [email protected]" 
     sleep 1 
     mkdir -p [email protected] 
     @echo "done making [email protected]" 


%.bar : ../%.foo 
     @echo "copying $< to [email protected]" 
     @cp $< [email protected] 

all : outputs 
     @echo "done [email protected]" 

outputs : $(OUTPUTS) 
     @echo "created all output files" 

clean : 
     @rm -rf dir1 dir2 

輸出功率爲:

~/sandbox/tmp20> make -j -f Makefile2 
making dir1/out 
making dir2/out 
sleep 1 
sleep 1 
mkdir -p dir1/out 
mkdir -p dir2/out 
done making dir1/out 
done making dir2/out 
copying dir1/out/../file.foo to dir1/out/file.bar 
copying dir2/out/../file.foo to dir2/out/file.bar 
created all output files 
done all 

注意它同時生成dir1/outdir2/out,並且在兩者都完成之前不運行模式規則。我也證實了我在note2中提到的解決方案也可行(至少在我的機器上......)。

在做模式的規則,你可以在模式之外指定依賴,所以你可以做:

foo.o: foo.h 

%.o: %.c 
    recipe here... 

這將重建foo.o如果foo.h是新的,或嘗試建立foo.h,如果它不存在之前建立了foo.o

+0

謝謝,但是僅依賴訂單的問題在於它不能保證目標將被重建 - 只有目錄纔會被創建。我在原始的Makefile中無法獲得可用的OOD,但是我還沒有嘗試過這個簡化版本 - 是否嘗試過對上述文件進行特定更改? – EML

+0

注意:由於模式規則,我無法做到這一點。如果目錄尚不存在,則模式中的詞幹匹配失敗(請參閱'..')。似乎沒有任何解決方法(無論如何我都能找到)。 – EML

+0

On注2:我不認爲這會起作用,因爲'$(OUTPUTS)'必須由模式規則構建,而不是新規則。我嘗試了各種各樣的組合,並將'makedirs'放入原始Makefile中的模式規則中,但沒有一個能夠工作。 – EML