make -j在具有和不具有子品牌的情况下的行为都不同

问题描述 投票:0回答:1

有人可以解释为什么带有子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'

makefile gnu-make
1个回答
0
投票

也许您正在考虑使make的可调用相互通信哪个]正在建立的目标,并且以某种方式互锁,这样就不会有两个子make试图同时建立相同的目标。

这是make无法做的事。所有制造商可以做的就是通知其他子制造商正在构建的其他[个目标,以便确保所调用的总目标(对于-jN)不超过N个。[如果要确保两个不同的生成文件不尝试构建相同的目标,则可以通过组织生成文件来完成;使您无法做到。

在第二个示例中,您将所有必备组件作为单个目标列出:

all: d.out c.out b.out a.out

[此配方说,“必须先完成目标alld.outc.outb.out的构建,然后才能构建a.out”。这表示先决条件(d.outc.outb.outa.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.outc.outb.out的配方直到要构建a.out的配方完成后才开始。
© www.soinside.com 2019 - 2024. All rights reserved.