概述
系统调用
内核对外提供接口。用户进程不能直接访问内核数据并对其操作,只能通过这些接口访问,进程调用这些接口的行为叫做系统调用
访问内核
系统调用 shell外壳 库函数
库
库函数
系统调用的功能是很纯粹的。库函数是把系统调用进行了封装,让功能更丰富。
以C库中的printf()为例。printf底层封装的是write,write接口的功能是把数据刷到内核缓冲区,而printf会在内核缓冲区之前封装一层用户级缓冲区,以提高printf函数的效率。
库会为我们提供丰富的库函数来满足我们对编程的需求。人们常说的站在巨人的肩膀上其实就是把别人写好的成熟的库拿来用。
静态库
命名格式为:lib____.a 前缀为lib,后缀为.a。 中间部分为库名。
.o的程序文件在链接静态库时,是把整库拷贝到目标程序文件中。这种链接成为静态链接。静态链接之后,目标程序文件就和静态库没有任何关联了
静态库之作用与程序的链接阶段
动态库
命名格式为:lib____.so 前缀为lib,后缀为.so。 中间部分为库名。
对于动态库的链接,可以理解为是把库方法的地址给给目标文件
如果一个进程需要动态库,动态库就要被加载到内存。如果多个进程共同使用一个动态库,这个动态库也可以称为共享库
制作动静态库
制作静态库
1.把可执行程序编译成.o文件,也就是二进制文件
2.将这些二进制文件用ar工具打包,就形成静态库啦
示例
ar -rc libmymath.a add.o sub.o
ar 是 gnu 归档工具, rc 表示 (replace and create)
制作动态库(以C为例):
1.用gcc把可执行程序编译成.o文件,带上 -fPIC选项,-fPIC表示与位置无关码
2.用gcc把.o文件打包成动态库,带上c -shared 选项, shared表示生共享库格式
示例
gcc -fPIC -c sub.c add.c gcc -shared -o libmymath.so *.o
我们用如下几个文件制作动态库和静态库
静态库文件
static.c
#include"static.h" 2 3 void Print() 4 { 5 printf("hello linux\n"); 6 printf("hello linux\n"); 7 printf("hello linux\n"); 8 printf("hello linux\n"); 9 printf("hello linux\n"); 10 printf("hello linux\n"); 11 12 return ; 13 14 }
static.h
#include<stdio.h> void Print();
动态库文件
dynamic.c
#include"dynamic.h" 2 3 void Prinr_d() 4 { 5 6 printf("hi linux\n"); 7 printf("hi linux\n"); 8 printf("hi linux\n"); 9 printf("hi linux\n"); 10 printf("hi linux\n"); 11 12 return ; }
dynamic.h
1 #include<stdio.h> 2 3 void Print_d();
编写make脚本
1 s_lib = libmystatic.a 2 d_lib = libmydynamic.so 3 4 #伪目标 5 .PHONY:all 6 all:$(s_lib) $(d_lib) 7 8 #静态库 9 $(s_lib):static.o 10 @ar -rc $@ $^ 11 static.o:static.c 12 @gcc -c $^ 13 14 #动态库 15 $(d_lib):dynamic.o 16 @gcc -shared -o $@ $^ 17 dynamic.o:dynamic.c 18 @gcc -fPIC -c $^ 19 20 #清理 21 .PHONY:clean 22 clean: 23 @rm -rf *.o *.a *.so mylib 24 25 #发布 26 .PHONY:ph 27 ph: 28 @mkdir -p mylib/lib 29 @mkdir mylib/include 30 @cp *.a *.so mylib/lib 31 @cp *.h mylib/include ~
将库发布出来:把动静态库和相关头文件打包到一个目录里
查看mylib目录结构
使用动静态库
我们自己制作的库属于第三方库,需要在gcc中添加相关选项
I (大写i):表示头文件路径
L:表示库路径
l (小写L):表示链接哪个库
静态库测试代码如下 s_test.c
1 #include"static.h" 2 3 int main() 4 { 5 Print(); 6 7 return 0; 8 }
用gcc编译
动态库测试代码如下d_test.c
1 #include"dynamic.h" 2 3 int main() 4 { 5 6 Prinr_d(); 7 8 return 0; 9 }
用gcc编译
那么动态链接第三方库的可执行程序能运行吗
显然是不能。
进程需要动态库的方法实现,动态库就必须加载到内存。但上述指令中,我们只告诉了gcc相应的库在哪里。
系统并不能找到相应的库。
而且上述gcc编译时,需要带一堆路径。根本原因是系统找不到第三方库。
如何让系统默认找到第三方库
系统会去默认路径下找相关的库(静态库和动态库)
/lib 和/lib64
/usr/lib 和 /usr/lib64
/usr/local/lib和/usr/local/lib64
系统会去默认路径下找相关的头文件
/usr/include
lib和lib64的区别
ilb是32位程序运行的库
lib64是64位程序运行的库
/和/usr/和/usr/local下lib和lib64的区别
/lib和/lib64 是 /usr/lib和 /usr/lib64 的软连接,也就是说根目录下的是快捷方式
在根目录下用 ll 指令查看
/usr/local/lib和/usr/local/lib64和上述两个库目录的区别呢
/usr下面的lib和lib64一般存放的是系统安装的标准库文件,和共享库文件,是系统管理安装的。
/usr/local下面的lib和lib64是由系统的管理员或者我们去手动安装的。
知道了系统默认搜索路径,由如下两个方法就可以让系统找到第三方库
1.直接把库拷贝到系统的默认搜索路径下
2.在系统默认搜索路径下建立软连接
ln -s 要查找的路径 软连接的文件放哪
环境变量
LIBRARY_PATH
是一个环境变量,它用于指定程序在寻找共享库(动态链接库,.so文件)时应搜索的路径列表。
当编译或运行一个动态链接的程序时,如果程序依赖的库不在当前目录或系统默认的搜索路径中,LIBRARY_PATH
会帮助系统查找这些库。
LD_LIBRARY_PATH
是一个重要的环境变量,它告诉动态链接器在哪里查找共享库。
当你在命令行中运行一个程序时,如果它依赖于某些共享库,并且这些库不在标准库路(如 /lib
、/usr/lib
等)中, LD_LIBRARY_PATH
会帮助系统查找这些库。
临时设置
export LD_LIBRARY_PATH=/path/to/libs:$LD_LIBRARY_PATH
将新的路径添加到 $LD_LIBRARY_PATH
的前面,并用冒号(:
)分隔,可以确保新的路径在标准库路径之前被搜索
永久设置
对于某个用户,可以将 export
命令添加到 /.bashrc
、/.bash_profile
或 /.profile
文件中
对于所有用户,可以将 export
命令添加到 /etc/profile
或 /etc/environment
文件中
配置相关文件
让系统找到相关的动态库可以在/etc/ld.so.conf.d/目录下建立以.conf为后缀的文件。在这个文件中写入动态库的路径即可。
然后执行ldconfig指令更新