研究意义
笔者日前正在参与利用C++代码作为底层的项目,基础已经在大一后忘得差不多,导致异常痛苦。经过不断尝试,总结出生成动态库dll以及调用动态库的一般步骤以及易踩坑的点,记录下来不仅是给以后的自己看,也是帮助其他初步上手C++的同学。
动态库dll生成
1. 找到需要打包封装的函数定义与声明,再其前端加上代码_declspec(dllexport)
_declspec(dllexport) int rendezvous(int a, double* b, double c[], int d);
若是需要调用C形式的函数,则再在最前端加上extern "C",即
extern "C" _declspec(dllexport) int rendezvous(int a, double* b, double c[], int d);
2. 右键项目,点击属性,将配置类型改为“动态库(.dll)”
3. 右键项目,点击“重新生成” or 点击顶部栏“生成”,点击“重新生成解决方案”
4. 在 项目名/x64/Debug 中,找到生成的“项目名.dll”和“项目名.lib”文件
(若是生成静态库,则在第2步中选择静态库(.lib),第4步中只需要找到“项目名.lib”文件即可)
动态库dll调用
1. 将“项目名.dll”和“项目名.lib”文件复制到vcxproj文件同一路径之下(在sln文件的下一层)
2. 在新的项目解决方案资源管理器中,右键“资源文件”,选择添加,点击“现有文件”,添加第1步的dll文件和lib文件
3.右键项目,选择属性,保证“常规”中的配置类型为“应用程序(.exe)”
在“VC++目录”中,修改库目录,点击编辑后直接输入之前的“项目名.dll”即可(不使用路径是因为交付其他人使用时路径会不同)
随后在“链接器”中,选择“输入”,在附加依赖项中输入第1步的“项目名.lib”
至此项目属性调整完成。
4. 建立测试源文件test.cpp,其中必须包含如下代码
#include <Windows.h>
#include <wincrypt.h>
#pragma comment(lib,"项目名.lib")
剩下main文件自己按照函数性质与测试内容书写,头文件根据需要可以自己重新创建,也可以从原文件里复制过来。
5. 在main函数前声明函数
extern "C" _declspec(dllexport) int rendezvous(int a, double* b, double c[], int d);
注意,此时VS会提示未找到函数定义,但可以不用管。随后进行解决方案生成,逐步纠错即可。
易踩坑
1. LINK2019 未解析的外部符号:
最有可能的原因是顶部的“x86”还是"x64"需要和原本的函数所在的项目保持一致。
以C形式进行调用的函数,若未在原本的项目中加入extern "C",或是在调用时为加入该代码,也会出现该问题。
2. xxx函数重载
指函数被多次定义,笔者在生成静态库lib的时候遇到一次。当时测试函数中需要用到一个额外的jday函数,于是在测试项目中增加了相应的源文件和头文件。但忘记了原函数中也定义了一次jday函数,生成的lib被装载到测试项目后,发生了该类报错。最后在原项目中去掉了jday的相关定义和声明,解决了该错误。
3. 无法打开源文件
部分源文件如Eigen,需要在“C/C++”中的“附加包含目录”中,将额外的.h文件包含,需要输入该文件的路径。