【手把手教学】VS2013 C++建立QT动态链接库
本文仅梳理总结自己在学习过程中的一些理解和思路,水平有限,理解粗鄙浅薄且不一定正确。文章所有观点均不保证绝对正确,请酌情参考。如果各位朋友发现任何错误请及时告诉我,大家一起讨论共同提高。
动态链接库
写在前面(可以跳过)
本文其实本质上是写给自己的备忘录,如果我不尽可能详尽地记录下操作流程和细节步骤,我不到俩星期就会忘得干干净净。
链接
C代码编译生成可执行程序的过程如下图所示:
(图片来自知乎专栏)
链接就是把目标文件与一些库文件生成可执行文件的一个过程,它所解决的问题即是将我们自己写的代码和别人写的库集成在一起。
链接,动态链接库和静态链接库
库
库是写好的现有的,成熟的,可以复用的代码。现实中每个程序都要依赖很多基础的底层库,不可能每个人的代码都从零开始,因此库的存在意义非同寻常。本质上来说库是一种可执行代码的二进制形式,可以被操作系统载入内存执行。库有两种:静态库(Windows下以.lib为后缀,Linux下以.a为后缀)和动态库(Windows下以.dll为后缀,Linux下以.so为后缀,特别的,在Windows下的动态链接也可以用到.lib为后缀的文件,但这里的.lib文件叫做导入库,是由.dll文件生成的)。
(图片来自博客)
静态链接库
在生成可执行文件的时候(链接阶段),把所有需要的函数的二进制代码(静态库)都(通过拷贝的方式)包含到可执行文件中去,这样,在程序发布的时候就不需要的依赖库,也就是不再需要带着库一块发布,程序可以独立执行。
动态链接库
在编译的时候不直接拷贝可执行代码,而是通过记录一系列符号和参数,在程序运行或加载时将这些信息传递给操作系统,操作系统负责将需要的动态库加载到内存中,然后程序在运行到指定的代码时,去共享执行内存中已经加载的动态库可执行代码,最终达到运行时连接的目的。使用动态链接的多个程序可以共享同一段代码,而不需要在磁盘上存储多个拷贝。不同编程语言编写的程序只要按照函数调用约定就可以调用同一个DLL函数。DLL文件与EXE文件独立,只要输出接口不变(即名称、参数、返回值类型和调用约定不变),更换DLL文件或更改其内容不会对EXE文件造成任何影响。
- 静态链接发生在编译过程中,形成可执行程序前,而动态链接把链接这个过程推迟到了运行时再进行
- 静态链接相当于拷贝库文件到工程中,执行速度快,体积大,可能会包含大量重复代码;动态链接不拷贝库文件内容,体积小,开发过程独立、耦合度小,复用程高。
- 使用静态链接的程序在运行时与函数库再无瓜葛,移植方便;但使用动态链接库的应用程序不是自完备的,它要求用户设备上要存在其所依赖的DLL模块才能正常运行。
- 静态链接库更新,则每个使用该静态库的程序都需要更新,不易于更新升级;动态链接库仅更新自身,易于更新升级
- 静态链接库不能再包含其他动态链接库;动态链接库可以包含其他动态链接库
那么接下来,在经过了一如既往漫长的前摇之后,终于进入正题了。
创建QT Library
在VS中,我们创建一个新的QT Library。可以看到,QT Library的扩展名为dll,即QT Library是一个动态链接库。
新建过程中要选中预编译头文件
新建好的工程中默认地自动生成了三个.h文件,其中,带有关键词_global的头文件中define了关于export和import的两个关键词,在构建允许被其他工程调用的类时需要加入词关键词。
在此解决方案中,我们可以构建属于自己的库。右键解决方案选择添加类可以向我们的库中新建类。
新建类后,需要在类的声明中加入库工程名(全大写)_EXPORT(库工程名_global.h中define的关键词)同时要包含头文件库工程名_global.h使其能够被其他工程引用。
#pragma once
#include "testdll_global.h" //包含头文件库
class TESTDLL_EXPORT test1 //加入关键词
{
public:
test1();
~test1();
};
调用动态链接库
当我们想在某个工程中调用动态链接库时
添加解决方案
在需要调用库的工程中将动态库的解决方案添加进来
添加好之后,右侧边栏会出现库文件的资源目录
添加引用
在需要使用该动态链接库的工程上右击->添加->引用
注意这一步和上一步的区别
添加新引用
这里应该就可以看到我们之前添加的库了,勾选即可
勾选后点击确定,会自动回到属性页,选择配置属性->C/C+±>常规->附加包含目录->编辑->新建,将…\testDLL\testDLL添加进目录。也可以点击三个点的图标选择路径
配置属性->链接器->常规->附加库目录->编辑->新建,添加库工程win32文件夹下的debug文件(…\testDLL\Win32\Debug)
配置属性->链接器->输入->附加依赖项->编辑->新建 加入动态链接库的名称
至此就可以使用该动态链接库的EXPORT类。
只需要包含需要使用的类的头文件就可以使用该类了
一些说明
如果你快乐地按照上面的步骤走了一遍,快乐地点下编译之后,程序能够顺利都成功生成解决方案,快乐地点击运行还能正常执行,那么祝贺你,你就是一发入魂一次成功的幸运大宝贝。
然而,更多的可能是,你会发现,哦嚯,打妹,有问题。
我在尝试以上步骤的时候遇到的错误有以下三个,我将问题分析和解决方案写在这里(没错我的意思是我只遇到过这三种其他的问题你来问我也不会 😄)如果各位i大佬遇到了新的问题(并找到了解决方案),欢迎在评论区补充,我看到就会编辑到正文里。
无法打开qglobal.h
我们新建的库文件为QT library,包含了QtCore的一些头文件,在调用的过程中,若调用此库的工程,需要配置添加QtCore的路径
打开工程内库文件的属性页,查看其配置属性->C/C+±>常规->附加包含目录,配置属性->链接器->常规->附加库目录,配置属性->链接器->输入->附加依赖项三个位置的内容,将其中与QtCore相关的路径添加到工程属性页的相同位置。
(我的库名为test DLL,工程名为KNN)
同理,链接器->常规和链接器->输入的目录页进行同样的操作
修改完之后,再次生成解决方案,哦吼,还是打妹,甚至错误信息都没有变 😄。
仍然无法打开说明我们的路径配置没有生效,再次回来看我们配置的路径信息,我们发现,其中包含环境变量$(QTDIR)。那么根据经验,多半问题就出在环境变量上。VS中使用的环境变量通常是在工程内部设立的,再另外一个工程中就失去了作用,我们把它添加到系统环境变量中,就可以自由地跨工程使用了。当然,这里也可以直接使用绝对路径。
添加系统环境变量后,再次运行,终于,错误信息变化了 😄
无法打开.dll文件
解决方法是在knn的属性页,配置属性->C/C+±>常规->附加包含目录中添加库工程的输出目录。如果使用库的工程和库在同一文件夹下,则不需要这一步
找不到.dll文件
解决方法同上,只不过这一步报错是在运行过程中出现的。
最后,错误之处,希望各位大佬不吝赐教。