QT动态库 & 静态库介绍及使用

文章目录

  • 动态链接库Dynamic Link VS 静态链接库 Static Link
    • 静态库
    • 动态库
  • 导出dll
    • 使用`_declspec(dllexport)`
    • 使用Def(模块定义)文件
    • warning
  • 动态库 .lib、.dll
    • 调用方式
      • 方法1:在vs中导入
      • 方法2:在对应的.pro文件中写入
      • 方法三:
  • visual studio运行时库MT、MTd、MD、MDd区别
  • Problem
    • #error: Building MFC application with /MD[d] (CRT dll version) requires MFC shared dll version. Please #define _AFXDLL or do not use /MD[d]
      • 方案1:修改vs中配置项
      • 方案2:在引入库的.h文件的上方加入`#define _AFXDLL`

动态链接库Dynamic Link VS 静态链接库 Static Link

https://zhuanlan.zhihu.com/p/71372182

https://www.cnblogs.com/skynet/p/3372855.html

  • 目标程序通常都不是独立个体,生成程序时都需要链接其他的库,用到其他库的代码。
  • 某些代码需要给别人使用,但是我们不希望别人看到源码,就需要以库的形式进行封装,只暴露出头文件。
  • 对于某些不会进行大的改动的代码,我们想减少编译的时间,就可以把它打包成库(因为库是已经编译好的二进制了,编译的时候只需要 Link 一下,不会浪费编译时间)。

QT动态库 & 静态库介绍及使用_第1张图片

静态库

  • 函数和数据被编译进一个二进制文件(windows:.LIB;Linux:)。
  • 在编译链接可执行文件.exe时,链接器从库中复制这些函数和数据,并把它们和应用程序的其他模块组合起来创建最终的可执行文件。当发布产品时,只需要发布这个可执行文件,并不需要发布被使用的静态库。

动态库

在使用动态库的时候,编译后往往提供两个文件:一个引入库(.lib)文件(也称“导入库文件”)和一个DLL(.dll)文件。当然到了后面会告诉你如果只提供一个DLL文件,使用显示连接的方式也可以调用,只是稍加麻烦而已。

虽然引入库的后缀名也是“lib”,但是,动态库的引入库文件和静态库文件有着本质的区别。对一个DLL文件来说,其引入库文件(.lib)包含该DLL导出的函数和变量的符号名,而.dll文件包含该DLL实际的函数和数据。在使用动态库的情况下,在编译链接可执行文件时,只需要链接该DLL的引入库文件,该DLL中的函数代码和数据并不可复制到可执行文件,直到可执行程序运行时,才去加载所需的DLL,将该DLL映射到进程的地址空间中,然后访问DLL中导出的函数。这时,在发布产品时,除了发布可执行文件以外,同时还需要发布该程序将要调用的动态链接库。

只有当EXE程序确实要调用这些DLL模块的情况下,系统才会将它们装载到内存空间中。这种方式不仅减少了EXE文件的大小和对内存空间的需求,而且使这些DLL模块可以同时被多个应用程序使用。如果DLL不在内存中,系统就将其加载到内存中。当链接Windows程序以产生一个可执行文件时,你必须链接由编程环境提供的专门的 “引入库(import library)”。这些引入库包含了动态链接库名称和所有Windows函数调用的引用信息。链接程序使用该信息在.EXE文件中构造一个表,当加载程序时,Windows使用它将调用转换为Windows函数。

导出dll

使用_declspec(dllexport)

_declspec(dllexport) int add(int a, int b);

缺点:存在函数名字被编译器转换的问题(区别重名程序)。同一个编译器版本的c++程序调用该dll是没有问题的。但其它语言的程序(如C#、VB)调用该dll则会出错。因为在C++中存在函数的重载,允许函数重名,因此在编译器生成dll的时候,为了区别重名的程序,会进行名称转换。我们直接通过函数名是无法找到该函数的,从而导致调用失败。
例如,对于前面的add函数,实际的函数名称是如下形式:
在这里插入图片描述
为了解决这一问题,我们往往在函数前面再加一个extern "C",使用C方式的函数命名规则。

 extern "C" _declspec(dllexport) int add(int a, int b);

在这里插入图片描述

使用Def(模块定义)文件

在项目中添加一个**.def文件**,然后把要导出的函数放在def文件中。

warning

一般C/C++默认的调用方式是__cdecl,这种方式下需要调用方对函数清栈。如果对外提供api共其它非C++程序使用时,应将接口声明为__stdcall,让api函数自己清栈,否则调用方会无法清栈而出错(C#会直接报函数声明不匹配的错误)。因此,对外提供api时还。这也是Windows API前面都加上了一个WINAPI的宏的原因。

def文件导出和_declspec导出区别以及示例

动态库 .lib、.dll

.lib称为导入库,相当于头文件;.dll是动态库文件,相当于cpp,头文件中函数的具体实现。

调用方式

方法1:在vs中导入

QT动态库 & 静态库介绍及使用_第2张图片

方法2:在对应的.pro文件中写入

INCLUDEPATH += $$PWD/ \
    $$PWD/../3rd_part/Include \
    $$PWD/../3rd_part/Include/opencv2
DEPENDPATH += $$PWD/ \
    $$PWD/../3rd_part/Include \
    $$PWD/../3rd_part/Include/opencv2

CONFIG(debug, debug|release){
    contains(TARGET_ARCH, x86_64){
            DESTDIR += $$PWD/../bin/Debug/64
    }else{
            
            DESTDIR += $$PWD/../bin/Debug/32
    }
    TARGET = Functiond
    LIBS += -L$$PWD/../3rd_part/Lib/Debug -lopencv_world455d
} else {
    contains(TARGET_ARCH, x86_64){
            
            DESTDIR += $$PWD/../bin/Release/64
    }else{
            
            DESTDIR += $$PWD/../bin/Release/32
    }
    TARGET = Function
    LIBS += -L$$PWD/../3rd_part/Lib/Release -lopencv_world455
}

方法三:

#ifdef _DEBUG
#pragma comment(lib,"../3rd_part/Lib/Debug/Qt5Pdfiumd.lib")
#else
#pragma comment(lib,"../3rd_part/Lib/Release/Qt5Pdfium.lib")
#endif

visual studio运行时库MT、MTd、MD、MDd区别

  • MT:mutithread,多线程库,编译器会从运行时库里面选择多线程静态连接库来解释程序中的代码,即连接LIBCMT.lib库
  • MTd:mutithread+debug,多线程调试版,连接LIBMITD.lib库
  • MD:MT+DLL,多线程动态库,连接MSVCRT.lib库,这是个导入库,对应动态库为MSVCRT.dll
  • MDd: MT+DLL+debug,多线程动态调试库,连接MSVCRTD.lib库,对应动态库为MSVCRTD.dll

对于MT/MTd,由于连接运行时库是LIBCMT.lib/LIBCMTD.lib,这两个库是静态库,所以此种方式编译的程序,移到另一台机器上面也可以正常运行。
但是对于MD/MDd,连接的是动态库,所以如果另一台机器上没有MSVCRT.dll/MSVCRTD.dll时,就提示缺少动态库这样的错误。
曾经犯这样的错误,以为以MT/MTd方式编译,程序对所有的库都是静态链接的,其实错了,它只能决定运行时库是动态链接还是静态链接,对用户自己写的库或其他第三方库,其连接方式取决于代码(显式连接动态库Loadlibrary)或所提供的lib文件(为导入库还是静态库),移动程序到别的机器上时,还是要带上所需要的动态库的。

https://www.cnblogs.com/ShaneZhang/p/3480502.html

Problem

#error: Building MFC application with /MD[d] (CRT dll version) requires MFC shared dll version. Please #define _AFXDLL or do not use /MD[d]

方案1:修改vs中配置项

方案2:在引入库的.h文件的上方加入#define _AFXDLL

#define _AFXDLL
#include "../3rd_part/Include/xxx.h"

你可能感兴趣的:(C++\QT,qt)