有人可以解释为什么带有子make的make具有不同的并行化行为吗?
我下面有两个例子。在一个例子中,所有目标都在一个Makefile中,在第二个示例中,每个目标都有其自己的文件夹/ makefile,它们使用$(MAKE)
相互调用。
-j
运行它们会产生截然不同的输出。在第一种情况下,所有对顶层依赖项(下面的a.out
)的访问都将同步。在运行依赖于此的任何目标之前,请先等待目标的建立。
在第二种情况下,顶层目标(以下为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'
也许您正在考虑使make的可调用相互通信哪个]正在建立的目标,并且以某种方式互锁,这样就不会有两个子make试图同时建立相同的目标。
这是make无法做的事。所有制造商可以做的就是通知其他子制造商正在构建的其他[个目标,以便确保所调用的总目标(对于-jN
)不超过N个。[如果要确保两个不同的生成文件不尝试构建相同的目标,则可以通过组织生成文件来完成;使您无法做到。
在第二个示例中,您将所有必备组件作为单个目标列出:
all: d.out c.out b.out a.out
[此配方说,“必须先完成目标,因此当您使用all
,d.out
,c.out
和b.out
的构建,然后才能构建a.out
”。这表示先决条件(d.out
,c.out
,b.out
或a.out
)本身之间的相对关系为nothing
-j
运行时,所有这些先决条件都将同时被调用。如果这些都试图建立相同的共享目标,那么它们将相互干扰。如果要确保不会发生这种情况,则必须在makefile中声明前提条件关系,以便对此有所了解。例如,您可以这样做:all: d.out c.out b.out a.out
d.out c.out b.out: a.out
%.out:
$(MAKE) -C $*
.PHONY:all
现在,要构建d.out
,c.out
和b.out
的配方直到要构建a.out
的配方完成后才开始。