我正在开发一个基于Qt的大型项目,即使在6核机器上也需要花费几个小时进行编译。
原因是当我运行make
时,只有一个核心编译源:其他核心仍处于空闲状态。
解决方案是使用make
选项(类似-j
)执行make -j6
,使用我机器的所有6个内核。
这个问题是make
不会在递归中产生。
例如:
我有4个模块,A,B,C和D: - D取决于A,B和C. - B取决于A. - C仅依赖于系统库。 - A仅取决于系统库。
qmake
应用程序为上述每个模块生成一个Makefile,为一个Makefile生成一个Makefile来编译所有模块。
当我运行make -j6
时,6个作业开始编译所有模块,而不是逐个编译。这种行为是有问题的,因为当模块D必须与其他模块链接时,那些模块可能没有准备好,抛出not found
错误。
是否可以使用make
选项更改此行为?这可能是软件工程的问题(模块没有很好地预测)?
答案 0 :(得分:1)
尝试使用makepp进行构建。这将通过将sub-make的目标传回主进程来解开递归(参见Recursive Make Considered Harmful),就好像makefile从一开始就设计得很干净。
然后它将执行其正常的依赖项分析,而不是在目录级别上进行抽象,而是通过深入查看整个目录树中的实际每个文件依赖项。因此,它可以并行化安全可能的最大值。
实际上我不知道为什么cmake会生成makefile ...他们所做的只是调用cmake来做make后面的所有事情。因此,makepp对cmake有一些特殊的处理,以避免无休止的递归,因为依赖会产生监督。现在qmake并不完全是cmake,我很高兴听到它是否足够接近工作!
答案 1 :(得分:0)
听起来你错过了递归make调用之间的依赖关系。你没有向我们展示调用递归make的toplevel makefile,但我想它看起来像这样:
all: A B C D
A B C D:
$(MAKE) -C $@
您可以通过在递归make之间添加必要的依赖项来解决此问题:
all: A B C D
A B C D:
$(MAKE) -C $@
B: A
D: A B C
这个策略会为你提供正确的并行构建,虽然代价是某些性能 - 但是很多工作可以在这些子制作之间安全地并行化,并且很遗憾地序列化所有它只是为了每个中的一个或两个命令真正必须序列化。一个更好的解决方案是使用非递归make,这需要对makefile进行更严格的重构,或者使用Electric Make,这可以为你解决这个问题而不需要你根本改变makefile(甚至不添加额外的依赖项)。我已经在我的博客上写过关于Electric Make fixes recursive make的内容。
(免责声明:我是Electric Make的设计师)
答案 2 :(得分:0)
我终于发现了如何使用qmake
自动执行此操作。
它不会更简单:只需将CONFIG += ordered
添加到.pro
文件中,一切都会正常工作。有关此标志的更多信息,请访问qmake Variable Reference。
请注意,它仅适用于subdirs
项目模板,但这不是问题,因为当您在不同的二进制文件之间存在依赖关系时,并行编译只是一个问题。
示例:
# ABC.pro
TEMPLATE = subdirs
CONFIG += ordered
SUBDIRS += \
A \
B \
C