我有一个很大的cmake / c ++ / linux项目:很多小型静态库,一些大型且相互依赖的静态库,一些大型可执行二进制文件。具有调试符号的单个二进制文件为数GB。大约有10个这样的二进制文件(worker,testA,testB,testC ...)。编译通常花费比我们想要的更多的时间,但是我们拥有快速构建的服务器,并且我们使用make -j20
。最糟糕的是链接。单链接大约需要60秒和4GB RAM。但是,当所有最终二进制文件同时链接时(经常发生在修改1个小型子库时,很少重新编译,很多重新链接),10个链接器使用40GB RAM(对于1个开发人员,可能更多),并且使用时间很长。 IO很可能是瓶颈。
我们在1台强大的服务器上拥有许多开发人员,每个人都使用make -j20 -l30
,因此我们不会使CPU过载。但是我们没有限制并发链接器数量的方法。限制服务器上全局工作链接器的数量非常好,但是每次调用也会有所帮助。理想情况下,make -j20 -l30 --concurrent-linkers=2
。有可能吗?
我们使用黄金接头。我们正在分离较小的独立模块,但这将需要很长时间。
答案 0 :(得分:0)
您可以尝试以下方法:
$ cat Makefile
OBJS := foo bar baz...
EXES := qux quux quuz...
.PHONY: all
all: $(OBJS)
$(MAKE) -j $(concurrent-linkers) $(EXES)
$(OBJS): ...
<compile>
$(EXES): ...
<link>
并调用:
$ make -j20 -l30 concurrent-linkers=2
基本上,它将构建分为两个make调用,一个用于编译,一个用于链接,分别具有不同的-j
选项。主要缺点是所有编译必须在第一个链接开始之前完成。更好的解决方案是设计一个简单的链接作业服务器(一个带有flock
并带有标记文件的简单shell脚本)并将其委派给链接作业。但是,如果您可以忍受……
带有虚拟Makefile的演示
$ cat Makefile
OBJS := a b c d e f
EXES := u v w x y z
.PHONY: all
all: $(OBJS)
$(MAKE) -j $(concurrent-linkers) $(EXES)
$(OBJS) $(EXES):
@printf 'building $@...\n' && sleep 2 && printf 'done\n' && touch $@
$ make -j20 -l30 concurrent-linkers=2
building a...
building d...
building b...
building c...
building e...
building f...
done
done
done
done
done
done
make -j 2 u v w x y z
make[1]: warning: -jN forced in submake: disabling jobserver mode.
make[1]: Entering directory 'foobar'
building u...
building v...
done
done
building w...
building x...
done
done
building y...
building z...
done
done
make[1]: Leaving directory 'foobar'
如您所见,所有$(OBJS)
个目标都是并行构建的,而$(EXES)
个目标是一次构建2个(最大)。
编辑:如果您的Makefile是由CMake生成的,则至少有两个选项:
调整您的CMake文件,以便CMake生成两个不同的makefile:一个用于编译,另一个用于链接。然后编写一个简单的包装器makefile,例如:
.PHONY: myAll myCompile
myAll: myCompile
$(MAKE) -j $(concurrent-linkers) -f Makefile.link
myCompile:
$(MAKE) -f Makefile.compilation
说服CMake(如果不是这样)来生成定义两个make变量的makefile:一个(OBJS
)设置为所有目标文件的列表,另一个({{1} })设置为所有可执行文件的列表。然后编写一个简单的包装器makefile,例如:
EXES
如果CMake生成两个假目标,一个针对所有目标文件,另一个针对所有可执行文件,则存在非常相似的解决方案:
.DEFAULT_GOAL := myAll
include CMake.generated.Makefile
.PHONY: myAll
myAll: $(OBJS)
$(MAKE) -j $(concurrent-linkers) $(EXES)