10

我们目前使用单个命令行工具在 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 等工具如何解决此问题?

4

4 回答 4

5

我很长时间没有使用 C++,但从这篇文章看来,这是一个停止为常见标头重新创建符号的性能技巧。

您可以尝试 /Z7 在每个 obj 中嵌入信息,而不是创建 PDB,然后使用 rebase 链接并重新创建它,如本文中所述。

于 2009-03-19T11:08:55.003 回答
5

无需合并 PDB 文件。

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

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

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

于 2009-03-25T13:01:51.880 回答
2

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

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

Microsoft 建议还包括 PDB 文件(每个 obj 都有一个相应的 PDB 文件)以及 .LIB 文件。

您无法将 PDB 文件存档在 .LIB 文件中,我用 VC2003 尝试过,失败了。

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

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

cl /子测试.c

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

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

我通过反复玩编译器得到了上述结论,然后捕获 sysinternals 的 procexp 结果并对其进行分析。希望能帮助到你。

于 2010-09-16T08:44:19.120 回答
1

除非您想重新分发带有调试信息的静态库,否则您实际上不需要合并任何 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

这还有一个好处,它可以解决此处提到的对共享 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 文件中。

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

于 2017-03-05T08:52:23.467 回答