Linux|【Linux】静态库和动态库的生成与使用

静态库动态库的生成与使用 :【 多图预警】

  • 动态库的生成(重点)
  • 静态库的生成(重点)
  • 查看动态库和静态库的汇编代码进行对比(了解)
  • 库的使用(重点)
    • 链接的时候使用库(重点)
    • 运行的时候使用库(重点)
  • 查看当前程序所依赖的库(了解)
  • 本节课重要的原因:
以后的使用大多数都是使用现成的动态库和静态库,在本文章我们以加法add()函数建一个动态库和静态库,分过程讲解动态库和静态库的生成与动态库使用。,使用动态库讲述链接与运行加载库的过程(静态库的链接与动态库一样,不一样的是静态库运行时不需加载静态库)
库文件: 把所用到的所有代码的实现打包成一个文件。 库中的代码没有main函数(和可执行程序的区别) 动态库的生成 动态库的命名:一般的动态库命名:lib().so 。 ()里面是动态库起的名字,以lib作为开始,以.so表明它是动态库
生成动态库:使用gcc
第一步: gcc-fPIC -c add.c -o add.o
第二步: gcc --share add.o -o libadd.so
讲解:gcc -c add.c -o add.o 普通的来讲 gcc add.o -o add 生成可执行程序了 没有main函数就会报错,有了main函数就不能生出库
所以:要写成gcc --share add.o -o libadd.so的形式
动态运行的时候加载,加载到内存之后,需要在多个程序中都要去使用。这样我们需要理解一个程序的运行需要将内存中的代码和数据映射到进程虚拟地址空间中映射到虚拟地址空间去才能访问,这个动态库需要映射到各个库独立的虚拟地址空间中去才能被访问,生成库的时候有自己的信息,映射的时候 ,无法保证每个程序都将它映射到虚拟地址空间中的同一位置,所以动态库就不能用于每个程序,所以要加上fPIC 产生位置无关的代码,库映射到虚拟地址空间的同一位置,每一个函数进行计算的时候拿偏移量+首地址就能得到,便于映射到每一个程序中(了解)。
在这里 我们把加法函数建一个动态库和静态库去使用和讲解
新建一个add.c文件
int add(int a,int b) { return a+b; }

在新建一个main.c文件
1 #include 2 int main () 3 { 4 5printf("%d".add(2,3)); 6return 0; 7 }

动态库的生成过程: Linux|【Linux】静态库和动态库的生成与使用
文章图片

可以看到我们的文件中已经存在动态库libadd.so
静态库的生成: 静态库的命名:般的动态库命名:lib().a 。 ()里面是静态库起的名字,以lib作为开始,以.a表明它是静态库
生成静态库:使用gcc/ar
第一步: gcc -c add.c -o add.o
第二步: ar -cr add.a add.o
讲解:直接将代码拿到程序中来,不关心动态库偏移量的问题,所以可以不加-fPIC,加上也行
静态库的生成过程
Linux|【Linux】静态库和动态库的生成与使用
文章图片

可以看到我们的文件当中已经存在静态库libadd.a
查看动态库与静态库汇编代码对比
执行命令:objdump -S
查看动态库的汇编代码:objdump -S libadd.so
Linux|【Linux】静态库和动态库的生成与使用
文章图片

查看静态库的汇编代码:objdump -S libadd.a
Linux|【Linux】静态库和动态库的生成与使用
文章图片

对比与总结:动态库的汇编指令比较多,其中加载的比较多, 有符号表,注册信息,代码信息(动态库的汇编指令还没有罗列完,还有很多)
库的使用: 在讲库的使用之前先要弄清楚
为什么链接的时候要使用库呢???
不能生成可执行文件,因为没有add函数的声明
Linux|【Linux】静态库和动态库的生成与使用
文章图片

接下来我们看:
Linux|【Linux】静态库和动态库的生成与使用
文章图片

运行错误没有找到add有关的动态库,这是为什么呢???
因为动态库和静态库链接的时候都是到指定位置下找动态库和静态库的位置。所以我们要把库放在指定路径下。当然链接也有其它的方法,我们往下进行浏览

链接的时候使用库 我们统一统一使用 gcc -o main main.o -ladd (-l:指定链接库的名称,默认是链接动态库,这里我们例子的函数名是add)
1、将库文件放置在指定的路径下
指定命令 sudo cp libchild.so /lib64/
重新编译 gcc -o main main.o -lchild 就好了
Linux|【Linux】静态库和动态库的生成与使用
文章图片

运行成功(add(2,3) = 5)但是放到指定路径下会污染系统目录,使用完记得在路径下删除文件(以便我们验证后面的方法)
记得删除系统目录中的:sudo rm -rf /lib64/libchild.so
Linux|【Linux】静态库和动态库的生成与使用
文章图片

删除完毕系统指定目录下的libadd.so,再次编译就生成不了可执行文件main了。
2、设置LIBRARY_PATH环境变量
export LIBRARY_PATH=${LIBRARY_PATH}: ./ (加上{} 表示变量)
echo $LIBRARY_PATH 查看环境变量LIBRARY_PATH内容
Linux|【Linux】静态库和动态库的生成与使用
文章图片

重新编译 gcc -o main main.o -ladd,但此时还是无法运行!接下来还要讲运行时加载动态库
Linux|【Linux】静态库和动态库的生成与使用
文章图片
unset LIBARY_PATH 删除环境变量就编译不通过
Linux|【Linux】静态库和动态库的生成与使用
文章图片

3、通过gcc -L选项设置链接库的默认搜索路径 gcc -o main main.o -L ./ -ladd(常用的方法)
注意:
-l(小L) : 指定连接库名称(去掉lib().so,只要()中间的名字)
-L:指定库的链接搜索路径(./在当前文件下)Linux|【Linux】静态库和动态库的生成与使用
文章图片

但是和设置环境变量的使用一样,生成可执行程序后,运行不了程序;但是将库放置在指定文件夹(/lib64/)下就可以运行。接下来我们讲运行时使用库.
也就是说链接是一个路径,运行时是另一个路径(系统默认的库路径/lib64/)
运行的时候使用库(.so) 运行的时候使用的库是动态链接生成的动态库。静态链接运行的时候不需要加载库,只有动态库才会在运行的时候加载库
./main 运行不了
两种方式解决问题 1、将库文件放置到指定的路径下
和链接的时候使用库用法一样,将libadd.so 放置指定路径下就可以运行了 。sudo cp libchild.so /lib64/。所以将动态库放置在这个路径下,可以直接成main并执行程序
2、设置LD_LIBRARY_PATH环境变量(用法同链接时一样)
Linux|【Linux】静态库和动态库的生成与使用
文章图片

在动态库的链接与运行时要注意:gcc 默认链接的是动态库,-l(小L)加上库的名称的话默认是先找动态库,若没有动态库,则就是找静态库。 当一个路径下(或第三方库)既有动态库又有静态库,想链接静态库的时候,拿出来放置到另一路径下。
ldd 查看当前程序所依赖的库 ldd main 查看main程序所依赖的动态库
Linux|【Linux】静态库和动态库的生成与使用
文章图片

not found 没有找到所依赖的动态库。
只设置了链接时的时候使用了库(LIBRARY_PATH)
运行的时候使用库没有设置(LD_LIBRARY_PATH)
所以ldd main中 libadd.so还是没有找到
Linux|【Linux】静态库和动态库的生成与使用
文章图片

运行的时候链接库 ,此时就可以找到依赖的动态库了!
【Linux|【Linux】静态库和动态库的生成与使用】

    推荐阅读