【问题标题】:How do I merge multiple PDB files?如何合并多个 PDB 文件?
【发布时间】:2009-02-09 13:20:59
【问题描述】:

我们目前使用单一命令行工具在 Windows 和 Linux 上构建我们的产品。

Si 到目前为止它工作得很好,允许我们从源代码构建并且具有比我们以前的任何构建系统所允许的更精细的依赖关系。这为我们带来了强大的增量和并行构建能力。

为了简要描述构建过程,我们采用通常的做法:

.cpp -- cl.exe --> .obj and .pdb
multiple .obj and .pdb -- cl.exe --> single .dll .lib .pdb
multiple .obj and .pdb -- cl.exe --> single .exe .pdb

msvc C/C++ 编译器充分支持它。

最近出现了构建一些静态库的需求。 根据我们收集到的信息,构建静态库的过程是:

multiple .cpp -- cl.exe --> multiple .obj and a single .pdb
multiple .obj -- lib.exe --> a single .lib

单个 .pdb 意味着 cl.exe 应该只对所有 .cpp 源执行一次。这个单一的执行意味着我们不能并行化这个静态库的构建。这真是不幸。

我们根据文档(和可用的命令行选项)进行了进一步调查:

  • cl.exe 不知道如何构建静态库
  • lib.exe 不知道如何构建 .pdb 文件

有人知道合并多个 PDB 文件的方法吗?我们注定要缓慢构建静态库吗? Incredibuild 等工具如何解决此问题?

【问题讨论】:

  • 您始终可以将代码放在固态驱动器上。构建速度快如闪电。
  • 我在我的样式簿上使用固态驱动器。它有帮助,但链接受 IO 限制,编译受 CPU 限制。

标签: visual-c++ command-line pdb-files


【解决方案1】:

我已经很久没有使用 C++ 了,但是从这个 article 看来,这是一个停止为常见标头重新创建符号的性能技巧。

您可以尝试 /Z7 在每个 obj 中嵌入信息,而不是创建 PDB,然后像 article 中那样使用 rebase 链接并重新创建它。

【讨论】:

  • 来自 /Z7 的调试信息与 /Zi 和 /ZI 生成的调试信息不​​是不同(并且劣质)吗?根据 Egghead cafe thead (support.microsoft.com/kb/258205) 中链接的文章,您可以将 /Z7 中的调试信息提取到 .dbg 文件而不是 .pdb 文件中。
  • 这两个链接现在都失效了:(
【解决方案2】:

无需合并 PDB 文件。

使用 /Z7 编译源文件以避免在 CL.EXE 步骤期间创建 PDB。

使用 LIB.EXE 创建带有嵌入式调试信息的静态库。使用 LINK.EXE 而不是 CL.EXE 链接,使用 /PDB 指定调试信息的去向。

如果您使用 EXE 和一个或多个 DLL 调试进程,请为调试器提供每个映像(EXE 或 DLL)的 PDB。

【讨论】:

    【解决方案3】:

    可以合并 PDB 文件,但只能通过 cl.exe 和 link.exe 完成。 我不知道任何用于合并 PDB 文件的独立工具。

    您可以使用 /PDB 选项链接器(我检查过 VC2005)来指定备用 pdb 文件名。

    Microsoft 建议同时包含 PDB 文件(每个 obj 都有一个对应的 PDB 文件)以及 .LIB 文件。

    不能在.LIB文件中存档PDB文件,我用VC2003试过了,失败了。

    使用 /Z7 编译可以避免 .LIB 的 PDB 文件,但目标文件很大,除非 link.exe 去除调试信息。如果您没有链接器的 /debug 选项,则无法调试您的 exe/dll。

    Compiler(cl.exe) 始终写入 vcXX.pdb 文件,除非您使用 /Fd 选项指定另一个名称。 即使您使用 cl.exe “直接”生成可执行文件,它也会生成 vc80.pdb 文件,然后 link.exe 将生成与可执行文件相同的 pdb 文件名。

    cl /Zi test.c

    cl.exe -> vc80.pdb link.exe 读取 vc80.pdb(名称嵌入在 test.obj 文件中)-> test.pdb

    每次 cl /Zi /c 编译一个文件时,它都会尝试修改现有的 vcXX.pdb 文件而不是覆盖它。

    我通过反复玩编译器得到上述结论,然后捕获 sysinternals 的 procexp 结果并分析它。希望对您有所帮助。

    【讨论】:

      【解决方案4】:

      除非您想重新分发带有调试信息的静态库,否则您实际上不需要合并任何 PDB 文件(或使用 /Z7 嵌入调试信息)。

      正如@zhaorufei 提到的,在使用/Zi 时,每个目标文件都包含对其PDB 文件的引用,然后链接器会使用该引用。

      只需使用/Fd 给每个对象一个唯一的 PDB 文件:

      > cl -c foo.cpp -Fo:target/foo.obj -Fd:target/foo.pdb -Zi
      > cl -c bar.cpp -Fo:target/bar.obj -Fd:target/bar.pdb -Zi
      
      > strings target/foo.obj | grep pdb
      D:\Dev\sample\target\foo.pdb
      > strings target/bar.obj | grep pdb
      D:\Dev\sample\target\bar.pdb
      

      这还有一个好处是它可以解决here 提到的对共享 PDB 文件的并发访问问题,因此您可以根据需要并行化编译步骤。

      然后像往常一样链接/归档目标文件。 VC++ 已经在目标文件中嵌入了各种信息以将它们传递给链接器,例如运行时链接设置和依赖库——PDB 文件路径也不例外。从对象创建静态库不会删除引用:

      > lib -out:target/all.lib target/foo.obj target/bar.obj
      > strings target/all.lib | grep pdb
      D:\Dev\sample\target\bar.pdb
      D:\Dev\sample\target\foo.pdb
      

      当将此库链接到可执行文件或 DLL 时,链接器仍会从引用的 PDB 中提取调试信息并将其添加到最终的 PDB 文件中。

      我能看到的唯一警告是路径始终是绝对的,因此如果在链接之前将文件移动到本地或另一台机器上,这可能不起作用。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2017-01-11
        • 2020-01-30
        • 2021-05-17
        • 2018-09-17
        • 1970-01-01
        • 2023-02-14
        • 2023-03-17
        • 1970-01-01
        相关资源
        最近更新 更多