1、静态库和共享库
静态库和共享库(动态库),二者的不同点在于代码被载入的时刻不同。
静态库的代码在编译过程中已经被载入可执行程序,因此体积较大。
共享库的代码是在可执行程序运行时才载入内存的,在编译过程中仅简单的引用,因此代码体积较小。
静态链接库和动态链接库的区别在于,主程序在运行前,静态链接库的链接固定写入在程序中,而动态链接库则是在每次程序运行再加载链接。
2、库存在的意义
库是别人写好的现有的,成熟的,可以复用的代码,你可以使用但要记得遵守许可协议。
现实中每个程序都要依赖很多基础的底层库,不可能每个人的代码都从零开始,因此库的存在意义非同寻常。
共享库的好处是,不同的应用程序如果调用相同的库,那么在内存里只需要有一份该共享库的实例。
3.静态库
Step 1.由源文件编译生成一堆.o,每个.o里都包含这个编译单元的符号表
Step 2.ar命令将很多.o转换成.a,成为静态库
静态链接库 libcool.a 遵从 GNU/Linux 规定的静态链接库命名规范,必须是”libyour_library_name.a”
动态库的后缀是.so,它由gcc加特定参数编译产生。
4、动态库
在 GNU/Linux 中动态链接文件,必需通过链接器 ld 生成。假设我们有 hot.c other.c 等文件要生成动态链接库 libhot.so 。首先使用如下指令得到相应的 object 文件 hot.o 和 other.o
gcc -fPIC -c hot.c
gcc -fPIC -c other.c
参数 -fPIC 指定生成的 object 文件为位置无关代码(position-independence code),只有 PIC 可以被用作生成动态链接库。然后使用如下指令得到动态库:
ld -Bshared -o libhot.so hot.o other.o
或者可以使用编译器的ld wrapper:
gcc -shared -o libhot.so hot.o other.o
也可以使用编译器直接生成动态库:
gcc -fPIC -shared -o libhot.so hot.c other.c
这里选项 -shared 指示目标文件的类型是动态链接库,动态库的命名规范是”libyour_library_name.so”
linux操作系统中,
1.和静态库类似,动态库文件也是一些目标文件(后缀名为.o)的集合体而已。
2.动态库的后缀名是.so,对应于windows操作系统的后缀名为.dll的动态库。
3.可以使用gcc命令来创建一个动态库文件。
来看一个实例,和静态库的代码实际是一样的。先看看可以编译成库文件的源文件中的代码:
/* test.c */
int f()
{
return 3;
}
代码非常简单。我们敲入下列命令:
gcc -c -fPIC test.c
gcc -shared -fPIC -o libtest.so test.o
会在当前目录下生成一个libtest.so动态库文件。再看如何使用这个库。看如下代码:
/* app.c */
#include <stdio.h>
extern int f();
int main()
{
printf(“return value is %d\n”,f());
return 0;
}
敲入如下命令:
gcc –c app.c
gcc -o app app.o -L. –ltest
敲命令的时候要记得将libtest.a文件和生成的app.o文件放在同一个目录(即当前目录)下。这样,敲入命令后,会在当前目录下生成一个名为app的可执行文件。但是当我们执行./app命令,来执行这个可执行文件时,却提示如下错误:
这就奇怪了,libtest.so文件明明就在当前目录下,为什么会提示找不到呢?
原来linux和windows的机制是不同的,它不会在当前目录下寻找动态连接库文件,它只会在标准路径下寻找。(The system searches only /lib and /usr/lib, by default.)。我们可以使用一个命令,使得操作系统去我们指定的路径下面去寻找。假设libtest.so文件所在的目录是/root/Desktop/aabb,那么执行命令
export LD_LIBRARY_PATH=/root/Desktop/aabb
后,再执行./app,我们发现,程序就正常运行了。
在加载动态链接库的时候,有可能会遇到加载不到的错误,原因在于系统默认加载的动态链接库路径里没有找到你的动态库,有三种解决方法:
- 1.在执行gcc main.c -L. -ltest -o main 前,执行 export LD_LIBRARY_PATH=$(pwd)
- 2.将其添加到/etc/ld.so.cache文件中。将你so所在的目录写到/etc/ld.so.conf文件里,然后执行ldconfig该命令会重建/etc/ld.so.cache文件。
- 3.将你的so放在/etc/ld.so.conf里的路径位置里。
Linux下的dlopen、dlsym、dlclose 相当于windows平台的LoadLibrary、GetProcAddress 、FreeLibrary,可以在运行时动态加载动态库,使用其中的导出函数。但是局限在于,这样仅仅能够导出全局函数,而不能导出类的方法。所以一般动态库导出C++类实现的功能时都会设计一大堆的全局函数来包装一下。
包含头文件:
#include <dlfcn.h> dlfcn.h : Linux动态库的显式调用
函数
void * dlopen( const char * pathname, int mode );
函数描述:
在dlopen的()函数以指定模式打开指定的动态连接库文件,并返回一个句柄给调用进程。使用dlclose()来卸载打开的库。
mode:分为这两种
RTLD_LAZY 暂缓决定,等有需要时再解出符号
RTLD_NOW 立即决定,返回前解除所有未决定的符号。
dlerror
函数定义:
void*dlsym(void* handle,const char* symbol)
函数描述:
dlsym根据动态链接库操作句柄(handle)与符号(symbol),返回符号对应的地址。使用这个函数不但可以获取函数地址,也可以获取变量地址。
dlclose
dlopen以指定模式打开指定的动态连接库文件,并返回一个句柄给调用进程,dlerror返回出现的错误,dlsym通过句柄和连接符名称获取函数名或者变量名,dlclose来卸载打开的库。 dlopen打开模式如下:
RTLD_LAZY 暂缓决定,等有需要时再解出符号
RTLD_NOW 立即决定,返回前解除所有未决定的符号。
生产动态链接库
编译参数 gcc -fPIC -shared
使用so文件的编译参数
编译选项如下:
gcc -rdynamic -o main main.c -ldl
选项 -rdynamic 用来通知链接器将所有符号添加到动态符号表中
(目的是能够通过使用 dlopen 来实现向后跟踪)比如日志系统,主程序里使用一套日志系统,dlopen方式打开的libso里无法使用。编译时加上这个参数,不需要增加任何代码就可以使代码通用。
使用-ldl选项指明生成的对象模块需要使用共享库