首页/新闻资讯/正文详情

【Linux】 动静态库

发布时间:2026/11/6 19:55:24 来源:云帆数科 栏目:资讯中心
【Linux】 动静态库
一、基础概念什么是库1.1 库的本质在 Linux 环境下无论是静态库还是动态库其本质都是源文件对应的.o目标文件的集合。简单来说库的制作就是把一堆.o文件打包压缩并配上相应的头文件.h以便于他人复用代码同时又能保护源代码不被泄露。1.2 静态库与动态库的命名规范在 Linux 中库的命名有着严格的规范编译器也是通过特定的前后缀来识别库文件的静态库前缀为lib后缀为.a。例如libmyc.a。动态库前缀为lib后缀为.so。例如libmyc.so。Windows 环境下的对应静态库通常以后缀.lib结尾。动态库通常以后缀.dllDynamic Link Library结尾。二、静态库的制作与使用2.1 静态库的打包制作静态库本质上是一种归档文件。我们可以使用ararchive命令将编译生成的.o文件打包成.a静态库。# 1. 将所有源文件编译成对应的目标文件 .ogcc-cmy_stdio.c calc.c# 2. 使用 ar 命令将 .o 文件打包为静态库# -r (replace)若库中已有同名文件则替换# -c (create)创建新的归档文件ar-rclibmyc.a my_stdio.o calc.oMakefile 示例libmyc.a: calc.o my_stdio.o ar -rc $ $^ calc.o: calc.c gcc -c $^ my_stdio.o: my_stdio.c gcc -c $^ .PHONY: clean clean: rm -rf *.o *.a静态库中要不要包含main函数绝对不能包含。库是提供给他人调用的功能集合如果库中包含了main函数会与使用者项目中的main函数发生符号冲突导致链接失败。使用file libmyc.a命令查看该文件可以清晰地看到其属性为ar archive[ljmiZ0jlgycwuno4vikja7kneZ lib_a]$file./lib/mylib/libmyc.a ./lib/mylib/libmyc.a: current ar archive2.2 静态库的发布与交付为了方便使用者安装和使用我们通常会将头文件和库文件组织到一个特定的目录结构中并打包压缩lib/ ├── include/ │ ├── my_stdio.h │ └── calc.h └── mylib/ └── libmyc.acalc.o: calc.c gcc -c $^ my_stdio.o: my_stdio.c gcc -c $^ .PHONY: output output: mkdir -p lib/include mkdir -p lib/mylib cp -f *.h lib/include cp -f *.a lib/mylib tar czf lib.tgz lib .PHONY: clean clean: rm -rf *.o *.a我们可以使用tar czf lib.tgz lib将其打包为压缩包这就是一个简易的库安装包。还可以写一个安装脚本和卸载脚本放里面如果你愿意的话。2.3 静态库的常规链接与使用当使用者拿到我们的库之后由于gcc默认不会去当前工作目录下寻找非标准库的头文件和库文件因此在编译用户的源文件如code.c时必须通过显式选项指明路径gcc code.c-ocode-Ilib/include/-Llib/mylib/-lmyc选项含义解析-I指明头文件的搜索路径告诉编译器去哪里找头文件。-L指明库文件的搜索路径告诉编译器去哪里找库文件。-l指明需要链接的库名称去掉lib前缀和.a/.so后缀。以上包含头文件都可以因为我们在编译时带了-I选项。但是如果我们不想写这么长只能用绝对路径或者相对路径gcc code.c-ocode-Llib/mylib/-lmyc那我们又能不能把-L也去掉、像正常编译一样呢这就要先回答这个问题了为什么 C/C 的标准库不需要这些-I、-L、-l选项因为gcc/g编译器默认就认识系统的标准库它们存放在特定的系统标准路径下如/usr/include、/lib64编译器会自动去这些路径检索并完成链接。若我们要链接任何非 C/C 标准库包括第三方库或我们自己写的库都需要用这些选项明确指出。2.4 从生产者到用户为了更直观地理解静态库的制作。在这个案例中项目被划分为两个核心角色开发者与使用者。1. 开发者的目录视角作为库的创作者开发者负责编写核心源代码并完成打包交付。其工作目录如下code ├── calc.h # 核心功能头文件 ├── calc.c # 核心功能实现源文件 ├── my_stdio.h # 字符串工具头文件 ├── my_stdio.c # 字符串工具源文件 ├── calc.o # 静态库专用目标文件 ├── my_stdio.o # 静态库专用目标文件 ├── lib/ # 准备交付的规范目录 │ ├── include/ # 包含所有的对外公开头文件 (calc.h, my_stdio.h) │ └── mylib/ # 存放打包生成的静态库文件 (libmyc.a) └── lib.tgz # 最终交付给用户的压缩包开发者在code目录下执行gcc -c calc.c my_stdio.c生成普通的目标文件。随后利用ar -rc libmyc.a *.o将它们归档为静态库。将生成的库放入lib/mylib/将对应的头文件放入lib/include/最后通过tar czf lib.tgz lib打包发布。2. 使用者的目录视角作为库的引入和使用者拿到了创作者发布的lib.tgz并在自己的工作空间内解压、编写业务逻辑。其工作目录如下code ├── lib.tgz # 从 Mr.Li 处获取的静态库压缩包 ├── lib/ # 解压出来的库资源 │ ├── include/ # 引入的头文件 (calc.h, my_stdio.h) │ └── mylib/ # 引入的静态库 (libmyc.a) ├── code.c # 自己的业务代码 ├── Makefile # 自动化编译脚本 └── code # 最终链接生成的独立可执行程序编译运行实操使用者在 Makefile 中封装了链接规则执行编译时实际调用的底层指令为gcc code.c-ocode-Ilib/include/-Llib/mylib-lmyc由于是静态链接编译成功后生成的code可执行程序已经将库中my_stdio.o和calc.o的二进制代码拷贝到了自身内部。此时哪怕彻底删除解压出来的整个lib/目录code依然可以独立运行。三、动态库的制作与使用3.1 动态库的特殊编译与打包动态库共享对象与位置无关这意味着它在内存中可以被多个进程共享。因此编译动态库时需要引入特殊的编译选项# 1. 产生位置无关码Position Independent Code# 必须使用 -fPIC 选项gcc-fPIC-cmy_stdio.c calc.c# 2. 使用 -shared 选项进行动态库打包gcc-shared-olibmyc.so calc.o my_stdio.oMakefile 示例libmyc.so: calc.o my_stdio.o gcc -shared -o libmyc.so $^ calc.o: calc.c gcc -fPIC -c $^ my_stdio.o: my_stdio.c gcc -fPIC -c $^ .PHONY: output output: mkdir -p lib/include mkdir -p lib/mylib cp -f *.h lib/include cp -f *.so lib/mylib tar czf lib.tgz lib .PHONY: clean clean: rm -rf *.o *.so lib *.tgz使用file libmyc.so命令查看该文件可以清晰地看到其属性为shared object且属于dynamically linked[ljmiZ0jlgycwuno4vikja7kneZ lib_shared]$file./lib/mylib/libmyc.so ./lib/mylib/libmyc.so: ELF64-bit LSB shared object, x86-64, version1(SYSV), dynamically linked, BuildID[sha1]9f99535aaf01594fba368359548c3c7c7c06c13d, not stripped3.2 动态库的运行报错问题在使用上动态库的编译链接指令和静态库一模一样gcc code.c-ocode-Ilib/include-Llib/mylib-lmyc然而当编译成功并尝试执行时系统却会抛出错误[ljmiZ0jlgycwuno4vikja7kneZ user]$ ./code ./code: errorwhileloading shared libraries: libmyc.so: cannotopenshared object file: No suchfileor directory1. 为什么静态库没有这个问题静态链接时编译器将库中的代码直接拷贝到了最终的可执行程序中。程序一旦生成就不再依赖原有的静态库文件因此可以独立运行。而动态链接在编译时只是在可执行程序中记录了符号表等信息。当程序真正运行时操作系统需要将动态库加载到内存中。2. 核心根源编译器 ≠ 操作系统使用ldd code查看程序依赖的动态库会发现libmyc.so not found。通过-L选项和-l仅仅是告诉了gcc编译器去哪里找什么名字的库但是操作系统OS在运行程序时并不知道这个路径。根本原因在于编译阶段和运行阶段是由两个完全不同的角色负责的。gcc 只管编译阶段你在编译时用-L选项是告诉gcc编译器“嘿你去这个路径下帮我把关一下看有没有这个动态库有的话就允许编译通过。”gcc听话地去看了发现库在于是给你的可执行程序盖了个戳记录下这个程序运行时需要链接libmyc.so然后gcc的工作就彻底结束了。操作系统只管运行阶段当你敲下./code运行程序时负责把程序加载到内存并跑起来的是操作系统内核与动态链接器ld-linux.so。这时候gcc早已下班了。操作系统要帮你去找libmyc.so加载到内存里但它根本不知道gcc编译时用的-L路径是什么你告诉了gcc库在哪里并不等于告诉了操作系统库在哪里。操作系统有它自己固定寻找动态库的路径类似于 PATH比如/lib64、LD_LIBRARY_PATH等。如果你的自定义路径不在它的朋友圈里操作系统就会抛出not found的报错。四、解决动态库无法加载的四种方案为了让操作系统在运行时能够成功定位并加载我们的动态库可以采用以下四种主流方案4.1 方案一拷贝至系统标准路径所谓的安装Linux 系统的动态链接器默认会自动前往系统标准路径下搜寻动态库。因此将我们自己的头文件和库文件拷贝进去在本质上就是完成了库的安装。# 将头文件拷贝到系统标准的头文件搜索路径sudocplib/include/* /usr/include/# 将动态库文件拷贝到系统标准的库文件搜索路径sudocplib/mylib/libmyc.so /lib64/相比于直接放入系统的/lib64对于用户自己编译、安装的第三方库更推荐的标准做法是放置在/usr/local/include与/usr/local/lib或/usr/local/lib64下这样能避免与系统自带的、由包管理器如yum维护的系统基础库发生冲突。自己安装一个第三方库sudoyuminstall-yncurses-devel4.2 方案二在系统标准路径下建立软链接如果不希望破坏系统原有目录或直接复制文件可以在系统标准库路径下为我们的动态库建立一个快捷方式软链接sudoln-s/home/ljm/day15/lib_shared/user/lib/mylib/libmyc.so /lib64/libmyc.so当我们在这些标准路径下建立一个指向自定义动态库的软链接时操作系统在扫描标准目录并尝试加载该库时会顺着该软链接的路径追踪到我们在用户目录下维护的真实.so文件。4.3 方案三配置环境变量 LD_LIBRARY_PATH操作系统在运行动态链接的程序时会专门去检查名为LD_LIBRARY_PATH的环境变量。我们可以将动态库所在的绝对路径追加到该环境变量中exportLD_LIBRARY_PATH$LD_LIBRARY_PATH:/home/ljm/day15/lib_shared/user/lib/mylib/这种在命令行中通过export配置的环境变量是内存级别的。一旦当前的终端会话被关闭或重新打开该配置就会失效。4.4 方案四在/etc/ld.so.conf.d/下添加配置文件这是系统级别的永久生效方案。Linux 系统允许我们在/etc/ld.so.conf.d/目录下任意创建一个专属的配置文件并在其中记录动态库的搜索路径# 1. 在配置目录下创建一个自定义的配置文件sudovim/etc/ld.so.conf.d/my_test_lib.conf# 2. 将动态库所在的绝对路径直接粘贴进文件中并保存退出/home/ljm/day15/lib_shared/user/lib/mylib/# 3. 运行 ldconfig 命令使系统的缓存配置重新加载生效sudoldconfig此时使用ldd code查看即可看到库路径已成功匹配程序可以永久正常运行。五、动静态库混合链接的优先级在 Linux 系统下默认情况下安装的大部分库都优先安装和提供动态库。5.1 gcc 的默认行为gcc/g默认情况下倾向于使用动态库进行链接。如果我们在同一个路径下同时存在同名的动态库和静态库例如同时存在libmyc.so和libmyc.a并且编译时不加特殊限制gcc-ocode code.c-Ilib/include/-Llib/mylib/-lmyc使用file code查看生成的可执行程序会发现它优先选择动态库进行链接dynamically linked。5.2 强制静态链接如果我们非要进行静态链接必须在编译命令的末尾显式加上-static选项gcc code.c-ocode-Ilib/include-Llib/mylib-lmyc-static这个时候会报错因为我们没有安装 C 的静态库要安装一下[ljmiZ0jlgycwuno4vikja7kneZ user]$ gcc code.c-ocode-Ilib/include-Llib/mylib-lmyc-static/usr/bin/ld: cannotfind-lccollect2: error: ld returned1exitstatus[ljmiZ0jlgycwuno4vikja7kneZ user]$sudoyuminstall-yglibc-static局限性约束一旦使用了-static选项就意味着程序中所有的库都必须存在对应的静态库版本。如果系统中缺失了某一个依赖库如 C 标准库的静态版本整个编译过程将会直接报错。只有当系统只存在静态库、完全没有动态库时gcc别无选择才会默认对该库采取静态链接。

相关推荐

Lean 4 形式化攻坚第三篇:五次 clean PASS 为何仍未过门——坏集损失 producer、合并清洗与排序块均值门
Lean 4 形式化攻坚第三篇:五次 clean PASS 为何仍未过门——坏集损失 producer、合并清洗与排序块均值门

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/5 3:59:30

测试代码相关
测试代码相关

<!-- 全局音频播放器&#xff0c;由父窗口统一管理 --><audio id"masterAudio" style"display:none;"></audio><script>// 提供给子页面调用&#xff1a;借用子页面的刷卡按键动作来激活父窗口的播放权限window.unlockParentAudio… · 2026/11/5 3:58:30

从硬编码到因果推导:广告语生成的两条代码路径
从硬编码到因果推导:广告语生成的两条代码路径

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/5 3:58:30

2026河南最新政策下工厂电工作业视频大全怎么用?别让证书耽误你找工作
2026河南最新政策下工厂电工作业视频大全怎么用?别让证书耽误你找工作

2026河南最新政策下工厂电工作业视频大全怎么用?别让证书耽误你找工作 别等了,现在就告诉你, 急需特种作业证才能上岗找工作 ,这年头没证连门都进不去。2026年河南最新政策对特种作业证的监管又加码了, 工厂电工作业视频大全… · 2026/11/6 19:55:11

内江特种电工证内部消息:实操考试心里没底怕挂科?这几点你必须知道
内江特种电工证内部消息:实操考试心里没底怕挂科?这几点你必须知道

内江特种电工证内部消息:实操考试心里没底怕挂科?这几点你必须知道 实操考试心里没底怕挂科?这年头,考个内江特种电工证,不光是为了一份工作,更是为了在行业里站稳脚跟。很多人担心自己操作不熟练,怕在考试中挂科,耽误时间又浪费钱。其实,只要掌握了… · 2026/11/6 19:55:11

内江特种电工证在哪考?新手快速上岗全流程指南
内江特种电工证在哪考?新手快速上岗全流程指南

内江特种电工证在哪考?新手快速上岗全流程指南 你是不是也和我一样,手里拿着内江的户口本,却因为没有特种电工证,一直找不到合适的工作?别急,今天我就来聊聊 内江特种电工证 到底 在哪考 ,以及从报名到取证的全流程,让你少走弯路,顺利上岗。… · 2026/11/6 19:55:11

电工证还有ic卡吗?良心建议助你快速上岗拿高薪
电工证还有ic卡吗?良心建议助你快速上岗拿高薪

电工证还有ic卡吗?良心建议助你快速上岗拿高薪 现在找工作,没有特种作业证根本进不了门,尤其是电工证,很多工地、工厂都明确要求持证上岗,没有证连面试资格都没有。如果你正愁不知道电工证还有没有ic卡,那就得听我说说,这证现在到底怎么考、怎么用… · 2026/11/6 19:55:11

考电工证怎考证全国通用吗
考电工证怎考证全国通用吗

电工证怎么考?实操考试心里没底怕挂科?这3个地方你必须知道 实操考试心里没底怕挂科?这事儿我太懂了。去年我带着一个河南小哥去考低压电工证,他连电笔怎么用都不太清楚,结果一上手就手忙脚乱。这不是怕挂科,是真怕出事儿。很多人不知道【在哪考】,更… · 2026/11/6 19:55:11

花都高级电工证咨询千万别踩坑,电工证上岗找工作必须知道的事
花都高级电工证咨询千万别踩坑,电工证上岗找工作必须知道的事

花都高级电工证咨询千万别踩坑,电工证上岗找工作必须知道的事 现在找工作,很多岗位都明确写着“ 持证上岗 ”,尤其是像电工、焊工这些特种作业岗位,没有证连面试资格都没有。特别是像 花都高级电工证咨询… · 2026/11/6 19:54:11

双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试
双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/5 10:27:59

STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析
STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/5 10:28:03

DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案
DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/6 10:29:23

三菱PLC数据采集到数据库的时序设计:Python+MC协议实战
三菱PLC数据采集到数据库的时序设计:Python+MC协议实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/6 1:02:11

ASIC主模式RTL设计:状态机与三态驱动的流片级实现
ASIC主模式RTL设计:状态机与三态驱动的流片级实现

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/6 1:02:11

STM32嵌入式C++开发:GDB调试与Renode仿真实战指南
STM32嵌入式C++开发:GDB调试与Renode仿真实战指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/6 1:02:11

双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试
双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/5 10:27:59

STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析
STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/5 10:28:03

DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案
DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/6 10:29:23

了解更多?预约专属演示

我们的顾问将为您一对一讲解产品与方案

企业微信二维码