QT 静态链接库和动态链接库

qt       windows            linux

dll          .dll                       .so

lib 对应 a    archiver的缩写 为静态库,是好多个.o合在一起,用于静态连接

dll 对应 so   share object 共享库      

lib文件:(依据编译器)    MSVC编译器是生成.lib 文件,文件名不变。 mingw编译器生成.a 文件,此外会在目标名称(即在.pro 文件中的TARGET)前面加lib

dll文件:(依据平台)   windows平台是.dll 文件,unix平台是.so  ,mac是.dylib

背景

在vs的mfc环境中:

设置x.dll 输出路径方法是在右键项目的"属性"->链接器->常规, 然后在常规属性界面中的 "输出文件" 中填入自己想要x.dll文件的输出路径.

设置x.lib 输出路径方法是在右键项目的"属性"->链接器->高级, 然后在高级属性界面中的 "导入库" 项中填入自己想要x.dll文件的输出路径.

设置x.pdb 输出路径方法是在右键项目的"属性"->链接器->调试, 然后在高级属性界面中的 "生成程序数据库文件" 项中填入自己想要x.pdb文件的输出路径.

在qt环境中

.pro文件通过宏DESTDIR设置生成的dll(或者so)文件,lib(或者a)文件。

另外可以通过DLLDESTDIR设置生成的dll(或者so)文件,但dll(或者so)文件在DESTDIR路径还保留有一份。

创建链接库

静态链接库

设计导出类,包括ui窗口类,对话框类。

在.pro文件中

TEMPLATE = lib
CONFIG += staticlib

TARGET = 

编译静态链接库时,不管是debug还是release版本,编译生成都是相同的文件名,并不会为debug版本自动添加一个字母“d”.

但是在debug或者release版本编译应用程序时,需要使用相应版本库文件。所有需要手动将debug版本的静态库更名,即在文件名后加上字母“d”,如 myStaticLib.lib => myStaticLibd.lib .

使用静态库方法是:

1.在应用程序的源程序目录下新建一个include文件夹,把.h头文件和.lib静态链接库文件都拷贝过去。

2.在项目管理目录树右键,选择“add library”,选择库类型“external library”(即外部库),连接类型必须选择"static",因为是静态库。

 勾选add "d"suffix for debug version.使在debug模式下,应用程序自动调用debug版本的库文件。

共享库

1,共享库会多一个特殊的头文件 xxx_global.h。用来代替qt的宏 Q_DECL_EXPORT 和Q_DECL_IMPORT.

2.在定义的导出类名称前面多了在xxx_global.h定义过的宏,用于表明该类为导出类。

3,编译后会生成.dll文件和.lib文件。同样,不管是debug还是release版本,编译生成都是相同的文件名。

导出函数

直接在函数声明加上Q_DECL_EXPORT 表示导出函数。为了兼容不同mingw和msvc编译器,加上extern "C".   

在实际使用中,linux系统如果dll的导出函数没有加上extern "C",则exe程序调用resolve函数没法获取到函数符号,返回空指针。所以必须在导出函数前加上extern "C"。

#if defined(TESTDLL_LIBRARY)
#  define TESTDLLSHARED_EXPORT Q_DECL_EXPORT
#else
#  define TESTDLLSHARED_EXPORT Q_DECL_IMPORT
#endif

extern "C" int TESTDLLSHARED_EXPORT dev(int a, int b);

int dev(int n1, int n2)
{
    return n1 - n2;
}

//在exe include 该头文件,然后直接调用

导出类

在声明类加上Q_DECL_EXPORT 即可。

#if defined(TESTDLL_LIBRARY)
#  define TESTDLLSHARED_EXPORT Q_DECL_EXPORT
#else
#  define TESTDLLSHARED_EXPORT Q_DECL_IMPORT
#endif

class TESTDLLSHARED_EXPORT Testdll
{

public:
    Testdll();
    int add(int n1,int n2);
};


#include "testdll.h"

Testdll::Testdll()
{
}

int Testdll::add(int n1, int n2)
{
    return n1 + n2;
}

//在exe中include该头文件,定义导出类的对象,然后调用相应的函数。

注意:其实对类的导出,一般都是父类纯虚函数的实现。这样可以在不同mingw和msvc编译器中相互调用。

具体表现为:父类为导出类,该dll的类继承导出类。结果就是该dll的类可以使用导出类的函数,但自己本身就不是导出类,不能给其他dll调用。

 class MSCVDLLSHARED_EXPORT test
{
public:
     virtual int add(int a,int b) = 0;
};

 class  test1 :public test
{
public:
     int add(int a,int b) override;

};


 extern "C" MSCVDLLSHARED_EXPORT test* getInstance();
 extern "C" MSCVDLLSHARED_EXPORT void DeleteInstance(test*pInstance );


int test1::add(int a, int b)
{
    return  a + b;

}

test *getInstance()
{
    test *pInstance = new test1();
    return pInstance;
}


exe调用

    test *ptest = getInstance();
    int bb = ptest->add(1,4);
    DeleteInstance(ptest);


void DeleteInstance(test *pInstance)
{
    if(pInstance)
        delete pInstance;
}

使用共享库

隐式链接

1.在源程序目录下新建一个include文件夹,把2个.h头文件(即包括_global.h文件)拷贝过去。

2..在源程序目录下新建一个lib文件夹,把 .lib或者是.a库文件都拷贝过去。

3.在项目管理目录树右键,选择“add library”,选择库类型“external library”(即外部库),连接类型必须选择"dynamic",因为是动态库。在library file选中include目录下的.lib 或者.a文件作为库文件。

或者直接在.pro配置文件的LIBS +=添加上去。如 LIBS += $$PWD/lib/libPropertyBrowser.a  

4.必须将动态链接库文件.dll拷贝到可执行文件的的目录下,即pro 配置中的DESTDIR

显示链接

1. 显示链接通过QLibrary实现,一个QLibrary对象只能对一个共享库进行操作。一般在QLibrary构造函数中传递一个文件名,表示共享库文件。可以不用带后缀,因为可以通过平台自动识别。 

如 QLibrary myLib("DelphiDLL");

QLibrary 的load函数用于首动载入dll到内存,一般不需要手动调用,因为在dll的函数第一次被调用时QLibrary会自动调用此函数。isLoaded 判断dll 是否已经被载入内存,unload用于将dll从内存卸载。如果不调用卸载,那么只会在程序退出时才卸载。

一个动态链接库在内存只有一个实例,即使有多处调用了这个动态链接库里的函数,它也只是会被载入一次。

2 .声明函数原型类型

如 typedef int (*FunDef)(int); //函数原定定义

3. 使用QLibrary 的resolve函数解析需要调用的函数。resolve()用于解析库中的符号。如果库尚未加载,resolve()函数会隐式地尝试加载它

如 FunDef myTriple = (FunDef) myLib.resolve("triple"); //解析DLL中的函数  triple为在dll的函数名

4.调用函数

如 int V=myTriple(ui->spinInput->value()); //调用函数

注意事项

在windows系统上,mscv编译器的exe想调用mingw编译器的dll,需要在dll的导出函数或导出类声明为 extern "C" 如下:

dll 导出函数的声明及定义
extern "C" int MSCVDLLSHARED_EXPORT dev1(int a, int b);
int dev1(int a, int b)
{
    return  a - b;
}

导出的lib和dll为:mscvdll.lib 和mscvdll.dll


exe的.pro配置文件
LIBS += $$PWD/lib/mscvdll.lib



延伸:

DLL地狱

出类的DLL在维护和修改时有很多地方必需很小心,增加成员变量、修改导出类的基类等操作都可能导致意想不到的后果,也许用户更新了最新版本的DLL库后,应用程序就再也不能工作了。这就是著名的DLLHell(DLL地狱)问题。

主要原因

参看:DLL Hell(DLL地狱)浅谈_远行的风的博客-CSDN博客

  • 0
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值