目录
静态库说明
在链接阶段,会将汇编生成的目标文件.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>,提供了下面几个接口:
- void * dlopen( const char * pathname, int mode ):函数以指定模式打开指定的动态连接库文件,并返回一个句柄给调用进程。
- void* dlsym(void* handle,const char* symbol):dlsym根据动态链接库操作句柄(pHandle)与符号(symbol),返回符号对应的地址。使用这个函数不但可以获取函数地址,也可以获取变量地址。
- int dlclose (void *handle):dlclose用于关闭指定句柄的动态链接库,只有当此动态链接库的使用计数为0时,才会真正被系统卸载。
- const char *dlerror(void):当动态链接库操作函数执行失败时,dlerror可以返回出错信息,返回值为NULL时表示操作函数执行成功。
在Windows下显式调用动态库
应用程序必须进行函数调用以在运行时显式加载 DLL。为显式链接到 DLL,应用程序必须:
- 调用 LoadLibrary(或相似的函数)以加载 DLL 和获取模块句柄。
- 调用 GetProcAddress,以获取指向应用程序要调用的每个导出函数的函数指针。由于应用程序是通过指针调用 DLL 的函数,编译器不生成外部引用,故无需与导入库链接。
- 使用完 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
}