无.lib文件的Visual C++ DLL插件项目如何编写单元测试
我太懂你这种卡壳的感觉了——明明DLL导出了符号(主程序都能正常识别加载),但VC就是死活不生成.lib,想写单元测试却被测试项目的链接要求拦在门外,试了各种网上的办法都没用,简直头大。结合我之前踩过的同款坑,给你几个实用的解决思路:
一、先强制VC自动生成导入库
你说找遍项目属性没看到“导出符号”的选项,其实有个更直接的设置能逼VC生成.lib:
- 打开插件项目的属性页,依次进入「配置属性 → 链接器 → 高级」
- 找到「导入库」这一项,手动填写生成路径和文件名,比如
$(OutDir)YourPlugin.lib($(OutDir)会自动替换为项目的输出目录) - 重新编译插件项目,这时候你去输出目录看看,应该就能找到生成的.lib文件了
之前你用了__declspec(dllexport)的宏却没效果,大概率是这个导入库的设置被默认留空了——VC在某些纯插件项目场景下,不会自动触发lib生成,手动指定路径后就会正常工作。
二、手动生成导入库(如果上面的方法还是不行)
如果VC还是不配合,我们可以用工具手动从DLL导出符号生成.lib:
步骤1:导出DLL的符号列表
打开VS自带的「Developer Command Prompt」(在VS的「工具 → 命令行」里能找到),进入你的DLL输出目录,执行:
dumpbin /exports YourPlugin.dll > exports.txt
这个命令会把DLL里所有导出的符号输出到exports.txt里,你能看到自己写的getName、setInfo这些函数肯定在里面。
步骤2:整理成.def文件
新建一个YourPlugin.def文件,格式如下:
LIBRARY YourPlugin.dll EXPORTS getName @1 setInfo @2
注意:@1、@2是符号的序号,在exports.txt里能找到对应的值(比如1 0 00001234 getName),直接抄过来就行;嫌麻烦的话也可以省略序号,只写函数名。
步骤3:生成.lib文件
还是在命令提示符里,执行:
lib /def:YourPlugin.def /out:YourPlugin.lib /machine:x64
(把x64换成x86,对应你的项目架构)
执行完后,当前目录就会生成YourPlugin.lib,把这个lib加到你的单元测试项目的「附加依赖项」里,测试项目就能正常链接了。
三、测试内部非导出函数的小技巧
如果你的单元测试不仅要测导出的getName、setInfo,还要测插件内部的Npp_Plugin类方法这类非导出符号,光靠上面的lib还不够,这时候可以给测试项目开个“后门”:
在插件的头文件里加一段条件编译:
#ifdef TEST_BUILD // 测试模式下导出内部符号 #define TEST_API __declspec(dllexport) #else // 正常编译插件时不影响原有逻辑 #define TEST_API #endif
然后把你要测试的内部类或函数加上TEST_API:
TEST_API class Npp_Plugin { public: // 把你要测试的方法声明暴露出来 static wchar_t const* get_plugin_name(); // ...其他内部方法 };
之后在单元测试项目的「预处理器定义」里加上TEST_BUILD,再把插件项目设为测试项目的依赖,这样编译测试项目时,插件会导出内部符号,生成的lib里就包含这些内部符号,测试项目就能直接调用Npp_Plugin::get_plugin_name()这类方法了。
最后再确认下你的导出代码
你的extern "C" __declspec(dllexport)写法是完全没问题的——主程序能加载插件就证明符号确实导出了,所以不用怀疑这部分,问题核心还是VC没自动生成lib,按上面的方法肯定能解决。
内容来源于stack exchange

