QT编译静态库与动态库

33 篇文章 4 订阅

目录

静态库说明

动态库说明

动态库隐式调用

动态库显式调用

在Linux下显式调用动态库

在Windows下显式调用动态库

显式调用C++动态库注意点

静态库调用


静态库说明

在链接阶段,会将汇编生成的目标文件.o与引用到的库一起链接打包到可执行文件中。静态库与.o文件格式相似,可以看成是一组目标文件(.o/.obj)的集合,即很多目标文件压缩后打包形成的一个文件。静态库特点:

I 静态库对函数库的链接是放在编译期完成的。

II 程序在运行时与函数库再无瓜葛,移动方便。

III 浪费空间和资源,因为所有的目标文件相当于拷贝进了可执行文件。

动态库说明

在编译时不会被链接到目标代码中,而是在程序运行时才被载入。不同的应用程序如果调用相同的库,那么在内存里只需要有一份该共享库的示例,规避了空间浪费问题(由此可以思考,为什么动态库又被称作共享库?)。动态库在程序运行时才会被载入,也解决了静态库对程序的更新、部署和发布带来的麻烦,只需要更新动态库即可,增量更新。动态库特点总结:

I 动态库把对库函数的链接推迟到程序运行时期。

II 可以实现进程之间的资源共享。

III 将程序的升级变得简单。

IV 甚至可以真正做到链接载入完全由程序员在程序代码中控制(显示调用)。

windows与linux执行文件格式不同,在创建动态库时有一些差异:

I 在windows系统下的执行文件格式是PE格式,动态库需要一个DllMain函数做初始化的入口,通常在导出函数的声明时需要有_declspec(dellexport)关键字。

II linux下gcc编译的执行文件默认是ELF格式,不需要初始化入口,亦不需要函数做特别声明,编写比较方便。

注意

无论是动态链接还是静态链接都会有一个.lib文件,动态库的lib文件叫【导入库】,导入库只包含了地址符号表等,确保程序找到对应函数的一些基本地址信息。

动态库隐式调用

编译时导出使用_declspec(dellexport)关键字

调用时导入使用_declspec(dellimport)关键字

动态库显式调用

在Linux下显式调用动态库

#include <dlfcn.h>,提供了下面几个接口:

  1.   void * dlopen( const char * pathname, int mode ):函数以指定模式打开指定的动态连接库文件,并返回一个句柄给调用进程。
  2.   void* dlsym(void* handle,const char* symbol):dlsym根据动态链接库操作句柄(pHandle)与符号(symbol),返回符号对应的地址。使用这个函数不但可以获取函数地址,也可以获取变量地址。
  3.   int dlclose (void *handle):dlclose用于关闭指定句柄的动态链接库,只有当此动态链接库的使用计数为0时,才会真正被系统卸载。
  4.   const char *dlerror(void):当动态链接库操作函数执行失败时,dlerror可以返回出错信息,返回值为NULL时表示操作函数执行成功。

在Windows下显式调用动态库

应用程序必须进行函数调用以在运行时显式加载 DLL。为显式链接到 DLL,应用程序必须:

  1.   调用 LoadLibrary(或相似的函数)以加载 DLL 和获取模块句柄。
  2.   调用 GetProcAddress,以获取指向应用程序要调用的每个导出函数的函数指针。由于应用程序是通过指针调用 DLL 的函数,编译器不生成外部引用,故无需与导入库链接。
  3.   使用完 DLL 后调用 FreeLibrary

显式调用C++动态库注意点

对C++来说,情况稍微复杂。显式加载一个C++动态库的困难一部分是因为C++的name mangling另一部分是因为没有提供一个合适的API来装载类,在C++中,您可能要用到库中的一个类,而这需要创建该类的一个实例,这不容易做到。

name mangling可以通过extern "C"解决。C++有个特定的关键字用来声明采用C binding的函数:extern "C" 。用 extern "C"声明的函数将使用函数名作符号名,就像C函数一样。因此,只有非成员函数才能被声明为extern "C",并且不能被重载。尽管限制多多,extern "C"函数还是非常有用,因为它们可以象C函数一样被dlopen动态加载。冠以extern "C"限定符后,并不意味着函数中无法使用C++代码了,相反,它仍然是一个完全的C++函数,可以使用任何C++特性和各种类型的参数。

静态库调用

1、静态库的编译

和动态库的区别是,pro文件中需要增加以下内容

CONFIG += staticlib

2、调用

这里我调用的是quazip库。quazip源码中有以下一段说明QUAZIP_STATIC的作用。而静态库其实相当于对源码的直接拷贝使用,所以需要额外声明 DEFINES += QUAZIP_STATIC。

INCLUDEPATH += $$PWD/3rdparty/quazip/include/
#staticlib
DEFINES += QUAZIP_STATIC
DEPENDPATH += $$PWD/3rdparty/quazip/include/

CONFIG(debug, debug|release): {
LIBS += -lzlib
#staticlib
PRE_TARGETDEPS += $$PWD/3rdparty/quazip/libwin/lib/quazipd.lib
PRE_TARGETDEPS += $$PWD/3rdparty/quazip/libwin/lib/zlib.lib
} else {
LIBS += -lzlib
#staticlib
PRE_TARGETDEPS += $$PWD/3rdparty/quazip/libwin/lib/quazip.lib
PRE_TARGETDEPS += $$PWD/3rdparty/quazip/libwin/lib/zlib.lib
}

  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Qt中,第三方库可以通过静态编译和动态编译两种方式进行使用。 1. 静态编译:静态编译是指将第三方库的代码编译静态库(.a或.lib文件),并将静态库链接到应用程序中,生成一个单独的可执行文件。这种方式需要在.pro文件中指定要链接的静态库,例如: ``` LIBS += -lmylib ``` 其中,`mylib`是要链接的静态库名字。 静态编译的优点是运行时不需要动态加载第三方库,提高了启动速度和效率。但缺点是可执行文件较大,不易扩展和更新。 2. 动态编译:动态编译是指将第三方库的代码编译动态库(.dll或.so文件),并在运行时通过libloaderapi函数手动加载动态库,并通过QLibrary类获取动态库中的函数地址,然后直接调用该函数。这种方式需要在代码中显式加载动态库,例如: ``` QLibrary mylib("mylib.dll"); mylib.load(); ``` 然后通过QLibrary的resolve方法获取函数地址,例如: ``` void (*myFunc)() = (void (*)()) mylib.resolve("myFunc"); ``` 其中,`myFunc`是要调用的函数名。 动态编译的优点是灵活性高,可以根据实际需要动态加载和卸载第三方库,便于扩展和更新。但缺点是运行时需要动态加载第三方库,影响了启动速度和效率。 需要注意的是,在使用第三方库时,需要遵循一些规范和最佳实践,以确保正确性和安全性。特别是在获取函数地址时,需要确保函数名的正确性和类型匹配,否则可能导致运行时错误和安全漏洞。同时,在编译和链接时,需要遵循第三方库的使用规范,以确保库文件的正确链接和使用。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值