Qt 静态库和共享库创建以及使用

一、程序编译过程

 

二、静态库创建和使用

1、新建Mainwindow项目,写一个定时器做测试

a).h

 b).cpp

 1 #include "staticclass.h"
 2 #include "ui_staticclass.h"
 3 #include<QTimer>
 4 
 5 staticClass::staticClass(QWidget *parent)
 6     : QMainWindow(parent)
 7     , ui(new Ui::staticClass)
 8 {
 9     ui->setupUi(this);
10     steps = 0;
11 
12     timer = new QTimer();
13     connect(timer, &QTimer::timeout, this, &staticClass::updateTime);
14 }
15 
16 staticClass::~staticClass()
17 {
18     if(timer)
19     {
20         delete timer;
21         timer = nullptr;
22     }
23     delete ui;
24 }
25 
26 
27 void staticClass::on_btnStart_clicked()
28 {
29     timer->start(500);
30 }
31 
32 void staticClass::updateTime()
33 {
34     ++ steps;
35     ui->lcdNumber->display(QString::number(steps));
36 }
37 
38 void staticClass::on_btnStop_clicked()
39 {
40     timer->stop();
41 }
.cpp

c)运行

 

2、生成静态库

a)创建库项目,注意选择库选项,别选成共享库了

 

 b)将生成的定时器.h/.cpp/.ui文件拷贝至库项目文件夹内,替换掉它的.h/.cpp文件,并加载.ui文件

c)修改.pro文件,因为使用了QMainwindow类,属于widgets

在.pro文件中添加  QT += widgets

d)分别构建库项目的Debug文件夹和Release文件夹,并把两个文件中的.lib文件拷贝出来,其中Debug文件夹的.lib记得在末尾添加d

例如:staticClass.lib 改成staticClassd.lib,最后再把库文件夹的.h(其实也是定时器的.h)拷贝出来,总共3个文件

 

3、使用静态库

a)创建新的QMainwindow项目,ui界面中拖拽一个widget框,在项目目录下将上一步的2个.lib文件和.h放入新建文件夹lib

b)添加静态库

 

 

 .lib选第一个即可,最后.pro新增如下

c)修改QMainwindow的.h文件

 d)修改QMainwindow的.cpp

 e)运行

 

 三、共享库生成和隐式链接调用

1、生成共享库

a)生成库项目,Type选择Shared Library

 b)将定时器的.h/.cpp/.ui拷贝至库目录,加载进去(不要在意类名,定时器项目请看静态库第一步)

 c).pro增加QT += widgets,复制库目录原生的.h中的宏(该宏来自xxx_global.h),粘贴至定时器的.h

 d)库目录.h文件添加QString Str() 函数成员,用于做测试(不做测试可以把库文件的.h和.cpp删掉,但是必须保留库_global.h)

 

 e)分别构建库项目的Debug文件夹和Release文件夹,并把两个文件中的.lib和dll文件拷贝出来,其中Debug文件夹的.lib记得在末尾添加d

例如:staticClass.lib 改成staticClassd.lib,最后再把库文件夹的两个.h和定时器的.h)拷贝出来,总共7个文件(当然,也可以把库文件.h删掉)。

PS:也可以将库_global.h定义代码拷贝出来,放到其他.h文件中,那就能减少一个文件,这里依旧留下。

xxxd.lib(Debug)

xxx.lib(Release)

xxx.dll(Debug)

xxx.dll(Release)

库.h

库_global.h

定时器.h

 

2、使用共享库

a)创建新的QMainwindow项目,ui界面中拖拽一个widget框,在项目目录下将上一步的.lib文件和.h放入新建文件夹ShareLibImplicit(共5个)

 b)添加动态库

 

 

 

.lib选第一个即可,最后.pro新增如下

 c)修改QMainwindow.cpp(头文件不需要添加XXX_global.h)

 1 #include "mainwindow.h"
 2 #include "ui_mainwindow.h"
 3 #include<QHBoxLayout>
 4 #include"ShareLibImplicit/sharedlib_implicit.h"    // 库测试类头文件
 5 #include"ShareLibImplicit/staticclass.h"    // 定时器类头文件
 6 #include<QDebug>
 7 
 8 MainWindow::MainWindow(QWidget *parent)
 9     : QMainWindow(parent)
10     , ui(new Ui::MainWindow)
11 {
12     ui->setupUi(this);
13     staticClass * sc = new staticClass(this);    //  定时器类
14     QHBoxLayout *layout = new QHBoxLayout(ui->widget);
15     layout->addWidget(sc);
16     ui->widget->setLayout(layout);
17 
18     SharedLib_implicit s;    //  库测试类
19     qDebug()<< s.Str();
20 }
21 
22 MainWindow::~MainWindow()
23 {
24     delete ui;
25 }
.cpp

d)构建项目Debug和Release文件夹,并将

xxx.dll(Debug)

xxx.dll(Release)

分别拷贝至对应的Debug和Release文件夹中

e)运行,可以看到定时器类生成成功,库测试类也打印成功

 

四、共享库生成和显示链接调用

1、生成共享库(参考三的生成共享库)

a)一样

b)一样

c)一样

d)修改文件,其中sharedlib_implicit为库文件,staticclass为定时器文件

 修改sharedlib_implicit.h,其中

Q_DECL_EXPORT  代表输出

Q_DECL_IMPORT  代表输入

extern  全局声明不能在类内部使用

extern "C" Q_DECL_EXPORT  生成一个连接外部的函数链接

 

Q_DECL_EXPORT和Q_DECL_IMPORT程序会根据调用情况,选择其中一个来替代。

 1 #ifndef SHAREDLIB_IMPLICIT_H
 2 #define SHAREDLIB_IMPLICIT_H
 3 
 4 #include<QWidget>
 5 
 6 /** @details 将global.h文件内容拷贝过来*/
 7 #if defined(SHAREDLIB_IMPLICIT_LIBRARY)
 8 #  define SHAREDLIB_IMPLICIT_EXPORT Q_DECL_EXPORT
 9 #else
10 #  define SHAREDLIB_IMPLICIT_EXPORT Q_DECL_IMPORT
11 #endif
12 
13 class SHAREDLIB_IMPLICIT_EXPORT SharedLib_implicit
14 {
15 public:
16     SharedLib_implicit();
17     QString Str();
18 };
19 
20 extern "C" Q_DECL_EXPORT int add(int a, int b);
21 #endif // SHAREDLIB_IMPLICIT_H
sharedlib_implicit.h

修改sharedlib_implicit.cpp

修改staticclass.h,创建一个函数和虚函数,用于测试,再创建一个外部链接函数,用于调用定时器函数

 1 #ifndef STATICCLASS_H
 2 #define STATICCLASS_H
 3 
 4 #include <QMainWindow>
 5 
 6 #if defined(SHAREDLIB_IMPLICIT_LIBRARY)
 7 #  define SHAREDLIB_IMPLICIT_EXPORT Q_DECL_EXPORT
 8 #else
 9 #  define SHAREDLIB_IMPLICIT_EXPORT Q_DECL_IMPORT
10 #endif
11 
12 QT_BEGIN_NAMESPACE
13 namespace Ui { class staticClass; }
14 QT_END_NAMESPACE
15 
16 class SHAREDLIB_IMPLICIT_EXPORT staticClass : public QMainWindow
17 {
18     Q_OBJECT
19 
20 public:
21     staticClass(QWidget *parent = nullptr);
22     ~staticClass();
23     int mul1(int a);
24     virtual int mul2(int a);    //  虚函数
25 
26 
27 private slots:
28     void on_btnStart_clicked();
29     void on_btnStop_clicked();
30 
31 private:
32     void updateTime();
33 
34 private:
35     Ui::staticClass *ui;
36     QTimer * timer;
37     int steps;
38 };
39 
40 extern "C" Q_DECL_EXPORT  staticClass * createStaticClass(QWidget *parent = nullptr);
41 #endif // STATICCLASS_H
staticclass.h

修改staticclass.cpp

 e)分别构建库项目的Debug文件夹和Release文件夹,并把两个文件中dll文件拷贝出来,

再把staticclass.h拷贝出来,共3个文件,这里可能会有疑问,为什么不拷贝sharedlib_implicit.h,

等下会解答

 

2、使用共享库

a)创建新的QMainwindow项目,ui界面中拖拽一个widget框和一个按钮,构项目的Debug文件夹和Release文件夹,

把dll分别放入对应文件夹。把staticclass.h放入QMainwindow项目根目录

b)mainwindow.cpp添加头文件staticclass.h,按钮槽函数添加代码

 1 #include "mainwindow.h"
 2 #include "ui_mainwindow.h"
 3 #include<QHBoxLayout>
 4 #include<QDebug>
 5 #include <QLibrary>
 6 #include"staticclass.h"
 7 
 8 MainWindow::MainWindow(QWidget *parent)
 9     : QMainWindow(parent)
10     , ui(new Ui::MainWindow)
11 {
12     ui->setupUi(this);
13 }
14 
15 MainWindow::~MainWindow()
16 {
17     delete ui;
18 }
19 
20 
21 void MainWindow::on_pushButton_clicked()
22 {
23     typedef int (*Fun1)(int, int);  //  定义函数指针
24     typedef  staticClass* (*Fun2)(QWidget*);    
25     QLibrary myLib("sharedLib_implicit");    //  加载dll文件,可以不写后缀dll
26 
27     
28     if(myLib.load())
29     {
30         //  sharedLib_implicit.h的add函数
31         Fun1 num = (Fun1)myLib.resolve("add");
32         int n = num(3 ,4);
33         qDebug()<<QString::number(n);
34 
35         //  staticClass类调用
36         Fun2 s = (Fun2)myLib.resolve("createStaticClass");
37         staticClass* sc = s(this);
38         QHBoxLayout * layout = new QHBoxLayout(ui->widget);
39         layout->addWidget(sc);
40         ui->widget->setLayout(layout);
41 
42         //  mul1报错,因为没有使用虚函数
43 //        int m1 = sc->mul1(5);
44 //        qDebug()<<m1;
45         int m2 = sc->mul2(5);
46         qDebug()<<m2;
47     }
48 }
mainwindow.cpp

 c)运行效果

d)为什么要添加定时器的头文件staticclss.h,而库文件的头文件不需要添加sharedlib_implicit.h?

因为库文件里面没有使用到sharedlib_implicit的成员,只用到一个全局函数

而定时器staticclss类使用了成员函数,为了解析成员函数的结构和关系,必须用到staticclss.h。

e)为什么只有虚函数mul2不报错,函数mul1报错?

因为成员函数非虚时,其地址在程序编译时候就确定了,而共享库是动态链接的,无法知道其静态地址。

成员函数是虚函数时,程序编译会生成虚函数表,虚函数表每个元素都指向其中一个虚函数地址,虚函数表

是编译时地址就确定了,但是虚函数地址是运行时候确定的,即程序运行到虚函数才给虚函数分配地址。

 

五、静态库和共享库优缺点(转自:https://www.cnblogs.com/renzhuang/p/6661519.html

1 静态链接库的优点 

 (1) 代码装载速度快,执行速度略比动态链接库快; 

 (2) 只需保证在开发者的计算机中有正确的.LIB文件,在以二进制形式发布程序时不需考虑在用户的计算机上.LIB文件是否存在及版本问题。 

2 动态链接库的优点 

 (1) 更加节省内存并减少页面交换;

 (2) DLL文件与EXE文件独立,只要输出接口不变(即名称、参数、返回值类型和调用约定不变),更换DLL文件不会对EXE文件造成任何影响,因而极大地提高了可维护性和可扩展性;

 (3) 不同编程语言编写的程序只要按照函数调用约定就可以调用同一个DLL函数;

 (4)适用于大规模的软件开发,使开发过程独立、耦合度小,便于不同开发者和开发组织之间进行开发和测试。

3 不足之处

 (1) 使用静态链接生成的可执行文件体积较大,包含相同的公共代码,造成浪费;

 (2) 使用动态链接库的应用程序不是自完备的,它依赖的DLL模块也要存在,如果使用载入时动态链接,程序启动时发现DLL不存在,系统将终止程序并给出错误信息。而使用运行时动态链接,系统不会终止,但由于DLL中的导出函数不可用,程序会加载失败;速度比静态链接慢。当某个模块更新后,如果新模块与旧的模块不兼容,那么那些需要该模块才能运行的软件,统统撕掉。这在早期Windows中很常见。

 

六、总结

1、静态库需要.lib 和.h,Debug生成的.lib需要加d,.lib包含了.h和.cpp的链接关系及.cpp的内容。

2、共享库隐式链接调用需要.lib,.dll,.h文件。

3、共享库显然式链接调用需要.dll文件,.h文件看情况而定。显示调用类内成员函数,只能调用虚函数,因为

显示调用只能获得动态地址。

4、DLL 包含一个或多个已被编译、链接并与使用它们的进程分开存储的函数,为动态链接提供了一种方法,

DLL 还有助于共享数据和资源。多个应用程序可同时访问内存中单个DLL 副本的内容。DLL 是一个包含可由

多个程序同时使用的代码和数据的库。

 

posted @ 2020-11-14 23:36  补码  阅读(1015)  评论(0编辑  收藏  举报