并发编译,串行链接

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

我有一个很大的cmake / c ++ / linux项目:很多小的静态库,一些大的和相互依赖的静态库,一些大的可执行二进制文件。带调试符号的单个二进制文件是几GB。有大约10个这样的二进制文件(worker,testA,testB,testC ......)。编译通常需要比我们想要的更多的时间,但我们有快速构建服务器,我们使用make -j20。最糟糕的是连接。单链接大约需要60秒和4GB RAM。但是当所有最终的二进制文件同时链接时(通常在修改1个小子库时,很少重新编译,重新链接很多),10个连接器使用40GB RAM(对于1个开发人员,可能会有更多)并且很长时间。 IO很可能是瓶颈。

我们在一个强大的服务器上有很多开发人员,每个人都使用make -j20 -l30,这样我们就不会超载CPU。但我们没有限制并发链接器数量的方法。在服务器上限制全局工作链接器的数量会很棒,但每次调用make也会有所帮助。理想情况下make -j20 -l30 --concurrent-linkers=2。可能吗?

我们使用金链接器。我们正在分离较小的独立模块,但这需要很长时间。

c++ makefile cmake linker
1个回答
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选项。主要缺点是必须在第一个链接开始之前完成所有编译。一个更好的解决方案是设计一个简单的链接作业​​服务器(一个简单的shell脚本,其中包含一些flock和标记文件)并将其委托给链接作业。但如果你能忍受这个......

使用虚拟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生成的,那么至少有两个选项:

  1. 调整CMake文件,使CMake生成两个不同的makefile:一个用于编译,一个用于链接。然后写一个简单的包装器makefile,如: .PHONY: myAll myCompile myAll: myCompile $(MAKE) -j $(concurrent-linkers) -f Makefile.link myCompile: $(MAKE) -f Makefile.compilation
  2. 说服CMake(如果不是这样)生成一个定义两个make变量的makefile:一个(OBJS)设置为所有目标文件的列表,一个(EXES)设置为所有可执行文件的列表。然后写一个简单的包装器makefile,如: .DEFAULT_GOAL := myAll include CMake.generated.Makefile .PHONY: myAll myAll: $(OBJS) $(MAKE) -j $(concurrent-linkers) $(EXES) 如果CMake生成两个虚假目标,一个用于所有目标文件,另一个用于所有可执行文件,则存在一个非常类似的解决方案: .DEFAULT_GOAL := myAll include CMake.generated.Makefile .PHONY: myAll myAll: cmake-target-for-compilation $(MAKE) -j $(concurrent-linkers) cmake-target-for-link
© www.soinside.com 2019 - 2024. All rights reserved.