最近在win32平台下封装MySQL的客户端C API时,出现的问题着实让我头痛了个把小时,不过多亏这一来,我终于明白了静态库是怎样链接的,结合了以前我对动态库与静态库之间进行比较的一些测试结论,也明白了为什么静态库需要这样的设计。不由感叹一下古人的那句话:“挫折果真是成功的母亲。”(好大雾^_^!)
闲话不多说,记录一些关键点,首先是静态链接到底和动态链接有哪些不太容易发现的区别呢?我来假设libA依赖libB,那么我的执行文件在使用libA的时候也需要导入libB才能正确链接,但若dllA依赖libB的话,则只需导入dllA就可以。我在一开始用MySQL时使用的内嵌数据库模式,所以导入的是那个libmysql.dll动态库,因此没出现问题。而换上了mysqlclient.lib后,居然告诉我没有找到socket相关的实现,即“无法解析的外部符号”这类错误,于是乎我只有加上ws2_32.lib库才能通过。
为什么这样设计?原因其实跟静态库的连接方式有关,由于静态库直接将函数实现和全局静态变量导入到包含它的执行体中,所以在多层多重的库包含中就会有大量重定义的问题存在,想想你在一个静态库中用了单件模式,那么其他库又包含你这个库,最后exe又包含所有这些库,最终形成菱形依赖,如果静态库不这样设计的话,问题就会像C++的多重继承问题一样。之所以静态库这样设计,跟C++的虚拟继承思想简直如出一辙。(我知道这段话其实只有已经懂了的人才能看得懂,不过没办法,我表达能力挺笨的...)
还有个极度郁闷的地方是:mysqlclient.lib中的libcmtd.lib和msvcrtd.lib这对活宝居然也被链接进去了,我这边首先需要忽略这两个默认库,然后再包含msvcrtd.lib才可以。我不知道为啥sdk提供的静态库非得在c runtime link的方式上跟一般人过不去,又懒得去自己编译,哎!将就一下就这么用吧......