最近在编译github上的开源项目,下载下来后,查看源码是dll工程且类是导出类,使用到导出string标准库中的字符串问题,由于接口中涉及到string类,就涉及到谁开辟谁释放的跨组件问题,加入工程后,如果主进程(调用进程为多线程MT形式)就会出现编译错误或模块内存释放问题,在这里要理解的知识点是:
(1)组件和调用进程同为MD(或MDd)多线程模式,则组件与调用进程使用的是主进程的内存空间,不存在跨模块释放内存问题;
(2)组件和调用进程同为MT(或MTd)多线程模式,则组件与调用进程使用的是各自模块的内存空间,给子有相应的内存分配器,除非使用统一的CoAlloc或其他API使得组件和主进程使用同一内存空间,这样就不存在内存组件开辟然后主进程释放,或主进程开辟内存空间但是dll释放导致跨模块释放崩溃问题;
解决以上跨模块问题的方法有两种:
(1)保证主进程与Dll组件同时为MD或MDd多线程模式,这样两个组件不存在跨进程内存分配问题(都为进程内存)
(2)把Dll工程更改为static库工程,使得静态库的多线程模式和主进程一致,编译后的lib直接添加到主进程调用;
方法(1)虽然可以解决问题,按照我的习惯:
(1)一个项目能不依赖其他dll的就不依赖其他dll,尽量减少dll的依赖,所以提倡使用静态库链接。
因为dll多了,可能出现A和B都依赖C,而C存在多个接口都不一样的版本,这就尴尬了,需要分文件存放不同版本dll,项目很难运维;增加打包繁杂度,特别是项目打了,依赖的组件上百个,容易漏掉;一致性不太好,比如win7上可用的dll在win server r2上不能用(很正常涉及到音视频,服务器机器上无对应组件)。等等原因;
(2)组件少,可移植性强,
所以,我们可以考虑将dll工程转为静态库工程,然后将静态库工程添加到调用进程,这样会解决若干麻烦,接下来告诉你如何将已有的dll工程转为静态库工程(当然,最简单的办法就是新建静态库,然后添加所有文件。但是如果代码量大,文件多就非常麻烦!),具体步骤如下:
(1)将项目-->属性-->常规-->配置类型(父项:项目默认值)更改为静态库lib
(2)将项目-->属性-->常规-->目标文件扩展名(父项:常规)更改为.lib
(3)重点在这里:将dll类或函数的导出声明去掉,随意找到一个类,跳转到导出宏定义声明,这里找到的定义在
\src\SimpleAmqpClient\Util.h
(4)更改宏定义为:
(4)更改宏定义为:
#ifdef WIN32
#ifdef SimpleAmqpClient_EXPORTS
#define SIMPLEAMQPCLIENT_EXPORT /*__declspec(dllexport)*/
#else
#define SIMPLEAMQPCLIENT_EXPORT /*__declspec(dllimport)*/
#endif
#else
#define SIMPLEAMQPCLIENT_EXPORT
#endif
这里仅仅是举例,具体宏定义见自己工程的dll导出声明宏,去掉dllexport和dllimport声明即可。
(5)最后编译生成静态库即可,否则报错提示dllimport,改单词仅仅适用于dll,也就是存在改单词会让vs误以为是动态库导入。
快来成为我的朋友或合作伙伴,一起交流,一起进步!
QQ群:961179337
微信:lixiang6153
邮箱:lixx2048@163.com
公众号:IT技术快餐
更多资料等你来拿!