一.创建动态链接库
这里注意是qmake,Qt的新版本会默认CMake
我们的第一种动态库通过C风格的导出文件去封装,这样做的好处是,调用库的时候不需要做太多的库链接设置,如.pro中添加一些内容,也可以提高库的隐蔽性,不对外展示类的结构,只提供调用的口
以下是动态库的代码
.pro
QT -= gui
TARGET = MyDll
DESTDIR = ..\Debug
TEMPLATE = lib
DEFINES += UNTITLED_LIBRARY
CONFIG += c++17
# You can make your code fail to compile if it uses deprecated APIs.
# In order to do so, uncomment the following line.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
SOURCES += \
ExportDll.cpp \
untitled.cpp
HEADERS += \
ExportDll.h \
untitled_global.h \
untitled.h
# Default rules for deployment.
unix {
target.path = /usr/lib
}
!isEmpty(target.path): INSTALLS += target
untitled_global.h
#ifndef UNTITLED_GLOBAL_H
#define UNTITLED_GLOBAL_H
#include <QtCore/qglobal.h>
#if defined(UNTITLED_LIBRARY)
#define UNTITLED_EXPORT Q_DECL_EXPORT
#else
#define UNTITLED_EXPORT Q_DECL_IMPORT
#endif
#endif // UNTITLED_GLOBAL_H
untitled.h
#ifndef UNTITLED_H
#define UNTITLED_H
class Untitled
{
public:
Untitled();
void MyActive();
};
#endif // UNTITLED_H
untitled.cpp
#include "untitled.h"
#include <QDebug>
Untitled::Untitled() {}
void Untitled::MyActive()
{
qDebug() << "Hello dll";
}
ExportDll.h
#pragma once
#include "untitled_global.h"
#include "untitled.h"
extern "C" UNTITLED_EXPORT void MyActive();
ExportDll.cpp
#include "ExportDll.h"
void MyActive()
{
Untitled test;
test.MyActive();
}
二.调用动态链接库
常规创建一个Qt的工程的流程
以下是调用库的代码
.pro
CONFIG += c++17
# 这里直接将exe文件生成在Debug目录下和刚刚动态库一个路径,这样加载库的时候就直接通过相对路径加载
DESTDIR = ..\Debug
# You can make your code fail to compile if it uses deprecated APIs.
# In order to do so, uncomment the following line.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
SOURCES += \
main.cpp \
Demo.cpp
HEADERS += \
Demo.h
FORMS += \
Demo.ui
# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target
Demo.h
#pragma once
#include <QDialog>
#include <QLibrary>
QT_BEGIN_NAMESPACE
namespace Ui {
class CDemo;
}
QT_END_NAMESPACE
class CDemo : public QDialog
{
Q_OBJECT
public:
CDemo(QWidget *parent = nullptr);
~CDemo();
private:
bool LoadDll();
bool Resolve(const QString& sFuncName, QFunctionPointer& pfFunc);
void MyActive();
private:
Ui::CDemo *ui;
QLibrary m_lib;
};
Demo.cpp
#include "Demo.h"
#include "ui_Demo.h"
#include <QDebug>
#pragma execution_character_set("utf-8")
typedef void (*pfMyActive)();
CDemo::CDemo(QWidget *parent)
: QDialog(parent)
, ui(new Ui::CDemo)
{
ui->setupUi(this);
if (m_lib.isLoaded())
return;
if (!LoadDll())
return;
MyActive();
}
CDemo::~CDemo()
{
delete ui;
}
bool CDemo::LoadDll()
{
QString sPath = QCoreApplication::applicationDirPath(); // exe文件所在路径
sPath += "/MyDll.dll"; // 动态库的名字
m_lib.setFileName(sPath);
return m_lib.load();
}
bool CDemo::Resolve(const QString &sFuncName, QFunctionPointer &pfFunc)
{
if (!m_lib.isLoaded())
{
return false;
}
pfFunc = m_lib.resolve(sFuncName.toStdString().c_str());
if (nullptr == pfFunc)
{
qDebug() << QString("CDemo::Resolve: Failed to resolve function:%1 %2").arg(sFuncName).arg(m_lib.errorString());
return false;
}
return true;
}
void CDemo::MyActive()
{
QFunctionPointer pfFunc = nullptr;
if (!Resolve("MyActive", pfFunc))
return;
((pfMyActive)pfFunc)();
}
运行后的效果
如果一个Qt Creator同时打开了库的工程和调用库的工程,那么通过断点可以进入库中的函数查看对应数据的信息
三.认识动态链接库的后缀名
1、 .dll (Dynamic-Link Library)
1>用途: 动态库(Dynamic Library)
2>操作系统: Windows
.dll 文件是Windows操作系统下的动态链接库。动态库在运行时被加载到内存中,允许多个程序共享相同的库代码,从而节省内存。
2、 .lib
1>用途: 静态库(Static Library)或导入库(Import Library)
2>操作系统: Windows
在Windows上,.lib 文件有两种用途:一种是静态库,直接将库的代码编译到应用程序中;另一种是导入库,用于在编译时链接动态库(.dll 文件),导入库包含动态库的符号信息而不是实际代码。
3、 .a
1>用途: 静态库(Static Library)
2>操作系统: Unix-like系统(如Linux、macOS)
.a 文件是Unix-like系统下的静态库。静态库在编译时被链接到应用程序中,从而在运行时不需要外部库的支持。
4、 .so (Shared Object)
1>用途: 动态库(Dynamic Library)
2>操作系统: Unix-like系统(如Linux)
.so 文件是Unix-like系统下的动态库。与Windows的.dll类似,.so文件在运行时被加载到内存中,多个程序可以共享这些库文件。
四.如何选择库类型
静态库: 如果你希望所有的库代码都包含在应用程序的可执行文件中,且不希望在运行时依赖外部库,可以使用静态库(.lib 或 .a)。这通常会导致较大的可执行文件,但部署较为简单,因为不需要额外的库文件。
动态库: 如果你希望多个应用程序共享同一套库代码,从而节省内存和磁盘空间,可以使用动态库(.dll 或 .so)。这通常会使得应用程序的可执行文件较小,但需要在运行时确保动态库可用。
五.在Qt中生成库
可以通过一开始建立工程的时候去配置,但这些本质上都是在.pro中添加信息,那么这里直接可以通过修改项目文件(.pro 文件)中的配置来实现。例如:
静态库:
TEMPLATE = lib
CONFIG += staticlib
动态库:
TEMPLATE = lib
CONFIG += dll