linux下动静态库

什么是库

库是写好的现有的,成熟的,可以复⽤的代码。现实中每个程序都要依赖很多基础的底层库,不可能每个⼈的代码都从零开始,因此库的存在意义⾮同寻常。

本质上来说库是⼀种可执⾏代码的⼆进制形式,可以被操作系统载⼊内存执⾏。库有两种:

  • 静态库 .a[Linux]、.lib[windows]
  • 动态库 .so[Linux]、.dll[windows]

静态库

  • 静态库(.a):程序在编译链接的时候把库的代码链接到可执⾏⽂件中,程序运⾏的时候将不再需要静态库。

  • ⼀个可执⾏程序可能⽤到许多的库,这些库运⾏有的是静态库,有的是动态库,⽽我们的编译默认为动态链接库,只有在该库下找不到动态.so的时候才会采⽤同名静态库。我们也可以使⽤ gcc的 -static 强转设置链接静态库。

    [root@localhost mystdio]# ldd [可执行程序]

ldd命令可以查看可执行程序所链接的库

基本命令:

复制代码
ar -rc libname.a [要打包的.o文件]

ar (归档)能把一堆编译好的目标文件(.o)"捆" 成一个 .a 文件(静态库),方便程序在编译时一次性链接所有需要的代码。

r (replace):表示 "替换" 或 "添加" 目标文件。如果静态库中已有同名的 .o 文件,会用新的 .o 替换;如果库中没有该文件,就新增进去。

c (create):表示 "创建" 静态库。如果指定的 .a 文件不存在,-c 会强制创建它。

将库放到标准路径下

在我们生成库文件,在编译发现会报错这是为什么呢?

那是因为头文件和库都在标准路径下,把头文件放到usr/bin目录下或者在当前目录下,库文件要放到/lib64目录下。

但即使这样他还是会报错。因为对于库,OS会在默认标准路径即/lib64下查找,但是你要告诉他要找的库名字!

而libc.a却不用指定库名字(因为 libc.a 是 C 标准库的静态实现,GCC 等编译器会默认自动链接它,无需手动指定)

-l +库名字表示去标准路径寻找该库,但需要注意的是库的名字需要去掉.a或.so的后缀和lib前缀。

如果不在标准路径下就算指定了库名编译器也是找不到的。

库不放在标准路径下

-L +路径表示除了系统路径,也要去这个路径下找库

-I +路径表示除了系统路径,也要去这个路径下找头文件(就不演示了)

为了方便操作,我们可以创建一个makefile,内容可以这样写

%.o:%.c

gcc -c $<//.o文件的实现方法写哪里都可以,如果在执行某条命令时发现依赖文件没有生成,系统会自动检查makefile中的所有指令看有没有用于生成该依赖文件的

libmystdio.a:mystdio.o mystring.o

ar -rc @ ^

.PHONY:clean

clean:

rm -rf *.a *.o stdc

.PHONY:output

output:

mkdir -p stdc/include//这需要先写mkdir,再写cp指令,这里是按照顺序执行的

mkdir -p stdc/lib

cp -rf *.c stdc/include

cp -rf *.a stdc/lib

tar -czf stdc.tgz stdc//打包压缩(便于传输共享)

动态库

  • 动态库(.so):程序在运⾏的时候才去链接动态库的代码,多个程序共享使⽤库的代码。
  • 动态库可以在多个程序间共享,所以动态链接使得可执⾏⽂件更⼩,节省了磁盘空间。操作系统采⽤虚拟内存机制允许物理内存中的⼀份动态库被要⽤到该库的所有进程共⽤,节省了内存和磁盘空间。

生成需要的.o文件

复制代码
gcc -fPIC -c 源文件

-fPIC 是 GCC 编译器的一个关键选项,全称是 Position-Independent Code(位置无关代码),核心作用是让编译生成的二进制文件(如共享库 .so)能在内存的任意地址加载执行,而不依赖固定内存位置。

生成动态库

复制代码
gcc -o name.so name.o -shared

在 GCC 编译中,-shared 是用于生成动态库(如 .so 文件)的关键选项,它的核心作用是让编译出的库可以被多个程序动态加载、共享使用,而不是像静态库那样被 "复制" 到可执行文件中。

libmystdio.so:mystdio.o mystring.o

gcc -o @ ^ -shared

%.o:%.c

gcc -fPIC -c $<

.PHONY:clean

clean:

rm -rf *.so *.o stdc*

.PHONY:output

output:

mkdir -p stdc/include

mkdir -p stdc/lib

cp -f *.h stdc/include

cp -f *.so stdc/lib

tar -czf stdc.tgz stdc

头⽂件和库⽂件安装到系统路径下

头⽂件和库⽂件和源⽂件在同⼀个路径下

头⽂件和库⽂件有⾃⼰的独⽴路径

当库文件不在标准目录下时,生成了可执行文件后直接./a.out执行也会报错,ldd查看会发现我们a.out找不到库的路径 。

这是因为动态链接器(ld.so)在运行时默认只搜索系统标准目录(如 /lib/lib64/usr/lib 等),不会自动查找可执行文件所在目录或自定义路径下的动态库。

解决方法:

• 拷⻉ .so ⽂件到系统共享库路径下, ⼀般指 /usr/lib、/usr/local/lib、/lib64 或者开篇指明的库路径等

• 向系统共享库路径下建⽴同名软连接

• 更改环境变量: LD_LIBRARY_PATH

• ldconfig⽅案:配置/ etc/ld.so.conf.d/ ,ldconfig更新

动态库与静态库的联系与区别

区别:

  • 动态库中的.o文件形成时多了-fPIC选项,形成库文件时多了-shared选项.
  • 动态库形成的可执行程序时,编译时需要路径,运行时也需要路径,而静态库只有编译时需要路径.

联系:

  • 如果同时提供动态库和静态库,gcc默认使用动态库.
  • 如果指定要静态连接,gcc命令要带上-static选项.
  • 如果只有静态库,将使用静态连接,但程序整体不一定是静态连接的.
  • 如果只有动态库,只能使用动态连接,使用静态连接会报错.

动态库加载

上文主要解释了库是怎么形成的,怎么参与形成可执行文件;它们不运行时都是在磁盘中存储;

当程序运行时,它依赖的动态库是怎么加载到内存,或者说操作系统?

系统角度理解

程序的代码和数据,从磁盘到物理内存,再通过也页表映射加载到进程的代码区和数据区。此时进程需要动态库的代码和数据,不选择加载到进程的代码区和数据区 ,因为不一定只有一个进程需要此动态库,那么动态库的代码和数据就存在公共属性,应该通过页表映射加载到共享区!这样,进程调用库函数依旧在进程地址空间中!

其他问题:

1.库的加载逻辑问题,也就是一个库要不要加载,哪些库加载了?哪些没加载?

这些都是由操作系统决定,目前不用具体了解怎么决定的。

2.加载的库需要被管理

被加载的库存在数量多的情况,需要管理,操作系统依旧基于"先描述,再组织"的思想进行管理

相关推荐
不做无法实现的梦~3 小时前
机载电脑部署安装px4环境详细教程
linux
特轮飞3 小时前
Linux网络协议ARP IGMP ICMP的理解
linux·运维·网络协议
DeeplyMind3 小时前
第10章:中断处理-6:Implementing a Handler
linux·驱动开发
jerryinwuhan3 小时前
Linux常用命令练习题
linux·运维·服务器
Ryan ZX3 小时前
CentOS 7.x 升级 OpenSSH 10.1 与 OpenSSL 3.5.4版本(2025)
linux·运维·centos
鸠摩智首席音效师3 小时前
如何在 Linux 中创建自签名 SSL 证书 ?
linux·ssl
qing222222224 小时前
Ubuntu设置程序开机自启动:基于.service文件实现
linux·运维·ubuntu
CtrlZ学习录4 小时前
笔记:现代操作系统:原理与实现(8)
linux·笔记·架构·开源
不会聊天真君6474 小时前
Linux命令-文件\文件夹、用户\用户组(Linux基础笔记第二期)
linux·笔记