什么是静态库?
程序在编译链接的时候将库中的代码链接到可执行文件中。程序运行的时候不再需要静态库。
什么是动态库?
程序在运行的时候链接库中的代码,多个程序共享使用库的代码。
模拟实现静态库
简单的来说,库就是把多个.o目标文件的集合。我们只需要为用户提供.o文件(方法的实现)以及头文件(说明有什么方法)就可以让一个程序运行起来。
我们先把.c文件和.h文件实现出来,后将.c文件生成目标文件,最后将所有的目标文件形成一个库
打包给用户。以下是Makefile的相关代码:
output的作用是将头文件和静态库放在一个目录中,这样就可以先打包目录再传输给用户。用户将该目录拷贝到自己的设备就完成了下载。因此下载的本质是拷贝。生成静态库的方法:ar -rc 静态库的名称 所需的所有.o文件。打包命令:tar -cvf 目标文件的名称 被打包文件的名称。解包命令:tar -xvf 目标文件的名称 被解包文件的名称。 -c代表create -v显示打包过程 -f生成目标文件 -x代表解包。 以下是代码的说明:
[root@localhost linux]# lsadd.c add.h main.c sub.c sub.h[root@localhost linux]# gcc -c add.c -o add.o[root@localhost linux]# gcc -c sub.c -o sub.o生成静态库[root@localhost linux]# ar -rc libmymath.a add.o sub.oar 是 gnu 归档工具, rc 表示 (replace and create)
用户收到静态库和.h文件以后该如何使用呢?代码如下:
首先必须用-I表明清楚头文件在什么地方,再用-L表明库在什么地方,最后用-l表明库的名称。
很显然这个方法使用起来感觉十分麻烦,我们可以将头文件拷贝到系统头文件里,将我们自己实现的静态库拷贝到系统库当中。
这个方法我不建议使用,因为很容易修改或者删除系统中的库和头文件!!!注:运行的时候还是要注明库名称!!!
因为我们使用的是静态库,现在我们来看看生成的可执行程序的性质:
很显然我们的程序是动态链接的,这是什么原因呢?
因为gcc默认使用动态库进行链接的,如果有动态库它会优先使用动态链接。如果是静态库它就使用静态链接。所以动态链接只是gcc的一种建议!!形成一个可执行程序的时候,虽然你只是给了一个静态库,但是它可能链接了其他的动态库,所以默认是动态链接。
模拟实现动态库
我们要介绍fPIC:产生位置无关码。使用gcc -fPIC -c 生成目标文件(这个我们后面会讲),再用gcc -shared -o 生成的库名称 *.o 这样一个动态库就生成成功了。
随后我们使用动态库形成一个可执行程序:
当我们运行该程序的时候发现以下标错:
我们用ldd命令查看这个可执行程序:
发现库根本就找不到!!!这是什么原因呢?我们明明已经把头文件的路径以及动态库的路径已经在命令行中写出来了,为什么说找不到动态库?
这是因为你在命令行中写的路径告诉了gcc编译器,这是在预处理编译的时候完成的工作(静态库就是这么使用的)。而动态库是在程序运行的时候需要被链接,操作系统不知道动态库的路径所以不知道。因此接下来我们介绍四种方法让操作系统找到被链接的动态库:
方法一:设置环境变量
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:动态库所属的路径
方法二:设置配置文件
在我们创建的106.conf中写入动态库的路径,最后再刷新一下配置文件即可。刷新操作使用ldconfig。
方法三:使用软链接将动态库的路径链接在和程序同一个了路径下。
系统默认会在当前路径下找动态库,所以我们建立一个软链接即可。
方法四:在系统路径下建立一个软链接链接到我们的动静态库中。
以上四种方法我已经讲述完了,现在我们对动静态库进行总结:
当一个程序运行的是静态库的代码的时候,在此代码编译期间,静态库的代码就已经加载到内存,再通过页表映射到该进程的虚拟地址空间。静态库的代码采用的是绝对编址的方式加载到虚拟地址的代码段中。所以程序运行的时候直接运行代码即可。
而程序需要用到动态库的时候,动态库的代码先加载到内存当中,再通过页表映射在虚拟地址空间中的共享区中,这样就形成了动态库的起始地址。而在程序运行的时候os早将需要用到的函数的地址写到我们的可执行程序当中(代码段)。这里的地址采用的是相对编址的方式,因此运行代码的时候遇到动态库的函数时,会从代码段跳转到共享区,再通过已有的相对地址找到函数的虚拟地址,最后再通过页表映射到内存找到函数的实现。
到这里动静态库的知识就全部讲完了,如果自己有表述的不对的地方还请多多指正!