引言
最近在编译项目代码的时候,发现全量编译一次代码需要十分钟,加了多核编译参数之后,还会出现各种错误,导致编译失败。于是我就想改造下makefile文件,使其能够多核编译,经过改造之后,效果显著,8核编译的情况下,只要1分半,编译速度提高了7倍(为之惊奇)。
多核编译失败的原因
要实现多核编译最重要的一点就是:确定正确的依赖关系。如下Makefile文件:
all: d c b a
a: # 执行一些规则
b: c# 执行一些规则
c: d# 执行一些规则
d:# 执行一些规则
如果直接执行make all
,完全没有问题,他会依照d、c、b、a的顺序去执行各个规则。那我如果使用make all -j4
会怎么样?那么就有可能是a、d先并行执行,然后再c、d顺序去执行。因为依赖关系是c依赖d,那么必须等d执行完,而b又依赖c,就得等c执行完。那么问题来了:如果a实际上要依赖b呢?必须等b执行完产出a执行时所依赖的文件。那么很明显,此时多核编译就会失败。
如何提高多核编译的效率
不要在一个目标下写多个规则或者命令,因为那样会导致他们只能是串行执行,如下:
a:make all -C dir1make all -C dir2make all -C dir3
上述写法就只能串行执行各个命令。改成如下方式:
DIRS = dir1 dir2 dir3
.PHONY: $(DIRS)
all: aa: $(DIRS)$(DIRS): %: make all -C $@
此时如果执行make all -j4
,就可以并发执行三条命令了。
再比如,编译生成某个库文件或者可执行文件时,千万不要写成如下方式:
app: *.cppg++ -o $@ $^ -I./
这种情况下显然效率极低,即不利于多核编译,也不利于增量编译。正确写法应该如下:
source=$(wildcard ./*.cpp)
obj=$(patsubst %.cpp, %.o, $(source))OBJS: $(obj)
$(obj) : %.o : %.cppg++ -c $< -o $@ -I./app: $(obj)g++ $^ -o $@
多核编译的情况下,会并行编译多个cpp文件,从而提高编译效率,并且增量编译也只会编译有修改的cpp文件。