MSVC10 / MP在项目中的文件夹之间不构建多核

时间:2011-08-11 22:46:04

标签: c++ visual-studio-2010 visual-c++ msbuild cl.exe

我希望有人指出我们遇到的问题或解决方法。

使用/ MP编译项目时,似乎只同时编译同一文件夹中的文件。我使用进程资源管理器来刷命令行并确认行为。

项目过滤器似乎对并发编译的内容没有任何影响。

磁盘上的项目结构:

Folder\
  project.vcxproj  
  source\  
    foo.cpp  
    foo1.cpp  
  other_folder\  
    bar.cpp
    bar1.cpp
    bar3.cpp

初始流程树:

MSBuild.exe
  cl.exe  ( passed: source\foo.cpp source\foo1.cpp )
    cl.exe  ( passed: source\foo.cpp )
    cl.exe  ( passed: source\foo1.cpp )

完成cl.exe的2个子实例后,父关闭并显示以下进程树:

MSBuild.exe
  cl.exe  ( passed: other_folder\bar.cpp other_folder\bar1.cpp other_folder\bar2.cpp )
    cl.exe  ( passed: other_folder\bar.cpp )
    cl.exe  ( passed: other_folder\bar1.cpp )
    cl.exe  ( passed: other_folder\bar2.cpp )

我们的源代码很好地组织在许多级别的嵌套文件夹中,这些文件夹与磁盘上的标题布局相匹配 - 我不愿意放弃使用/ MP。

4 个答案:

答案 0 :(得分:3)

在“对象文件名”(在vcxproj XML中,/ FL在CL.exe命令行上)项目中使用%(RelativeDir)会导致msbuild在每个目录的基础上将cpp文件批处理为cl.exe。这会对使用/ MP获得的好处产生重大影响。

请注意,如果您的项目对目标文件使用%(RelativeDir),则配置可能会尝试避免来自不同文件夹中具有相同名称的cpp文件的.obj文件冲突。

/ Fo命令行参数通常是编译器将obj文件转储到的文件夹 - 只传递了一个,因此给定目录的所有cpp文件一次只能传递给CL.exe。

这很痛苦 - 但我很高兴有理由和解决方案。希望它有所帮助。


<强>更新

队友发现,无论何时将MSBuild参数发送到CL.exe,它似乎都会破坏或严重限制/ MP。这很可能是因为/ MP能够很好地工作,顶级CL.exe需要有一堆cpp文件。

我们的解决方案是不使用'Object File Name'的任何msbuild参数(我认为它的%params%)。这要求我们重命名一些cpp文件,以免它们发生冲突。

希望在VS2012或VS2013中发生了变化。

答案 1 :(得分:1)

According it MSDN,当有一个线程处理它们时,应该编译文件,它同时不保证文件的编译顺序:

  

源文件的编译顺序可能与它们的顺序不同   出现在命令行中。虽然编译器创建了一组   包含编译器副本的进程,即操作系统   每个进程执行时的计划。因此,你不能   保证源文件将在特定的情况下编译   顺序。

     

当进程可用于编译时,将编译源文件。   如果文件多于进程,则第一组文件为   由可用流程编译。其余文件将被处理   当进程完成处理前一个文件并且可用时   处理剩下的一个文件。

它还声明创建的进程数将受命令行中线程和文件数量的限制:

  

该值是您在命令行上指定的源文件数量中的较小者

将这些与事物相结合,我们可以看到编译器以递增方式处理编译(文件方式),以便它可以正确地将工作分配给子项,它按文件夹处理此文件夹。

如果你生成了一个自定义make文件,你可以解决这个问题,你应该能够同时处理多个文件夹(或尝试使用MSBUILD.exe工具)。 / p>

答案 2 :(得分:1)

我在这里用一种避免.obj破坏冲突的新方法解决了这个问题

https://stackoverflow.com/a/26935613/4253427

考虑到上述情况,我可以详细说明&#34;无论何时将MSBuild参数发送到CL.exe,它似乎都会破坏或严重限制/ MP&#34;。 / MP一次调用一个CL.exe。当你&#34;发送一个msbuild参数&#34;你实际做的是使用为每个源文件定制的命令行创建多个CL.exe调用。这些都不能批量处理。上面链接的解决方案试图通过将命令行定制到最小的输出目录集来解决这个问题。

这可以通过防止clobbers同时保持高度批量来解决您的问题,只要您的项目不包含100个文件,所有文件都在不同目录中命名为x.cpp ...通常根据我的经验,只有在一个更大的项目中,有一些碰撞.obj。

答案 3 :(得分:0)

可以确认问题,而且原因不容易找到,所以让我们为陷入困境的其他用户提供更多关键字。

我一直注意到,在最新的MSVC项目上进行重建花费的时间太长。特别是,几乎没有利用CPU内核,任务管理器中cl.exe进程上的编号变化很大,并且“输出”窗口显示正在按批处理方式编译的源文件。一次要编译从16到16的任何位置,稍停片刻,然后再编译另一组文件,依此类推。相比之下,在我较旧的项目中,CPU几乎已被充分使用,并且“输出”窗口显示正在编译的源文件的连续流。

现在,我的新项目的最大不同之处在于更好地利用了具有匹配目录结构的名称空间,这意味着最终会得到一些具有相同名称的类,并且由于指向同一目录的不同.obj文件而导致冲突,这导致在C / C ++->输出文件中更改对象文件名。

更新到“输出”窗口也匹配目录结构。如果存在一个带有一个源文件的名称空间/目录,则VS仅显示一次正在编译的一个文件。下一个目录包含10个源文件,而VS显示所有10个源文件正在同时编译。

解决方案不多。避免使用具有相同名称的类并且不更改对象文件名,或者使用the workaround posted by zeromus,它的功能很好。我的重建时间是从03:15到01:20,这是一个很大的差异,并且在大多数编译过程中,CPU利用率从〜35%降至平坦100%。

VS 2015、2017和2019都以这种方式运行,因此改变的希望不大。