Linux:动静态库
一:什么是库
库是写好的,现有的,成熟的可以复用的代码。现实中每个程序都要依赖很多基础的底层库,不可能每个人都从零开始写,因此库的存在一样非同寻常
本质上库是一种可执行代码的二进制形式,可以被操作系统载入内存执行。库有两种:
- 静态库:.a[Linux]、.lib[Windows]
- 动态库:.so[Linux]、.dll[Windows]
二:静态库
2-1 本质
静态库的本质就是将.o文件打包 ,并且.a静态库,本质是一种归档文件,不需要用户解包,而用gcc/g++直接进行链接即可
2-2 ar 命令
基本语法:
ar + 选项 + 归档文件(目标静态库文件)+ 成员文件
我们使用 ar -rc libmyc.a *.o 命令即可将当前路径下所有.o文件打包生成一个名为libmyc.a的静态库文件,其中静态库文件libmyc.a的真正文件名名去掉前缀lib和后缀.a剩余的部分,即myc。其中选项rc分别代表着replace和create,即如果已存在的文件发生更新即用更新后的文件替换原有文件,不存在的文件即新建
2-3 静态库的使用
2-3-1 -L -l 选项
假设我们将我们自己的代码拷贝至zhangsan目录下,如果将一个个.c和.h拷贝至zhangsan目录下将会非常麻烦而且非常费时(特别是文件很多的时候), 我们就可以将我们当前目录下的.c文件打包形成一个静态库文件并将这个静态库文件libmyc.a拷贝至zhangsan目录下,并将所有的.h文件拷贝至zhangsan目录下,如下图所示:
可是当我们使用 gcc -o usercode usercode.o 命令将usercode.o文件形成可执行文件usercode的时候为什么会报错表示找不到对应的方法呢?如下图所示:
这是因为这些函数在自定义的静态库内实行的,而我们没有指定链接需要的库,那么就可以使用gcc -o usercode usercode.o -l myc 命令来指定需要库,其中 -l myc 表明在链接过程中去myc库中查找需要的源文件,可是我们执行了该命令后还是报错了,这是为什么呢?
这是因为静态库链接失败了,找不到指定要链接的库myc,这是因为静态库链接时会在系统指定的静态库路径下查找静态库文件,而我们如果需要链接我们自己的静态库文件就需要指定路径去查找静态库。因此如果我们要连接任何非C/C++的标准库(包括其他外部和我们自己写的),都需要指明 -L + 路径 表明去哪里找库和 -l + 静态库真正文件名 表明找什么库。因此当我们执行gcc -o usercode usercode.o -L . -l myc 命令的时候就会在当前目录下查找名为myc的库,如下图所示,可以看到生成了可执行文件usercode
2-3-2 -I 选项
如上所示:在zhangsan目录下,mystdio.h 和 mystring.h这两个头文件在 ./lib/include目录下,而libmyc.a在 ./lib/mylib目录下,而usercode.c就在zhangsan 目录下 。如果我们此时直接执行gcc -c usercode.c 命令将usercode.c文件生成对应的同名.o文件就会报错 如下图所示:
可以看到提示我们找不到mystring.h这个我们自己写的头文件,这是因为这个头文件不在当前目录下也不在系统里面,而是在我们自己保存的路径下,因此我们需要提示编译器在哪里找我们的头文件。我们可以使用 -I + 路径 表明编译器也要在指定路径下查找头文件,执行 gcc -c usercode.c -I ./lib/include 命令就会生成对应的.o文件,如下图所示:
三:动态库(共享库)
3-1 动态库的生成
在前面我们提到静态库的生成依靠ar工具,而动态库文件的生成依靠gcc就可以了。首先我们先将.c 文件生成对应的 .o 文件,然后依赖gcc工具执行命令,详细步骤如下:
首先执行 gcc -fPIC -c *.c 命令将所有的.c 文件生成对应的同名 .o 文件,其中 -fPIC 是位置无关码,这里不做多解释,接着执行 gcc -shared -o libmyc.so *.o 命令表示将所有的 .o 文件生成一个动态链接库libmyc.so,其中动态链接库的真正名为去掉前缀 lib 和后缀 .so 后剩余的部分即myc,而-shared表明生成的是动态链接库而不是生成指定的可执行文件,如下图所示:
那么我们怎么查看我们生成的是动态链接库而不是可执行文件呢?执行file libmyc.so可查看libmyc.so文件的类型和相关信息,结果如下:
3-2 -I -L -l 选项
如上所示:在zhangsan目录下,mystdio.h 和 mystring.h这两个头文件在 ./lib/include目录下,而libmyc.so在 ./lib/mylib目录下,而usercode.c就在zhangsan 目录下 。如果我们此时直接执行gcc -o usercode usercode.c 命令将usercode.c文件生成可执行文件usercode就会报错 如下图所示:
可以看到提示我们找不到mystring.h这个我们自己写的头文件,这是因为这个头文件不在当前目录下也不在系统里面,因此我们需要指定自己头文件的路径,执行 gcc -o usercode usercode.c -I lib/include/ 系统也就会在lib/include/路径下寻找头文件,然后报错表示找不到库,如下所示(原因同静态库所写一样)
执行 gcc -o usercode usercode.c -I lib/include/ -l myc 命令查找myc库还是报错,如下所示找不到库,那么我们就需要指定查找库的路径,执行 gcc -o usercode usercode.c -I lib/include/ -L lib/mylib/ -l myc 命令
可是运行时却报错表明找不到动态库如下图所示,可是我们在运行的时候不是已经告诉编译器在哪里在动态库并且动态库存在吗?
我们执行 ldd usercode 命令用来查看动态库myc的动态链接库的依赖关系,如下图所示:我们可以看到出现 libmyc.so => not found 的提示,意味着系统找不到libmyc.so这个动态链接库,这是为什么呢?
这是因为我们执行 gcc -o usercode usercode.c -I lib/include/ -L lib/mylib -l myc 命令时我们只告诉了gcc 去哪里找libmyc.so 这个动态链接库而没有告诉系统去哪里找所以系统在自己的默认路径下找不到就会报错,那么为什么动态库会出现这个情况而静态库却没有出现这个情况呢?这是因为静态库在链接时是直接将库的实现拷贝到可执行程序里,一旦形成可执行程序,可执行程序不再依赖静态库,而动态库在链接时在加载可执行程序的同时还要找到依赖的动态库,那怎么解决呢?
方法一:软链接
执行 sudo ln -fs /home/cwy/cw/linux/lesson22/zhangsan/lib/mylib/libmyc.so /lib64/libmyc.so 命令在lib64下创建一个libmyc.so的文件并将 /lib64/libmyc.so 软链接到前者 /home/cwy/cw/linux/lesson22/zhangsan/lib/mylib/libmyc.so
方法二:LD_LIBRARY_PATH
LD_LIBRARY_PATH是Linux下的一个环境变量,当操作系统运行程序时系统除了会在标准路径下查找程序运行所需要的动态库外,也会在该环境变量下查找动态库,而且LD_LIBRARY_PATH经常都是空的,但是不影响
执行 export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:/home/cwy/cw/linux/lesson22/zhangsan/lib/mylib命令就会在环境变量LD_LIBRARY_PATH上添加/home/cwy/cw/linux/lesson22/zhangsan/lib/mylib这个目录。因此在执行 ./usercode 命令时,不仅会在系统的标准路径下查找动态库,还会在 /home/cwy/cw/linux/lesson22/zhangsan/lib/mylib 这个目录下查找动态库,从下图可以看得到我们成功将所需要的动态库libmyc.so 动态库链接成功.但是根据我们前面学过的环境变量的知识,环境变量的存在只是临时的,一旦将XShell关闭那么这个环境变量将不存在
方法三:/etc/ld.so.conf
/etc/ld.so.conf是Linux系统中用于配置动态链接库搜索动态库路径的配置文件,用于指定系统在运行时搜索动态库的目录路径。即系统在运行时也会在/etc/ld.so.conf路径下查看所有动态库的路径来查找动态库
首先在 /etc/ld.so.conf.d/ 的目录下创建一个后缀为conf的配置文件,例如执行 sudo touch /etc/ld.so.conf.d/dong.conf 命令即在/etc/ld.so.conf.d/路径下创建一个名为dong.conf 的配置文件,如下图所示创建成功
接着将需要使用的动态库路径通过编译器写入dong.conf这个文件中,这里使用nano日记写入,执行 sudo nano /etc/ld.so.conf.d/dong.conf 命令,将libmyc.so 动态库所在的路径 /home/cwy/cw/linux/lesson22/zhangsan/lib/mylib 写进去就行,如下图所示,将文件中的内容打印出来就是这个动态库所在的目录路径,表明写入成功
但是到这一步还不行,我们还需要执行 sudo ldconfig 更新配置文件
四:动静态库
动静态库能否同时存在呢?如果能同时存在又会如何呢?答案是动态库和静态库可以同时存在并且动态库和静态库同时存在的时候,会发生动态链接。如下图所示:在当前路径下,同时存在着libmyc.a这个静态库和libmyc.so这个动态库
当我们执行 gcc -o code usercode.c -I lib/include/ -L lib/mylib/ -l myc 命令时,我们没有指定是链接libmyc.a这个静态库还是链接libmyc.so这个动态库只是表明查找myc这个库,可以看到编译器默认链接了动态库。因此
那如果我们就是想使用静态链接呢?那就必须指定 -static ,如果要静态链接必须存在静态库,如果不存在就会报错,如下所示: