多作业make的依赖排序错误 [英] Dependency ordering error for multi-job make
问题描述
下面的Makefile必须创建(多个)输出目录,并根据上面目录中的输入在这些目录中生成输出.因此,在输入时,dir n 存在,而dir n /file.foo存在.构建必须创建dir n /out/file.bar.
The Makefile below has to create (multiple) output directories, and generate output in those directories, from input in the directory above. So, on entry, dirn exists, and dirn/file.foo exists. The build has to create dirn/out/file.bar.
此Makefile在作为单个作业运行时起作用(请注意,它在$(shell)
中创建了两个必需的源目录和文件).大概是可行的,因为makedirs
是all
的第一个/最左边的先决条件.但是,它不适用于多职位品牌(即make -j4
/任何).
This Makefile works when run as a single job (note that it creates the two required source directories and files in the $(shell)
). It presumably works because makedirs
is the first/leftmost prerequisite for all
. However, it doesn't work for a multi-job make (ie. make -j4
/whatever).
关于如何解决依赖关系以确保在需要输出目录之前就已经建立它们的任何想法?
Any ideas on how to fix the dependencies to ensure that the output directories are made before they're required?
编辑
我应该清楚地表明,我已经尝试了各种只能订购的先决条件解决方案,但是我不能这样做,并且不能保证目标实际上已经重建(订购的目的通常是 prevent 重建,而不是强制执行依赖项排序).如果您有一个面向对象的解决方案,请检查它!谢谢.
I should have made it clear that I have tried various order-only prerequisite solutions, but I couldn't do this and guarantee that the target actually rebuilt (the point of order-only is generally to prevent rebuilding, not enforce dependency ordering). If you have an OO solution, please check it! Thanks.
# 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 $@"
@cp $< $@
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
推荐答案
make $(OUTPUTS)
have an order-only dependency on the directories themselves:
$(OUTDIRS) :
mkdir -p $@
$(OUTPUTS) : | $(OUTDIRS)
这将确保在$(OUTPUTS)
之前创建目录,但是如果目录比目标目录新,则不会导致输出重建(这很重要,因为每次文件被设置时都会设置目录的时间戳记)添加到它...).
This will guarentee that the directories are created before $(OUTPUTS)
, but will not cause the outputs to rebuild if the directories are newer than the targets (which is important, as a directories' time stamp is set each time a file is added to it...).
注意:您还可以在输出配方的目录中添加mkdir -p
,如果每次运行输出规则时该目录都不存在,则会创建目录,但是我更喜欢上面的方法.
Note: you can also add a mkdir -p
in your output recipe's which will create the directory if it's not already there each time you run an output rule, but I prefer the above method.
注2:您还可以在现有的makefile中添加一行:$(OUTPUTS): makedirs
,这将强制在生成任何输出之前运行makedirs
规则,但是我还是更喜欢上面的解决方案:- )
Note2: in your existing makefile you could also just add a line: $(OUTPUTS): makedirs
, which would force the makedirs
rule to be run before any of the outputs are built, but again, I prefer the above solution :-)
---------
---- -----
那么有些事情很奇怪-您使用的是哪个版本的make?我只是运行以下命令:制作目录时请注意sleep 1
,这意味着如果存在并发问题,则肯定会命中:
Something is odd then -- what version of make are you using? I just ran the following: notice the sleep 1
's when making the directories, which means if there was a concurrency issue, it would definitely have hit:
$(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 $@"
sleep 1
mkdir -p $@
@echo "done making $@"
%.bar : ../%.foo
@echo "copying $< to $@"
@cp $< $@
all : outputs
@echo "done $@"
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/out
和dir2/out
,并且直到两个都完成后才运行模式规则.我还验证了在note2中提到的解决方案也可以使用(至少在我的机器上...).
Notice it concurrently builds dir1/out
and dir2/out
, and doesn't run the pattern rules until both are finished. I also verified that the solution I mentioned in note2 also works (at least on my machine...).
在执行模式规则时,可以在模式之外指定依赖项,因此可以执行以下操作:
When doing pattern rules, you can specify dependencies outside of the pattern, so you can do:
foo.o: foo.h
%.o: %.c
recipe here...
,如果foo.h
是较新版本,它将重新构建foo.o
;如果在构建foo.o
之前不存在,请尝试构建foo.h
.
which will rebuild foo.o
if foo.h
is newer, or try to build foo.h
if it doesn't exist before foo.o
is built.
这篇关于多作业make的依赖排序错误的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!