前言
在 Linux 基础 IO 的体系中,打通了用户态接口、系统调用、缓冲区等上层操作链路,以及文件系统、inode、软硬链接等底层存储逻辑后,完整的知识体系还离不开两个关键延伸:一是代码复用的载体——库(静态库与动态库),二是程序运行的内存基础——进程地址空间。本文作为该系列的收官篇,将聚焦这三大核心模块,详解库的构建命令、链接方式、底层差异,剖析进程地址空间的本质,并补充内存管理、IO 数据拷贝流程等关键细节。
动态库和静态库
库的安装其实就是把库文件放到系统的默认路径里。
库文件中不能包含 main 函数,因为库是被其他程序调用的。
静态库
静态库是将源代码编译后打包成 libxxx.a 文件(命名规范为 lib + 名称 + .a)。静态库通常与头文件一起提供给使用者,使用者无法直接获取源文件。
静态库是为单个程序生成的,互不干扰。因此,生成可执行程序后,即使删除原始的静态库文件,程序仍可正常运行,因为静态库的代码已被完整拷贝到可执行文件中。
生成静态库:
ar -rc libmymath.a add.o sub.o
参数 -r 表示存在就替换,不存在就创建。
链接: 如果头文件和库不在当前目录或系统默认位置,需要指定路径:
gcc main.c -I ./lib/include/ -L ./lib/mymathlib/ -lmymath
-I:指定头文件的搜索目录。-L:指定库文件的搜索目录。-l:指定要链接的库的名称(去掉lib前缀和.a后缀)。
gcc 可以同时链接多个库。默认情况下,gcc 优先调用动态库,除非只有静态库或显式指定 -static。
在使用自定义头文件时,若不在当前目录同级,需指定路径或使用绝对路径(但绝对路径可移植性较差)。
动态库(共享库)
动态库可以被多个程序同时使用,属于共享资源。
库名格式:libxxx.so(必须包含 .so)。
生成动态库:
gcc -fPIC -c *.o
ar -rc libmymath.so *.o
加载问题: 编译器知道动态库的位置,但操作系统加载器不知道。因此,运行时需要确保动态库能被找到。
fPIC
fPIC(Position Independent Code,位置无关代码)是指库中的函数不采用绝对编址,而是通过偏移量进行寻址。这是因为动态库被加载到内存地址空间的位置是不固定的,使用相对偏移可以适应不同的加载地址。
让动态库能被加载的方法
- 拷贝到系统默认库路径:如
/lib64或/usr/lib64。 - 建立软链接:在系统默认库路径下建立指向实际库文件的软链接。
- 设置环境变量:将库所在路径添加到
LD_LIBRARY_PATH环境变量中(注意是上一级目录)。 - 配置 ldconfig:在
/etc/ld.so.conf.d/下建立配置文件,然后运行ldconfig更新缓存。
为什么动态库需要加载而静态库不用? 动态库只有一份存在于物理内存中,程序通过共享区对应的页表访问它,所以需要被加载。静态库在链接时已完整拷贝到可执行文件中,外部静态库不再需要。


