Visual Studio并行编译失效的原因

对于大型C++项目来说,并行编译开关/MP是必不可少的编译器选项,它能显著提高项目的编译速度。但是,当我在自己所在的项目中开启了这个选项之后,发现没有什么效果,只有少数文件可以并行编译,大多数文件仍然是串行编译的,编译时CPU使用率只有30%~40%。这个问题困扰了我们项目组很久。

最近,我在Visual Studio的社区里发现了一个反馈,内容是说当显式指定了.obj文件的输出文件名时,/MP选项会失效。而Visual Studio的官方团队也解释说这确实是编译器的缺陷,因为编译器是以传递给编译器的参数来决定编译单元是否能并行编译的,只有编译参数一模一样的编译单元才能够并行。

于是我立即查看我们工程的设置,发现.obj文件的输出文件名确实被修改了,如下图所示:

这个值的意思是,按照源文件的相对路径来输出.obj文件。默认情况下,工程里所有源文件编译后的.obj文件都会输出到同一个目录中,一旦在不同目录下存在名字相同的源文件,它们输出的.obj文件就会相互覆盖,在大型工程里这个问题很容易遇到。所以,为了避免这个问题,我们在这个设置项加上了%(RelativeDir)

这样一来,虽然解决了名字冲突的问题,却带来了并行编译失效的问题。由于%(RelativeDir)的值是随着源文件所在目录而改变的,所以不同目录下的源文件其编译参数都不一样,它们就无法并行编译了。只有同一个目录下的源文件才能并行编译。

去掉了这个设置之后,/MP选项终于恢复了该有的效率,在编译时CPU使用率一直在90%以上,整个工程的编译时间缩短了一半。当然,代价是必须逐个处理名字冲突的源文件,要么改名字,要么改.obj文件的输出路径。

在上述的反馈中,Visual Studio团队已经在着手修复这个问题,希望在不久的将来能恢复使用%(RelativeDir)