现在的位置: 首页 > 综合 > 正文

VS创建动态链接库和静态链接库的一些注意事项

2012年11月07日 ⁄ 综合 ⁄ 共 1419字 ⁄ 字号 评论关闭

本文凭记忆写出来的, 所以很多东西可能有误差,仅列举一下, 具体事项如果遇到了, 请自行查询, 这里仅仅用来起提示作用.

1. 配置属性->常规: 编码设置, 建议选Unicode. 但是看到的代码很多人还是用ANSI, 完全是历史遗留问题, 在程序处理字符上, Unicode非常方便, 只有在保存和传输的时候需要使用不同的编码.

2. 预编译头, 实际上可以给每个CPP文件指定预编译方式, 一般设置如下, stdafx.cpp设置为创建预编译头, 整个工程设置使用预编译头.

3. 代码生成:运行库, 一般选多线程调试DLL(\MDd)(Debug版本), 或者多线程DLL(\MD)(Release版本),  很少有人用单线程版本吧. 关键是如果使用了多个库, 每个库的这个设置都需要一致, 不管你是动态库或者静态库. 如果不一致, 就会有警告或错误. 可是如果使用现成的库, 这个设置我们又控制不了他用什么生成的, 不过绝大多数人用的是上面的DLL链接, 所以尽量不要用纯静态链接运行时库. 

4. 如果确实发生了冲突, 一般是libcmdd.lib或者libcmd.lib, 链接器->输入:忽略的库, 把这个libcmdd.lib(或libcmd.lib, 对应debug和release)填上.

5. 动态库需要导出符合, 也就是类和函数需要在前面加一个__declspec(dllexport), 否则外部是看不到的. 但是因为头文件一般既是库编译使用的也是外边引用时引用的, 外部引用时候又需要把这个符合换成__declspec(dllimport), 所以一般是用一个宏来代替, 然后利用宏判断是库本身还是外部引用, 重新定义宏是导出还是导入.

6. 模版函数和类在动态链接库不适用上述规则, 模版类和函数实际上肯定是在使用的程序里, 而不是生成的dll里, 但是同样的没有导出符合, 这个类外部就不可用, 而在使用的时候 __declspec(dllimport)又会出错, 因为它根本不在库里面, 无法从库导入. 解决办法是定义一个新的宏, 模版使用这个宏,
而把这个宏不论在库内部还是外部都定义成__declspec(dllexport).

7. 静态变量, 静态变量在动态库里没有什么特别的, 整个进程只有一个实例. 但是对于静态库, 问题就来了, 静态库本质上只是代码,
如果我们写了一个dll使用了另一个静态库的一个静态变量(包括函数内部的), 那么这静态变量就在这个dll内部有一个实例, 非常可能的, 引用这个dll的应用程序也使用了那个静态库, 而这时候, 静态变量会在应用程序里也有一个实例, 静态库本质就是拷贝代码, 这很自然, 应该是这样. 但是这时候, 尽管dll和应用程序调用的是静态库的同一个函数或者使用的同一个静态变量, 实际上他们各自有一个实例, 而非同一个, 这往往不是我设计这个静态变量的本意, 我们希望整个程序它们是同一个, 但是事实上, 确实无法解决这个问题,
如果有这种交叉引用的静态库, 最好不要使用静态变量, 虽然这可能导致整个程序和库需要重新设计. 

8. 静态库很干净高效, 不用考虑dll的诸多特殊的地方, 看上去更好用, 但是静态库最严重的问题是, 它可能也使用了别的库,
那么他发布的时候也要把他使用的库也带上, 这一下子就把问题搞的异常复杂了, 现代应用往往使用多个库, 发布一个库还要带上其它库, 而用户也可能使用了这些库, 就有可能发生版本冲突. 所以静态库适合简单的, 没有使用其它库的原生组件, 对于复杂的大型库交叉引用了很多其它库的情况, 动态库更好.

抱歉!评论已关闭.