运行时库错误、libcmt已定义、msvcrt已定义、LINK2005、无法找到符号
一、动态库DLL提供1、新建一个项目(任意项目,无论是控制台也好,空项目也罢)。
2、项目属性-》常规-》项目默认值 设置为动态库。
3、新增一个头文件,名字自定。写入如下方声明。以GetImphash 函数为例的一个声明。
4、添加新建项-》代码-》模块定义文件(.def)写入库隐式链接名和函数名。
5、设置属性-》连接器-》输入-》模块定义文件设置刚才的def文件(一般会自动设置)。
6、增加cpp文件,包含3中头文件并实现该方法即可。
//.h文件声明导出函数,也用于导入时链接lib
#ifdef __cplusplus
extern "C" {
#endif
#ifdef EXPORTDESC //在库项目属性-》c++-》预处理器-》预处理器定义加入EXPORTDESC 即可
#define DLL_EXPORT __declspec(dllimport)
#else
#define DLL_EXPORT _declspec(dllexport)
#endif
//保证缓冲区大于33字节
DLL_EXPORT int GetImphash(char* FileName, char* HH);
#ifdef __cplusplus
}
#endif
;def文件 LIBRARY yara_imphash_33;指定模块名 EXPORTS GetImphash @1;导出函数名字 和序号,此处可以确保名字不带参数二、静态库编译
一般而言,能将代码编译为静态库同样也能编译为静态库。只需将 项目属性-》常规-》项目默认值 设置为静态库,所以编译静态库先完成上述动态库设置。
①如果原来在dll中存在依赖项(属性-》连接器-》输入-》附加依赖项),这里的依赖项的所在目录一般在此指定:属性-》连接器-》常规-》附加库目录 。此时编译lib也需要将依赖加入到lib的配置中。
②务必注意,设置为dll和lib时其设置不共通,需要手动设置① 涉及的目录。操作为首先设置 属性-》常规-》项目默认值-》配置类型 更改为lib,此时属性页不会改变,需要点击确定或应用后属性页才会刷新。
③在② 设置后 即可对应①中的配置进行设置。附加依赖项在:属性页-》库管理器-》常规-》附加依赖项 ,而附加库目录在: 属性页-》库管理器-》常规-》附加库目录。将dll时的设置同样添加到这里
④由于之前dll的头文件是用于声明导出的,在编译为静态库后则不再需要,因此在使用项目时需要去掉export的声明。
知识点汇总1、头文件声明使用宏实现在库项目和使用者项目函数的导入和导出的声明。即在库项目中export声明生效。在使用库的项目中import宏生效。
2、def文件可以使导出函数名不附带参数与返回值的符号说明,干净易用
3、dll动态库生成时同样会生成lib 文件,此时lib作用仅仅是隐式链接(很多缺少dll弹框则隐式链接,代码调用loadlibray自行编写则为显示)。
4、库编译为lib时,如dll依赖A.lib和 B.lib。则lib依然依赖他们,在编译后的目标lib中将包含A.lib和 B.lib的代码,之后的使用者只链接改库lib无需再链接A.lib和 B.lib。
5、无论编译为LIB还是DLL,其运行时库尽量统一,这在编译为LIB或者程序兼容方面有莫大的帮助。运行时库的查看选择:属性-》c++-》代码生成-》运行库。对应关系为
| 运行时 | 对应库 | 是否静态 | 优缺点 |
| MT/MTD | licmt.lib | 静态(编译后不引入运行时dll) | 程序大,跨模块堆隔离 |
| MD/MDd | msvcrt.lib | 动态(依赖于msvcrxxx.dll) | 程序小,需要使用者安装VC运行时库 |
如果在程序中引入上述的 md系列运行时库,那在使用者未安装vc运行库时则无法正常运行,出现类似如下的错误 。
6、从上述中可以发现,如果我们混用mt md且先不谈他们会出现符号重定义问题,而且也会集合两个的缺点,让程序变得混乱,既是增加了依赖还让程序臃肿不堪。因此尽量保证一个dll或lib的运行时和他的所有依赖项都一致。
7、最后的编译时的平台工具集或SDK版本不同会导致链接错误,因此需要在相同的平台工具集和SDK版本下编译。有的平台工具集无法选择SDK(较老的如vs 2010工具集)
8、使用LIB有时候死活无法解析外部符号,可以注意看函数声明的头文件关于 import字段的声明宏处理,有的需要在使用者的预编译定义加入一些宏。保证使用静态lib时候的声明无import字样。



