使用 /Zi 和 /Z7 对于 Visual Studio C++ 项目有哪些影响?

42

背景

Visual Studio C++编译器有几个不同的调试标志,它们分别是:

  • (无)
    • 不创建任何调试信息
    • 编译时间更快
  • /Z7
    • 使用CodeView格式在.obj文件中生成完整的符号调试信息
  • /Zi
    • 为目标生成一个.pdb文件中的完整符号调试信息,使用Program Database格式
    • 启用对最小重建(/Gm)的支持,可以减少重新编译所需的时间。
  • /ZI
    • 生成类似于/Zi的调试信息,但支持编辑并继续

问题

  • /Gm标志与/MP标志不兼容,适用于多进程构建(Visual Studio 2005/2008)

  • 如果要启用最小重建,则必须在/Z7标志上使用/Zi标志。

  • 如果您将使用/MP标志,则在MSDN中查看/Z7和/Zi似乎没有区别。但是,SCons文档指出,您必须使用/Z7来支持并行构建。

问题

  • 在Visual Studio C++项目中使用/Zi与/Z7有什么影响?

  • 是否存在其他优缺点我漏掉的选项?

  • 具体而言,目标的单个程序数据库格式(PDB)文件与每个源的多个CodeView格式(.obj)文件相比有什么好处?

参考资料

MDSN /Z7, /Zi, /ZI (调试信息格式)

MSDN /MP (使用多个进程进行构建)

SCons构建变量CCPDBFLAG

调试信息

5个回答

10

Codeview是一种较早的调试格式,它是在上世纪80年代中期的“Microsoft C Compiler”时代引入的,由微软的单独调试器推出。它占用更多磁盘空间,调试器解析时间更长,并且在链接过程中处理起来非常麻烦。我们在1998年至2000年期间为Windows的CodeWarrior编译器生成了它。

唯一的优点是Codeview是一种文档化的格式,其他工具通常可以处理它,而不能处理PDB格式的调试数据库。此外,如果您一次构建多个文件,则没有争用来写入项目的调试数据库。然而,在大多数情况下,如今使用PDB格式是一个很大的胜利,无论是在构建时间还是特别是在调试器启动时间方面。


6
我不同意。对于我们的项目来说,使用Z7构建可以显著加快速度,特别是在虚拟机上。而且最终链接/ DEBUG会创建PDB文件。但它不能与LTCG一起使用。 - Trass3r
1
同意。众所周知,Z7编译速度比Zi快。 - Sophit

8
旧的C7格式的一个优点是它是全包含的,存储在EXE中,而不是单独的PDB和EXE。这意味着您永远不会出现不匹配的情况。VS开发工具将确保PDB与其EXE匹配,然后才会使用它,但是拥有一个包含所有所需内容的单个EXE肯定更简单。

这增加了新问题,需要能够在发布时剥离调试信息以及巨大的EXE文件,更不用说古老的格式和缺乏其他现代功能(如minrebuild)的支持,但是当您尽可能保持简单时,它仍然可以帮助您。一个文件比两个文件更容易。

并不是我经常使用C7格式,只是因为你问了,所以我把这个可能的优点放在这里。

顺便说一下,在我使用的几个平台上,GCC就是这样做的。DWARF2格式隐藏在输出ELF中。Unix人认为这很搞笑。 :)

顺便说一下,可以使用DIA SDK解析PDB格式。 DIA SDK


我们本可以在CodeWarrior中使用DIA SDK,但编译器/链接器必须在Macintosh和Windows机器上运行以进行交叉编译,并且该SDK仅为二进制格式 :) - Ben Combee
14
根据http://msdn.microsoft.com/en-us/library/xe4t6fc1%28v=vs.80%29.aspx ,不可能创建包含调试信息的 .exe 或 .dll 文件,调试信息总是存储在 .pdb 文件中。这在 Codeview 时代可能是一项功能,但是现在的 C7 只会将调试信息放在 .obj 文件中,而不是 .exe 文件中。 - Tad Marshall

6
/Z7 会以CodeView格式将调试信息保留在.obj文件中,并允许链接器将它们提取到.pdb中。而 /Zi 则在编译时通过与 mspdbsrv.exe 同步来将其合并到一个公共的.pdb文件中。因此,/Z7 意味着需要更多的文件IO、使用更多磁盘空间以及给链接器带来更多的工作量(除非使用/DEBUG:FASTLINK),因为这些.obj文件中有很多重复的调试信息。但是如果有足够的并行化,它也意味着每次编译都是独立的,因此实际上可能比 /Zi 更快。
现在,通过减少与 mspdbsrv.exe 的进程间通信,他们已经改进了 /Zi 的情况:https://learn.microsoft.com/en-us/cpp/build/reference/zf 另一个 /Z7 的用例是针对“独立”(虽然更大)的静态库,如果您需要的话,无需发送单独的.pdb。这也避免了由 cl 使用可怕的默认vcxxx.pdb名称引起的恼人问题,只要您不使用适当的https://learn.microsoft.com/en-us/cpp/build/reference/fd-program-database-file-name进行修复,但大多数人忘记了。 /ZI/Zi 类似,但添加了其他数据等,以使编辑和继续功能起作用。

4

/Z7 还有一个缺点:它不与增量链接兼容,这也许是要避免使用它的原因之一。

顺便说一下:尽管 Microsoft 表示当“使用 /Yu /Z7 选项编译的对象发生更改时执行完整链接(而不是增量链接)”,但似乎这只对使用 /Z7 构建的静态库而非对象文件有效。

http://msdn.microsoft.com/en-us/library/4khtbfyf%28v=vs.100%29.aspx>

从MSVC 2017开始,不再提及此限制: “使用/Yu /Z7选项编译的对象已更改。” 我认为这意味着现在可以将/Z7与/INCREMENTAL一起使用。 https://learn.microsoft.com/en-us/cpp/build/reference/incremental-link-incrementally?view=msvc-170 - elegant dice

3
/Z7的另一个缺点是目标文件非常大。虽然这一点已经在此提到过了,但它可能会升级到链接器无法链接可执行文件的程度,因为它超出了链接器或PE格式的大小限制(它会给出链接器错误LNK1248)。看起来Visual Studio或PE格式在x64机器上有一个硬性限制为2GB。构建调试版本时,您可能会遇到这个限制。似乎这不仅影响最终编译的可执行文件的大小,还会影响临时数据。只有微软知道链接器的内部情况,但我们在这里遇到了这个问题(尽管可执行文件当然不会很大,在调试中也不会超过2GB)。当我们将项目切换到/ZI时,这个问题神奇地消失了并再未出现过。

我猜你最终使用了32位的链接器。 - Trass3r

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