库的概念
1.库的定义
本质上来说库是一种可执行代码的二进制形式,可以被操作系统载入内存执行。
2.库的分类
linux 下的库有两种:静态库和共享库(动态库)。 二者的不同点在于代码被载入的时刻不同。 静态库的代码在编译过程中已经被载入可执行程序,因此体积较大。
共享库的代码是在可执行程序运行时才载入内存的,在编译过程中仅简单的引用,可以节省系统开销,因此代码体积较小。不同的程序调用相同库时,内存中只需有一份该动态库的实例即可。
3.在Linux下库文件的产生
静态库(后缀是.a):
由源文件编译生成一堆.o,每个.o 里都包含这个编译单元的符号表
ar 命令将很多.o 转换成.a,成为静态库
如:ar rcs libmyhello.a hello.o ,再编译:gcc add.c -static -L. -lmyhello -o hello,执行可执行文件:./hello
此时发现执行gcc main.c -static -L. -lmyhello -o hello后报了一个错误,原因是你的系统中没有安装静态库
安装静态库后执行发现结果正确:
删除静态库文件发现程序照常运行,原因是静态库中的公用函数已经连接到目标文件中
动态库(后缀是.so):
gcc hello.c -shared -fPIC -o libmyhello.so
-PIC:表示 GCC 产生的代码不要包含对函数和变量具体内存位置的引用,即编译为位置独立的代码
-shared:表示生成动态库gcc add.c -L. -lmyhello -o hello
-L.:表示告诉 GCC 函数库可能位于当前目录若直接执行./hello会发现编译器报错,原因是GNU连接器会查找标准系统函数目录,先后搜索:①elf 文件的 DT_RPATH 段—>②境变量LD _LIBRARY _PATH(此环境变量指示动态连接器可以装载动态库的路径)—>③/etc/ld.so.cache 文件列表—>④/lib/或/usr/lib 目录找到库文件后将其载入内存。但这里生成的库并没有加载到这四个路径中的任何一条,所以编译器会报错。
解决方法:①将文件 libmyhello.so 复制到目录/usr/lib 中,再执行./hello
②先执行:export LD_ LIBRARY_PATH=$(pwd),再执行:./hello
③执行ldconfig /usr/zhsoft/lib,此命令的功能在于让 ldconfig 将指定目录下的
动态链接库被系统共享起来,会重建/etc/ld.so.cache 文件
注:当静态库与动态库同名时,gcc命令会优先使用动态库
4.库文件的命名
在 linux 下,库文件一般放在/usr/lib 和/lib 下
静态库的名字一般为 libxxx.a,其中 xxx 是该 lib 的名称。如:libc.a
动态库的名字一般为 libxxx.so.major.minor,其中xxx 是该 lib 的名称,major 是主版本号,minor 是副版本号。如:libc.so.6
静态库链接时搜索路径顺序
ld 会去找 gcc 命令中的参数-L
再找 gcc 的环境变量 LIBRARY_PATH(该环境变量指定静态链接库文件搜索路径)
再找内定目录 /lib 或/usr/lib 或/usr/local/lib
动态库链接时搜索路径顺序
编译目标代码时指定的动态库搜索路径
环境变量 LD_ LIBRARY_PATH 指定的动态库搜索路径(该环境变量指定动态链接库文件搜索路径)
配置文件/etc/ld.so.conf 中指定的动态库搜索路径
默认的动态库搜索路径/lib
默认的动态库搜索路径/usr/lib
gcc 编译
gcc编译会有以下四个步骤:
预处理(宏替换、条件编译、头文件展开、去注释)
实例:gcc -E test.c -o test.i
编译(生成汇编)
实例:gcc -S test.c -o test.s
汇编(生成机器可执行代码)
实例:gcc -c test.c -o test.o
链接(生成可执行文件或库文件)
实例:gcc test.c -o test 或 gcc test.o -o test
选项:
-o:指定生成的输出文件名字
-E:仅执行编译预处理
-S:将C代码转换为汇编代码
-O0:编译器优化级别(0表示没有优化,1为编译器默认值,3优化级别最高)
特殊记忆法:esc、iso