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

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

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

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

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

在这里插入图片描述

静态库

  • 函数和数据被编译进一个二进制文件(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导出区别以及示例

Windows

库文件形式

动态库:.lib + .dll

静态库:

符号可见性

默认隐藏所有符号,除非显式地使用 __declspec(dllexport) 来标记为导出。=》优化链接和加载过程,减少导出符号表的大小,提高性能。

符号导入

__declspec(dllimport)

不是必需的,链接器在没有显式导入声明的情况下也可以解析出符号来。显示导入,可帮助编译器优化调用过程。

MacOS\Linux

库文件形式:.dylib。

符号导入

在 Unix-like 系统中,链接共享库时通常不需要特别声明从哪里导入符号。

符号可见性

macOS 和 Linux 等 Unix-like 系统不需要像 Windows 显式导出和导入符号。在 Unix-like 系统中,当编译一个共享库时,默认情况下所有符号(函数、变量等)都是可见的,即它们都是自动导出的。

显示设置
#if __GNUC__ >= 4           // GCC版本
#define DLL_PUBLIC __attribute__ ((visibility ("default")))
#define DLL_LOCAL  __attribute__ ((visibility ("hidden")))
#else
#define DLL_PUBLIC
#define DLL_LOCAL

MYLIBRARY_API void MyFunction();

优势:

  1. 隐藏内部符号和减少库的符号表尺寸。动态库装载和识别的符号越少,程序启动和运行的速度就越快。导出所有符号会减慢程序速度,并耗用大量内存。
  2. 有助于提升性能和防止符号冲突。
  3. 保持代码的可移植性。

动态库 .lib、.dll

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

调用方式

方法1:在vs中导入

请添加图片描述

方法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
}

方法3:

#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"
  • 3
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值