【发布时间】:2019-11-24 21:36:20
【问题描述】:
有人能解释一下为什么 make 和 sub-make 有不同的并行化行为吗?
下面有两个例子。一方面,所有目标都在一个 Makefile 中,如在第二个示例中,每个目标都有自己的文件夹/makefile,并且它们使用 $(MAKE) 相互调用。
使用-j 运行它们会产生截然不同的输出。在第一种情况下,对顶级依赖项(下面的a.out)的所有访问都是同步的。 Make 在运行任何依赖它的目标之前等待目标构建。
在第二种情况下,顶级目标(下面的a.out)受到并发访问。除非我们使用自己的同步技术来克服这个问题,否则这会给我们带来严重的问题。
示例 1:
jesaremi@u16-3:~/maketest$ cat Makefile
.ONESHELL:
all: d.out b.out c.out a.out
a.out: CALLER ?= self
a.out:
@
echo entering $@ "(called by $(CALLER))"
sleep 10
echo exiting $@
b.out: a.out
@
echo entering $@
sleep 1
echo exiting $@
c.out: a.out
@
echo entering $@
sleep 1
echo exiting $@
d.out: a.out
@
echo entering $@
sleep 1
echo exiting $@
jesaremi@u16-3:~/maketest$ make
entering a.out (called by self)
exiting a.out
entering d.out
exiting d.out
entering b.out
exiting b.out
entering c.out
exiting c.out
jesaremi@u16-3:~/maketest$ make -j
entering a.out (called by self)
exiting a.out
entering d.out
entering c.out
entering b.out
exiting c.out
exiting d.out
exiting b.out
示例 2(使用子制作):
jesaremi@js-u16-1:~/maketest$ cat */Makefile
---------- a/Makefile -------------
.ONESHELL:
a.out: CALLER ?= self
a.out:
@
echo entering $@ "(called by $(CALLER))"
sleep 10
echo exiting $@
---------- b/Makefile -------------
.ONESHELL:
export CALLER:=b
a.out:
$(MAKE) -C ../a
b.out: a.out
@
echo entering $@
sleep 1
echo exiting $@
---------- c/Makefile -------------
.ONESHELL:
export CALLER:=c
a.out:
$(MAKE) -C ../a
c.out: a.out
@
echo entering $@
sleep 1
echo exiting $@
---------- d/Makefile -------------
.ONESHELL:
export CALLER:=d
a.out:
$(MAKE) -C ../a
d.out: a.out
@
echo entering $@
sleep 1
echo exiting $@
jesaremi@js-u16-1:~/maketest$ cat Makefile
all: d.out c.out b.out a.out
%.out:
$(MAKE) -C $*
.PHONY:all
jesaremi@js-u16-1:~/maketest$ make
make -C d
make[1]: Entering directory '/home/jesaremi/maketest/d'
make -C ../a
make[2]: Entering directory '/home/jesaremi/maketest/a'
entering a.out (called by d)
exiting a.out
make[2]: Leaving directory '/home/jesaremi/maketest/a'
make[1]: Leaving directory '/home/jesaremi/maketest/d'
make -C c
make[1]: Entering directory '/home/jesaremi/maketest/c'
make -C ../a
make[2]: Entering directory '/home/jesaremi/maketest/a'
entering a.out (called by c)
exiting a.out
make[2]: Leaving directory '/home/jesaremi/maketest/a'
make[1]: Leaving directory '/home/jesaremi/maketest/c'
make -C b
make[1]: Entering directory '/home/jesaremi/maketest/b'
make -C ../a
make[2]: Entering directory '/home/jesaremi/maketest/a'
entering a.out (called by b)
exiting a.out
make[2]: Leaving directory '/home/jesaremi/maketest/a'
make[1]: Leaving directory '/home/jesaremi/maketest/b'
make -C a
make[1]: Entering directory '/home/jesaremi/maketest/a'
entering a.out (called by self)
exiting a.out
make[1]: Leaving directory '/home/jesaremi/maketest/a'
jesaremi@js-u16-1:~/maketest$ make -j
make -C d
make -C c
make -C b
make -C a
make[1]: Entering directory '/home/jesaremi/maketest/d'
make -C ../a
make[1]: Entering directory '/home/jesaremi/maketest/c'
make -C ../a
make[1]: Entering directory '/home/jesaremi/maketest/b'
make -C ../a
make[2]: Entering directory '/home/jesaremi/maketest/a'
make[1]: Entering directory '/home/jesaremi/maketest/a'
entering a.out (called by self)
make[2]: Entering directory '/home/jesaremi/maketest/a'
entering a.out (called by c)
make[2]: Entering directory '/home/jesaremi/maketest/a'
entering a.out (called by d)
entering a.out (called by b)
exiting a.out
make[1]: Leaving directory '/home/jesaremi/maketest/a'
exiting a.out
make[2]: Leaving directory '/home/jesaremi/maketest/a'
exiting a.out
make[1]: Leaving directory '/home/jesaremi/maketest/c'
make[2]: Leaving directory '/home/jesaremi/maketest/a'
make[1]: Leaving directory '/home/jesaremi/maketest/d'
exiting a.out
make[2]: Leaving directory '/home/jesaremi/maketest/a'
make[1]: Leaving directory '/home/jesaremi/maketest/b'
【问题讨论】:
-
我们无能为力,因为您遗漏了最关键的信息:第二个示例中的根级 makefile 的内容。破译
cat */Makefile的输出也很困难,因为我们不知道一个makefile 在哪里结束,下一个从哪里开始。 -
我认为这与递归使用
make没有任何关系。发生这种情况是因为在第二种情况下,每个配方都会在输出中打印几行。 -
@MadScientist 我添加了缺失的信息
-
第二个例子中的@HolyBlackCat 注意第一次执行(无-j)和第二次执行(有-j)的区别。您应该能够清楚地看到目标 a.out 的配方打印交织在一起,因为它同时调用了多次
-
如果您想要多个 makefile 仅用于组织目的,请使用
include,并将它们命名为something.make而不是Makefile