【WIN32】CMake的学习总结 4——深入动态库

来源:互联网 发布:天心软件怎么用 编辑:程序博客网 时间:2024/06/05 21:55

上回讲述了CMake使用动态库与使用静态库之间并没有太大的区别,并讲述了学习期间碰到的问题:无法正确生成动态库DLL,导致使用动态库的test测试项目无法正确编译;

【 学习时遇到的疑问 】

既然已经include_directories指定头文件的搜索路径,头文件已经声明,使用动态库为毛还要lib中的声明?

声明在头文件是没错的,所以需要include_directories来指定头文件的搜索路径;但是lib也并不包含函数的声明,只是dll中的函数的列表而已,这一点我理解错了!
在此将动态库与静态库之间的区别做一个对比,分析错误的原因:
部分资料来自:http://www.cppfans.org/1394.html

动态库与静态库的对比

静态库lib

编译静态库:生成的是一个lib文件(static lib);

对于静态库lib的调用者:
编译时:链接使用lib文件(这个过程可以理解为:链接并把函数的实现一起打包进执行文件中)。
运行时:则不需要则不需要lib文件;

注:静态库的lib:里面其实就是源文件函数的实现;

动态库dll

动态库编译之后有3个文件:.dll,.lib(dynamic lib),.exp;
其中lib只是dll的附属品,是dll导出的函数列表文件

对于动态库dll的调用者:
编译时:需要lib文件,并将导出函数列表打包进可执行文件中,此过程并不需要dll文件;
运行时:需要dll文件,并根据导出函数列表动态链接dll文件,此过程不需要lib文件,但不能缺少dll文件,否则可执行文件无法执行;

往下继续对动态库dll作更深入的描述:

对于动态库dll的理解不能按照lib的思维去理解,lib只是个只编译但未链接的obj文件的集合而已;而dll是应用程序的扩展,属于半个可执行文件,只是它不能自己运行而已;既然如此,我们就不能好像lib那样去编译dll( so, 按照lib的方式编译dll,你知道为什么编译的动态库不完整了吧);

因此我们可以站在exe的角度去理解dll。
其实dll和exe是几乎完全一样的,唯一的不一样就是exe的入口函数式WinMain函数(console程序是main函数),而dll是DllMain函数,其他完全是一样的;

然而dll创建的过程也比较简单,唯一麻烦的就是需要定义导出函数接口

在此我们看到了dll的3个概念:导出的函数列表的文件(dynamic lib)导出函数接口入口函数,归纳起来实际就是:入口函数和导出函数2种;

入口函数:

在此就先不谈,有兴趣可访问以下地址:
http://wenku.baidu.com/link?url=Gv3rPd-c9x-tjhxn6AcgsTlHdDBf7gk4acL0-ZBKb99tNFUYt1dH-B-q_iZYxvwhGRMyvTS1dvQ4E3fyazNG0vWbqpQ4FFl3CuI45yo7tI_

导出函数:

导出函数:供调用dll的程序(如exe)使用,因此使用导出函数的列表文件(dynamic lib)可调用dll中所有导出的函数;

导出方式一:采用模块定义文件声明(.def)

  1. 文件第一句必须是LIBRARY语句。
    此语句将.def文件标识为属于dll,LIBRARY语句的后面是dll名称;连接器将此名称放到dll的到入库中;
  2. EXPORTS语句列出名称;
    可能的话还会列出dll导出函数的序号值。通过函数名的后面加上@符合一个数字,给函数分配序号值。
    当指定序号值时,序号值的范围必须是从1到N,其中N是dll倒数函数的个数。
  3. 注释语句:在语句前面加分好“;”
  4. 例子如下:
;DLLTest.def: Declares the module parameters for the dll.LIBRARY "DLLTest"EXPORTS    add @1    fun @2

导出方式二:_declspec(dllexport)导出方式
《【WIN32】CMake的学习总结 3——动态库》最后对xmath.h的修改,就是使用这种方式的;

为了防止名字改编,将extern “C” _declspec(dllexport)语句放在想导出函数的声明前面;
例如:extern “C” _declspec(dllexport) int add(int a, int b);

注:如果要进行函数的导入则dllexport换成dllimport即可,
例如:extern “C” _declspec(dllimport)

至此,我们已经找到上一回后面的提出的问题了!哈哈哈~~~~

上一回后面的提出的疑问如下:

  1. 为什么要作这样的修改才能正确编译动态库dll呢?
  2. 其中的奥妙是什么呢?
  3. 正确编译DLL动态库还有其他什么方法呢?
0 0