使用 Visual Studio 调试共享库¶
在之前的例子中,我们讨论了如何在 Visual Studio 中调试依赖项,但是当在项目中使用 Conan 依赖项时,原始构建文件夹和构建文件可能不存在。默认情况下,Conan 包不包含使用 Visual Studio 调试库所需的信息,此信息存储在库编译期间生成的 PDB 文件中。使用 Conan 时,这些 PDB 文件在构建文件夹中生成,而构建文件夹仅在构建库时才需要。因此,使用 conan cache clean
清理 Conan 缓存以删除构建文件夹并节省磁盘空间是一种常见操作。
对于构建文件夹不存在的这些情况,我们创建了一个 hook,将构建文件夹中生成的 PDB 文件复制到包文件夹中。默认情况下,不能强制执行此行为,因为 PDB 文件通常大于整个包,并且会大大增加包的大小。
本节将介绍如何在不同情况下调试项目的一些示例,以展示用户如何使用 PDB hook。
创建项目并像往常一样调试¶
首先,我们将像往常一样调试我们的项目,如之前的示例中更详细地解释的那样。我们可以像上一节一样,从源代码构建我们的依赖项,只是这次我们将它们构建为共享库。首先,从 GitHub 上的 examples2 仓库克隆示例所需的源代码并创建项目。
$ git clone https://github.com/conan-io/examples2.git
$ cd examples2/tutorial/consuming_packages/simple_cmake_project
$ conan install . -o="*:shared=True" -s build_type=Debug --build="zlib/*"
...
Install finished successfully
# CMake presets require CMake>=3.23
$ cmake --preset=conan-default
注意
我们将只介绍依赖项构建为共享库的情况,因为 PDB 文件以及它们如何链接到库,对于静态库而言有所不同。
我们现在可以打开解决方案 compressor.sln
以在 Visual Studio 中打开我们的项目,并按照之前的示例进行调试。在第 22 行设置断点,运行调试器并使用单步执行将允许我们在依赖项文件 deflate.c
中进行调试。

在这种情况下,原始构建文件都存在,因此调试器像往常一样工作。接下来,我们将了解从 Conan 缓存中删除构建文件后,调试器如何工作。
从 Conan 缓存中删除构建文件¶
有多种原因可能导致依赖项编译后不存在构建文件。我们将使用 conan cache clean
从缓存中清除我们的构建文件,以模拟其中一种情况。--build
标志确保我们只删除构建文件,因为我们将需要我们的源文件用于此示例。
$ conan list "zlib/1.2.11:*"
$ conan cache path --folder build zlib/1.2.11:17b26a16efb893750e4481f98a154db2934ead88
$ conan cache clean zlib/1.2.11 --build
$ conan cache path --folder build zlib/1.2.11:17b26a16efb893750e4481f98a154db2934ead88
在 Visual Studio 中关闭并重新打开我们的解决方案后,我们可以尝试再次调试。如果您尝试单步调试依赖项,并在第 22 行设置断点,您会注意到它会直接跳到下一行,因为 Visual Studio 没有关于调试依赖项的任何信息。
安装 hook 以将 PDB 文件复制到包文件夹¶
为了解决包文件夹中没有 PDB 文件的问题,我们创建了一个 hook,将 PDB 文件从构建文件夹复制到包文件夹。该 hook 位于 conan-extensions 仓库中。安装整个仓库会起作用,但我们建议只从 conan-extensions
仓库安装 hooks 文件夹,使用
$ conan config install https://github.com/conan-io/conan-extensions.git -sf=extensions/hooks -tf=extensions/hooks
该 hook 的设计使其默认情况下不会运行,因为它会显着增加包的大小。正如hooks 文档中所解释的那样,我们需要更改 hook 的名称,使其以 hook_
开头。要找到 hook 的放置路径,请运行命令 conan config home
查找您的本地缓存路径,然后转到 extensions/hooks
文件夹以重命名 _hook_copy_pdbs_to_package.py
文件。请注意,每次运行 package()
方法时,此 hook 都会运行,要禁用该 hook,只需将 hook 重命名回以 _hook_
开头。
该 hook 实现为 post-package hook,这意味着它将在通过配方的 package()
方法创建包后执行。这避免了任何潜在的问题,因为顺序如下
执行配方的
build()
方法,生成 DLL 和 PDB 文件执行配方的
package()
方法,将必要的文件复制到包文件夹(在本例中为 DLL 文件,但不包括 PDB 文件)执行 hook,将 PDB 文件从构建文件夹复制到包中每个 DLL 的旁边
该 hook 使用 Visual Studio 安装中包含的 dumpbin
工具。此工具允许我们获取 DLL 的信息,在本例中是其关联的 PDB 文件的路径。它将用于包中的每个 DLL,以找到其 PDB 文件并将其复制到包文件夹。
有关 PDB 如何与 Visual 工作以及我们如何使用它创建 hook 的更多信息,请参见 hook readme。
在没有构建文件的情况下进行调试¶
安装 hook 后,我们将再次从源代码创建项目,以便 hook 现在可以将 PDB 文件与包 DLL 一起复制到包文件夹,以便调试器可以找到它们。
$ conan install . -o="*:shared=True" -s build_type=Debug --build="zlib/*"
...
zlib/1.2.11: Calling package()
...
[HOOK - hook_copy_pdbs_to_package.py] post_package(): PDBs post package hook running
...
Install finished successfully
# CMake presets require CMake>=3.23
$ cmake --preset=conan-default
请注意,现在运行 conan install 时,您会看到在调用 package()
后运行的 hook 的输出。为了测试该 hook,我们可以再次清除缓存以删除构建文件,包括用于构建库的源文件和最初生成的 PDB 文件。
$ conan cache clean zlib/1.2.11 --build
再次在 Visual Studio 中打开解决方案并启动调试器。当您尝试在第 22 行单步调试依赖项时,会弹出一个错误消息,告诉我们找不到该文件,并询问该文件位于何处。我们可以关闭此窗口,它将提供查看反汇编的选项,该反汇编可以借助 PDB 文件进行调试。PDB 文件仅包含调试信息,但 Visual Studio 缺少源文件,因此它将无法像最初那样调试这些文件。

为调试器定位源路径¶
删除原始构建文件后,Visual Studio 将无法自行找到源文件。为了能够调试源文件,有一个选项可以手动设置源文件夹路径,以便可以调试源文件。这要求依赖项的源文件存在。在我们的例子中,我们可以通过运行 `conan cache path
获取此源文件的位置。
$ conan cache path --folder source zlib/1.2.11
如果不存在此源路径,我们可以使用配置再次下载源文件。
$ conan install . -o="*:shared=True" -s build_type=Debug -c:a="tools.build:download_source=True"
获得源路径后,我们可以在 Visual Studio 中设置它,以便调试器可以找到源文件。在解决方案资源管理器中右键单击解决方案,然后选择属性。转到通用属性部分中的“调试源文件”并添加我们的源路径。

再次启动调试器将允许像我们在第一个示例中所做的那样,单步调试依赖项的代码。
注意
如果对源文件进行了修补,我们将无法调试修改后的文件,因为我们使用的是源文件夹中的文件,并且修补是在稍后的步骤中应用的,就在在构建文件夹中编译之前。
对源文件进行任何修改都不允许调试它们,因为 Visual Studio 会进行校验和检查,因此它们需要与编译库时的文件完全相同。