2017-06-06 9 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