在Visual Studio中,如何在项目之间共享预编译头文件?

42

我有一个解决方案,其中包含许多使用PCH的Visual C++项目,但某些项目为满足特定需求打开了特定的编译器开关。

大部分这些项目在其各自的stdafx.h(STL、boost等)中共享相同的头文件集。我想知道是否可能在项目之间共享PCH,以便于不必为每个项目编译每个PCH,而是可以拥有一个通用的PCH,供解决方案中的大多数项目使用。

似乎可以在项目设置中指定PCH的位置作为共享位置,所以我猜这应该可行。我还假设所有使用共享PCH的项目中的所有源文件都必须具有相同的编译器设置,否则编译器将抱怨PCH与正在编译的源文件之间存在不一致。

有人尝试过这个吗?它能行吗?

相关问题:这样的共享PCH应该过度包容吗?或者这会影响总体构建时间吗?例如,共享PCH可以包含许多广泛使用的STL头文件,但某些项目只需要<string><vector>。使用共享PCH节省的时间是否需要在后期的构建过程中付出代价,因为优化器必须丢弃PCH带入项目中的所有未使用的内容?


为什么不试一下,然后告诉我们呢?在你写这篇文章的时间里,你已经可以完成一个简单的2个项目的概念验证了。 - shoosh
1
我认为两个项目的概念验证并不能证明什么。大量项目在其中起了一定作用。 - Assaf Lavie
3
请投票支持这个提议:http://visualstudio.uservoice.com/forums/121579-visual-studio/suggestions/4931119-allow-precompiled-headers-to-be-shared-between-pro该提议的内容是允许预编译头文件在项目之间共享。 - Scott Langham
根据上述内容,现在已经支持了,但是没有关于如何设置的信息。有人成功实现了吗? - Robin
6个回答

25

是的,这是可能的,我可以向您保证,节省的时间是显著的。当您编译您的PCH时,您必须从创建PCH文件的项目中复制.pdb.idb文件。在我的情况下,我有一个简单的两个文件的项目来创建PCH文件。头文件将是您的PCH头文件,源文件则被告知在项目设置中创建PCH——这与您通常在任何项目中所做的类似。正如您提到的,您必须对每个配置使用相同的编译设置,否则会出现差异,编译器会发出警告。

每次重新构建或重新编译PCH时复制上述文件将会很麻烦,因此我们将自动化这个过程。要自动复制,执行一个预构建事件,在其中将上述文件复制到适当的目录。例如,如果您正在编译PCH的DebugRelease版本,则从PCH项目的Debug复制文件到依赖项目的Debug。所以,一个复制命令看起来像这样

copy PchPath\Debug*.pdb Debug\ /-Y

请注意末尾的/-Y。在第一次构建之后,每次后续构建都是增量编译的,因此如果再次替换文件,Visual Studio将会抱怨有损坏的符号。如果它们确实被破坏了,您可以始终执行重新构建,这将再次复制文件(这时不会跳过它们,因为它们已不存在——清理将删除文件)。

希望这能帮到您。我花了很长时间才能做到这一点,但它是值得的。我有几个依赖于一个大型框架的项目,PCH只需要编译一次。所有依赖项目现在都可以很快地进行编译。

编辑:与其他几个人一样,我已经在VS2010和VS2012下对此进行了测试,似乎可以正常运行。


有人在vs2010上尝试过这个吗? - Hertzel Guinness
1
是的,它似乎不起作用,我收到了错误提示:\vc100.pdb 不是创建此预编译头文件时使用的 pdb 文件,请重新创建预编译头文件。此外,必须更改 Microsoft.Cpp.Win32.targets,否则它会尝试首先删除 PCH! - paulm
这绝对不能在生产环境中使用,它会破坏重建并出现各种问题。 - paulm
这在发布构建中对我有效,但在调试构建中无效,我遇到了和paulm一样的错误。 - Jherico
我只是想知道是否仍然需要编译使用pch的项目的自己版本。看起来是这样,因为stdafx.cpp的设置仍然显示“生成”。我尝试简单地删除stdafx.cpp,但这会导致链接器错误:“LNK2011:未链接预编译对象;映像可能无法运行”。所以其他项目可能应该链接到已创建的stdafx.cpp对象文件? - imagiro

16

虽然这是一个老问题,但我想给出一个新的答案,适用于Visual Studio 2017,并且不涉及任何复制。唯一的缺点:编辑和继续不再起作用。

基本上,您必须为预编译头文件创建一个新项目,并使所有其他项目依赖于它。以下是我所做的:

步骤如下:

  1. 在解决方案中创建一个新项目,其中包括头文件(从这里起称为pch.h)和一个只有一行的cpp文件,该文件包括pch.h。该项目应该创建一个静态库。设置新项目以创建预编译头文件。输出文件需要被所有项目访问。对于我来说,这是相对于IntDir的,但对于默认设置,它可以相对于$(SolutionDir)。pch项目必须只包含所有其他项目也具有的定义。

    pch project settings

  2. 使所有其他项目依赖于这个新项目。否则,构建顺序可能会出错。

    project references

  3. 设置所有其他项目使用pch.h。请注意,输出文件参数与pch项目中的参数相同。额外的包含目录也需要指向pch.h目录。您还可以强制在每个cpp中包含pch文件(或者在每个cpp文件的第一行手动包含它)。

    pch include include

    1. 设置所有项目(包括pch项目)使用相同的编译器符号文件(链接器符号文件不受影响)。同样,在我的示例中,这是OutDir,但在您的解决方案中可能会有所不同。它必须指向磁盘上相同的文件。调试信息格式需要设置为C7(见上图),否则Visual Studio将无法并行编译项目。 pdb

我希望我没有忘记任何东西。对于我的解决方案(130k loc,160个项目),这导致编译时间从大约3:30分钟缩短到了约2:30分钟。


好奇,使用此设置时使用“编辑和继续”会发生什么? - Ramkumar
您需要切换调试信息格式,这将导致 Visual Studio 无法并行编译,从而降低任何性能优势。 - Nick Papagiorgio
哦,糟糕。错过了你切换到 /Z7 的帖子。谢谢澄清。 - Ramkumar
1
即使在vs2010中也能正常工作。 - Daniel Laügt
1
有没有人能够用CMake完成这个?我的尝试都失败了,而且由于链接不再起作用,我无法验证我在CMake中做的工作是否能够转换成VS。 - spellmansamnesty
预编译头文件能否在可执行文件中重复使用?在可执行文件中引用通用的预编译头文件会导致编译器警告,提示编译器选项不匹配。 - Elad Maimoni

5

Samaursa的回答对我很有帮助。

我也看到了这个链接,它可以工作(在底部找到Reginald的答案)。

这个使用copy,而Reginald的使用xcopy(我更喜欢xcopy)。无论哪种方式,谢谢 - 这大大加快了我的构建速度。


1
+1,这个更好,因为它会在stdafx文件改变时自动重建。 - Yakov Galka

5

看起来不可能,因为每个源文件都必须针对与预编译头文件编译时相同的PDB进行编译。真糟糕。


是的,我也遇到了这个问题。 :-(错误 C2859: vc90.pdb 不是创建此预编译头文件时使用的 pdb 文件,请重新创建预编译头文件。http://msdn.microsoft.com/en-us/library/3bw58yy6.aspx - Trevor Robinson
1
可以的,请看我的答案。 - Samaursa

3
这听起来像是“收益递减”的情况。假设每个.cpp文件直接包含常见的头文件会浪费1秒钟,每个目标(DLL / EXE)有10个.cpp文件。通过为每个目标使用一个.pch,您可以每个目标节省10秒钟。如果整个项目有10个目标,则在整个构建过程中可以节省1.5分钟,这很不错。
但是,将其减少到整个项目的一个.pch,您只能再节省9秒钟。这值得吗?额外的努力(可能要设置得更加繁琐,因为它是VS向导不支持的非标准配置)仅产生了十分之一的节省。

9
考虑到解决方案中有200个项目,使用预编译头可能需要10秒钟来进行编译。在这种情况下,不清楚回报是否那么微不足道。 - Assaf Lavie
整个构建需要多长时间? - Daniel Earwicker
这也涉及到在增量构建中节省时间的问题。一个更改可能只会强制重新编译每个项目中的一个文件,然后加载每个预编译头文件以进行快速编译需要很长时间。 - Macke
1
@DanielEarwicker:一个配置 x(32,64位)x(Debug,Release)需要40-50分钟。而且已经有大约400个项目了。 - Yakov Galka

1
在2012年,您可以使用PDB,并从仅构建pch和依赖于pch lib的主项目的lib项目中构建pch,而且它们可以直接放在同一个目录中(无需复制),不幸的是,这种方法在2013年以后就不再适用了,除非通过冗长的变通方法。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接