并行makefile执行会导致库被构建两次

时间:2014-10-22 15:33:16

标签: makefile

我有两个二进制文件(bin_a,bin_b)和这两个二进制文件共享的库(lib)。 二进制文件取决于库。

main makefile:

include makeenv.mk

all: $(BIN_A) $(BIN_B)

.PHONY: clean
clean:
    $(MAKE) -C lib clean
    $(MAKE) -C bin_a clean
    $(MAKE) -C bin_b clean

makeenv.mk:

BIN_A=$(ROOT)/bin_a/bin_a
BIN_B=$(ROOT)/bin_b/bin_b
LIB=$(ROOT)/lib/liblib.so

first_target: all

$(BIN_A):
    $(MAKE) -C $(ROOT)/bin_a

$(BIN_B):
    $(MAKE) -C $(ROOT)/bin_b

$(LIB):
    $(MAKE) -C $(ROOT)/lib

bin_a /生成文件:

include ../makeenv.mk

all: bin_a

bin_a: $(LIB)
    gcc -I $(ROOT) -L $(ROOT)/lib -l lib -o $@ bin_a.c

.PHONY: clean
clean:
    rm -f bin_a

bin_b /生成文件:

include ../makeenv.mk

all: bin_b

bin_b: $(LIB)
    gcc -I $(ROOT) -L $(ROOT)/lib -l lib -o $@ bin_b.c

.PHONY: clean
clean:
    rm -f bin_b

LIB /生成文件:

include ../makeenv.mk

TARGET=liblib.so

all: $(TARGET)

$(TARGET): lib.c
    gcc -shared -fPIC -o $@ $^
    sleep 5

.PHONY: clean
clean:
    rm -f liblib.so

如果我输入make,那么一切都很好:

make -C /tmp/mak/bin_a
make[1]: Entering directory `/tmp/mak/bin_a'
make -C /tmp/mak/lib
make[2]: Entering directory `/tmp/mak/lib'
gcc -shared -fPIC -o liblib.so lib.c
sleep 5
make[2]: Leaving directory `/tmp/mak/lib'
gcc -I /tmp/mak -L /tmp/mak/lib -l lib -o bin_a bin_a.c
make[1]: Leaving directory `/tmp/mak/bin_a'
make -C /tmp/mak/bin_b
make[1]: Entering directory `/tmp/mak/bin_b'
gcc -I /tmp/mak -L /tmp/mak/lib -l lib -o bin_b bin_b.c
make[1]: Leaving directory `/tmp/mak/bin_b'

但是,如果我想并行构建它,那么库就构建了两次:

make -C /tmp/mak/bin_a
make -C /tmp/mak/bin_b
make[1]: Entering directory `/tmp/mak/bin_a'
make -C /tmp/mak/lib
make[1]: Entering directory `/tmp/mak/bin_b'
make -C /tmp/mak/lib
make[2]: Entering directory `/tmp/mak/lib'
gcc -shared -fPIC -o liblib.so lib.c
make[2]: Entering directory `/tmp/mak/lib'
gcc -shared -fPIC -o liblib.so lib.c
sleep 5
sleep 5
make[2]: Leaving directory `/tmp/mak/lib'
make[2]: Leaving directory `/tmp/mak/lib'
gcc -I /tmp/mak -L /tmp/mak/lib -l lib -o bin_a bin_a.c
gcc -I /tmp/mak -L /tmp/mak/lib -l lib -o bin_b bin_b.c
make[1]: Leaving directory `/tmp/mak/bin_a'
make[1]: Leaving directory `/tmp/mak/bin_b'

问题是:为什么?

如何修复这些makefile以使并行运行?

谢谢!

2 个答案:

答案 0 :(得分:1)

toplevel makefile并不知道子makefile会转到每个构建$(LIB),而子makefile自然不会知道其他makefile正在做什么。

所以你有一个竞争条件,他们都发现$(LIB)需要重建,然后都安排建设。这是Recursive Make Considered Harmful (pdf)论文中的主要论据之一。

makeenv.mk更改为:

BIN_A=$(ROOT)/bin_a/bin_a
BIN_B=$(ROOT)/bin_b/bin_b
LIB=$(ROOT)/lib/liblib.so

first_target: all

$(BIN_A): $(LIB)
    $(MAKE) -C $(ROOT)/bin_a

$(BIN_B): $(LIB)
    $(MAKE) -C $(ROOT)/bin_b

$(LIB):
    $(MAKE) -C $(ROOT)/lib
在这种情况下,

可能足以让你得到你想要的东西(但我必须尝试并仔细检查先决条件列表以确定)。

或者,您可以阅读我之前列出的论文,并停止使用递归制作这类事情。

答案 1 :(得分:0)

subdirs=lib bin_a bin_b
.PHONY : all $(subdirs)

bin_a bin_b : lib

$(subdirs) : 
    $(MAKE) -C $@ $(MAKECMDGOALS)

这对我有用。 或者我试过

all : makeall

bin_a bin_b : lib

makeall :
   $(MAKE) -C lib
   $(MAKE) -C bin_a 
   $(MAKE) -C bin_b 
   $(MAKE) -C moredirs 

在我的手中,困难在于并行并使制作过程保持定义的顺序。如果你有一个大型项目,你迫不及待地想做单线程make。你几乎要做-j 24。 如果有任何改进,请告诉我。