在Visual Studio里利用pdb文件进入lib调试方法

本文介绍了如何在Visual Studio中调试静态库(.lib)和动态库(.dll)的代码,包括加载符号文件(.pdb)及源码的具体步骤,并提供了解决方案属性配置的指导。

1. 基础知识

静态库和动态库

首先说一下,库的导出分为静态库和动态库。
在这里插入图片描述

导出静态库的话,会生成一个.lib文件,其实就是.obj的集合,.obj又是.cpp编译得到的,所以,静态库里有函数的实现。不过这些实现是二进制的,是不带源码的。使用静态库的时候,需要链接.lib,包含.h。

导出动态库的话,会生成.dll文件和.lib文件,动态库生成的.lib文件会很小,因为这里的.lib只需要指明函数在.dll中的位置就可以了。使用的时候,需要把.dll和程序将要生成的.exe放在一个位置(双击exe运行),或者放在“调试 - 工程目录”指定的位置(在IDE中运行)。当然,如果你把“调试 - 工程目录“设置成$(OutDir),就和exe的输出位置一致了,调试也能运行,双击exe也能运行。

符号文件.pdb

.pdb文件就是所谓的符号文件。在库的编译过程中一同产生,pdb的生成位置和文件名由“链接器 - 调试 - 生成程序数据库文件”决定。这个名字是会写进.dll的,也可以和.dll的名字不一样。例如,dll的名字是a.dll,生成时的符号文件是b.pdb,你在调试时把b.pdb强行改成a.pdb,调试器是不认的。所以,为了调试方便不混淆,我建议把.pdb的文件名设置成和.dll一样。否则debug版和release版的pdb都一个名字,就无法区分了。

.pdb文件里面记载了函数名称和对应的.cpp文件名称,.cpp文件的md5信息。所谓“符号文件”,就是在你调试时用来查找函数对应于哪个.cpp文件哪一行的,好告知调试器跳转过去。
在这里插入图片描述

2. 加载符号

现在假设你已经有一个工程了,可以编译运行。你调用了在.lib中的函数,下了断点,按F11想要步入。

这时有两种情况,第一种是你直接跳转到库的源码了。这里的原理很简单,因为你的pdb已经加载(你把pdb放在调试目录了),pdb里记载了函数所在的cpp,而这个库是你在本机编译的,绝对路径没有改动,调试器直接就找到了对应的cpp,所以就直接跳转了。

而第二种情况,按F11并不能进入到源码,而是直接步过了。如果想进入.lib的源码,需要怎么做呢?

首先需要准备.pdb文件,还有库的源码。

之后要检查符号是否加载。下断点,F5调试。然后“调试 - 窗口 - 模块”打开模块窗口。
在这里插入图片描述
找到第三方dll的名字,我这里是DuiLib_ud.dll,看“符号文件”一栏是空的。说明这个dll的符号文件没有加载。

把.pdb和.dll放在一起。
在这里插入图片描述
再次调试。可以看到符号文件已经加载了。
在这里插入图片描述
其实不和dll放一起也可以。“工具 - 选项 - 符号”,在符号文件位置下面增加路径也可以。不过我不喜欢改动没有移植性的环境选项,更喜欢凡事都用相对路径。顺带一提,通过上面的模块界面,可以加载系统dll的符号文件,调试时可以进入系统dll的汇编。
在这里插入图片描述

3. 加载源码

现在符号文件已经加载了。再次开始调试,在断点处按F11步入。弹出了查找源码的选项。
在这里插入图片描述
在这里你就可以手动指定源码的位置了,不用担心版本出错,有md5校验的,你指定的.cpp如果不是这个库当初生成时的.cpp是通不过的。

不过我不喜欢这种硬编码绝对路径的做法,不优雅。我们点取消,就会看见未找到XXX.cpp界面。展开“源搜索信息”,可以看到调试器都从哪些地方在寻找这个.cpp文件。记住这个界面,如果我们之后指定.cpp路径时不正确,可以在这里来查看。
在这里插入图片描述
之后,把库的源码复制到我们自己的工程目录里。工程文件什么的不用带,只需要.cpp就可以了,理论上.h都不需要。
在这里插入图片描述
之后,在解决方案上右键“属性”,注意是解决方案上右键,不是工程。选择“通用属性 - 调试源文件”,在“包含源代码的目录”里增加我们刚拷进来的库的源代码目录。
在这里插入图片描述
微软说这里的查找源文件功能是不能识别子目录的,所有子目录都要手动加进来。

这里修改了之后,我实验发现要重启VS才生效。再次调试,可以进到库的源码了。在库的源码上悬停,我这里是在UIBase.cpp上悬停,可以看到它找到的源码的文件路径。确认是找到了我们刚放进去的源码。
在这里插入图片描述
本来我还想实验一下。我改了lib_src文件夹的名字,发现它还是能找到源码;我删掉debug文件夹下的内容,它还是能找到;我删掉和exe一块儿生成的.ilk和.pdb,它还是能找到;我删掉.vs隐藏文件夹,它还是能找到;我改动工程路径,它还是能找到。

这就很迷茫了。总之,也许它找到一次之后,查找文件功能就突然逆天了,知道寻找解决方案下面的所有cpp文件吧。

参考

如何调试静态库的代码(libeay32.lib和ssleay32.lib)

在 Visual Studio 调试器(C#、C++、Visual Basic、F#)中指定符号 (.pdb) 和源文件

### Visual Studio 2022 中 LNK1104 错误解决方案 当遇到 `LNK1104` 错误,提示无法打开文件 `'opencv_world320.lib'` 时,通常是因为链接器未能找到指定的库文件。以下是可能的原因以及对应的解决方法: #### 原因分析 1. **缺少必要的库文件** 如果开发环境中未安装或未正确配置 OpenCV 库,则可能导致链接失败[^1]。 2. **路径配置不正确** 配置项目的附加依赖项或库目录时,如果路径设置有误或者指向不存在的位置,也会引发此问题[^2]。 3. **编译平台与库版本不匹配** 使用不同架构(如 x86 和 x64)构建项目时,需确保所使用的库文件与其一致。例如,在 Release x64 平台下应使用针对该平台预编译的 `.lib` 文件[^3]。 4. **环境变量缺失** 若系统 PATH 变量中未包含动态链接库 (DLL) 的位置,可能会导致运行时报错找不到相应的 DLL 文件[^4]。 --- #### 解决方案 ##### 方法一:确认并下载正确的 OpenCV 版本 - 确保已下载适合当前系统的 OpenCV 安装包。对于 `opencv_world320.lib` 而言,这表明正在使用的是 OpenCV 3.2.0 版本。 - 下载地址可参考官方资源页面或其他可信站点获取对应版本二进制分发版。 ##### 方法二:调整项目属性中的库路径 1. 打开 Visual Studio 2022 工程; 2. 进入菜单栏依次点击【项目】-> 【<YourProjectName> 属性】; 3. 导航至左侧列表中的 “C/C++ -> 常规”,在右侧窗口添加 OpenCV include 目录路径;例如: ``` D:\opencv3.2.0\opencv\build\include ``` 4. 继续前往 “链接器 -> 常规”,修改 “附加库目录” 字段加入 lib 子目录所在位置;比如: ``` D:\opencv3.2.0\opencv\build\x64\vc14\lib ``` 5. 最后切换到 “链接器 -> 输入”,于 “附加依赖项” 处追加目标静态库名称及其调试模式变体形式(若有),即: ``` opencv_world320.lib;opencv_world320d.lib; ``` 上述操作完成后重新尝试编译验证效果^。 ##### 方法三:复制必要 DLL 至输出目录 为了使应用程序能够正常加载所需的共享对象模块,请按照以下步骤处理: 1. 将 OpenCV 提供的相关 dll 文件从其默认存储区域拷贝出来; 如示例所示路径为: ```plaintext D:\opencv3.2.0\opencv\build\x64\vc14\bin\ ``` 2. 把这些 dll 放置于最终生成的应用程序同级目录之下,或者是 Windows 系统全局搜索范围内像 `%SystemRoot%\System32` 或者 `%SystemRoot%\SysWOW64%` 内部^。 注意区分发行态(`*.dll`)和调试态(`*d.dll`)两种情况分别对待! ##### 方法四:清理旧残留数据重设环境 有时先前错误遗留下来的缓存信息干扰了后续工作流程,建议执行下列动作清除影响因素后再按前述指导完成设定过程: - 删除整个解决方案内的 Intermediate 输出物及最终产物(.exe,.pdb等),可通过右键单击 Solution Explorer 上面节点选择 Clean Option 实现自动化销毁作业; - 检查是否存在重复定义相同功能实体的情况从而引起冲突现象发生。 --- ### 示例代码片段展示如何引入外部头文件与函数调用关系建立连接机制 假设我们想利用 OpenCV 来读取一张图片显示给用户看,那么可以编写如下简单测试脚本作为起点入门学习材料之一部分: ```cpp #include <iostream> #include <opencv2/opencv.hpp> int main() { cv::Mat image = cv::imread("example.jpg"); // 加载图像 if(image.empty()) { // 检测是否成功加载 std::cout << "Could not open or find the image!" << std::endl ; return -1; } cv::namedWindow( "Display window", cv::WINDOW_AUTOSIZE );// 创建窗口用于呈现画面内容 cv::imshow("Display window", image); // 显示加载后的图形素材 cv::waitKey(0); // 等待按键触发事件退出循环 return 0; } ``` 以上便是基于 C++ 结合 OpenCV 开展基础视觉运算的一个典型例子说明文档. ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值