动静态库简述
在本篇我打算从三个角度为大家讲解动静态库的知识这三个角度分别是怎么制作库怎么使用库以及动态库是怎么加载的。在具体讲解之前我们要知道在Linux中静态库文件一般是libxxx.a动态库文件是libxxx.so(xxx是具体的库名称)。在编译的过程中如果链接方式是静态链接那么使用的就是静态库。如果链接方式是动态链接使用的就是动态库。静态库制作静态库为了更好地讲解制作静态库的方法我们将亲手制作一个简单的静态库例如数学库(mymath)库中的方法如下// mymath.h #pragma once extern int myerrno; int add(int x, int y); int sub(int x, int y); int mul(int x, int y); int div(int x, int y);// mymath.c #include mymath.h int myerrno 0; int add(int x, int y) { return x y; } int sub(int x, int y) { return x - y; } int mul(int x, int y) { return x * y; } int div(int x, int y) { if (0 y) { myerrno -1; return -1; } return x / y; }现在我们已经完成了库中的方法再讲如何制作静态库之前我有一个问题要问大家我们怎们才能让其他人使用我们自己的方法呢首先我们可以将我们的方法源码发给其他人(.c和.h)这样他们就能够自己使用。但这样就存在一个问题其他人可能会借鉴或者抄袭代码更过分的是声称那是他们创造的代码这种情况下我们的利益就会受损。所以直接将源码交给他人不太现实那我们要怎么办呢我们先回想一下程序变为可执行文件的过程源代码经过预处理编译和汇编生成目标文件(.o文件)后多个目标文件链接才会生成可执行程序。那么如果我们将自己的方法实现后再编译成目标文件其他人能否使用我们的方法呢答案是肯定的。我们这么做允许其他人使用我们编写的方法的同时他们也无法轻易查看方法实现的细节。如果我们要分享多个源程序我们可以这多个源程序编译成目标文件后将其打包而这便是静态库。简单地说静态库本质上是多个目标文件的集合。原理已经说完了接下来就要讲具体怎么制作静态库了。首先我们需要将所有的源文件编译成目标文件。需要注意的是我们希望将自己所写的方法分享给其他人也就是说生成静态库的源代码中不包含main函数所以在生成静态库阶段不需要将main所在源代码编译成目标文件。我们只需要使用gcc即可即gcc -c mymath.c接着我们要使用ar工具这是gnu归档工具具体命令如下。如果有多个目标文件生成一个静态库我们可以在命令末尾继续列举。ar -rc libmymath.a mymath.o // 多个目标文件 ar -rc libmymath.a add.o sub.o我们可以使用ar -tv查看静态库中的文件。其中-t代表列出静态库的文件-v表示详细信息例如我们可以看到我制造的静态库mymath中只有一个文件那就是mymath.o。同时为了更加规范我将库文件 libmymath.a 放到了 ./test/lib 目录中头文件 mymath.h 放到了 ./test/include 目录中。具体如下// test.c #include mymath.h int main() { printf(5 7 %d\n, add(5, 7)); return 0; }静态库制作好后接下来我们该用一用静态库了。使用静态库测试代码就是刚刚提到的 test.c现在我们要生成可执行程序了。使用指令 gcc结果报错错误内容是无法找到头文件很明显这是编译时报错但是为什么会出现这个错误呢这和 gcc 编译时头文件的搜索规则有关。头文件搜索使用gcc编译源文件时包含头文件的方式不同其头文件的搜索规则不同。如果是使用尖括号包含头文件那么在编译时会跳过当前目录直接去系统标准路径搜索。如果是使用双引号包含头文件编译器会优先在源文件所在目录中搜索(不会搜索该目录下的子目录)。但如果没有找到就会去系统标准规则搜索。所以要解决头文件找不到的问题有简单的办法例如将头文件和源文件放在同一个目录下或者将头文件直接放在系统标准目录中像/usr/include等等。我们可以通过下面的命令输出gcc内置的所有头文件搜索路径在我的机器中运行的部分结果如下gcc -v -E -x c /dev/null前两个方法可以解决问题不过如果你注重自己文件的结构性的话将源文件和头文件放在同一目录下就不太适合。同时如果是我们自己写的库还是不要直接复制在标准路径中了因为可能会污染系统的头文件目录。当然最终决定权在你自己。除了直接复制外我们还能为自己的头文件建立软链接这会减少我们复制的麻烦但仍会污染系统的目录。那么有没有其他方法让我们直接能够找到我们的头文件呢方法一编译选项-I(大写i)我们可以使用这个选项手动指定搜索目录当手动指定目录后被指定的目录搜索的优先级仅次于使用双引号引用头文件时的“当前源文件目录”如果在指定目录中没找到的话则按照之前的规则搜索。例如通过指定目录编译器能够编译源代码了最终可以生成目标文件。我们可以看到在第一次尝试生成可执行程序时失败了而失败原因是无法找到add函数。这就是链接时错误了具体的之后再谈。方法二通过环境变量指定路径gcc在预处理时它会读取专门的环境变量补充头文件搜索路径。这样的环境变量有两个一是C_INCLUDE_PATH它仅仅针对C语言头文件。另一个是CPATH它对C/C头文件都有效。在该环境变量中通过冒号(:)分割不同的路径。下图是具体演示图中我们使用的环境变量是C_INCLUDE_PATH环境变量CPATH我们就不演示了。当然这样设置的是临时环境变量等我们下次重新登陆时就会消失。如果想要设置成永久的就将设置环境变量的命令写入文件~/.bashrc或~/.profile然后执行source ~/.bashrc(具体看你想写哪个文件)。在之前我们提到过gcc编译时头文件的搜索路径优先级问题现在我们就总结一下头文件包含方式完整搜索优先级(由高到低)#include xxx.h1. 当前源文件所在的目录(不进行子目录递归搜索)2.-I选项指定的目录(如果有多个-I指定按顺序)3. 环境变量C_INCLUDE_PATH/CPATH4. 系统默认路径#include xxx.h1.-I选项指定2. 环境变量C_INCLUDE_PATH/CPATH3. 系统默认路径现在已经解决了头文件的搜索问题我们该解决一下链接时具体实现找不到的问题了。我们已经知道了gcc将源文件编译成目标文件(.o)时它会搜索引用的头文件然后将其展开。那么在多个目标文件链接时是否需要搜索函数的具体实现呢(搜索对应的库文件)答案是肯定的。既然链接时要搜索文件那么肯定会有搜索规则甚至是搜索路径链接时的搜索又是什么样的呢库文件搜索在讲具体的库文件搜索规则之前我们需要知道链接库文件时的相关知识gcc在链接库时只认识固定命名规则的库文件就是之前说的静态库名字是libxxx.a动态库名字是libxxx.so。而且库文件的搜索规则是按优先级顺序查找直到找到符合命名的库就会停止查找。库文件的核心搜索优先级如下1. 手动通过-L指定库目录。这是优先级最高的库搜索方式同时我们可以使用多个-L参数指定多个目录此时按先后顺序进行搜索。2. 通过环境变量指定库目录(对应头文件搜索时的C_INCLUDE_PATH/CPATH)。这时我们要使用的环境变量是LIBRARY_PATH使用冒号分隔多个路径即可。也许你的机器上就没有这个环境变量这很正常我也没有。3. gcc内置的系统默认库目录。对于这个不同的Linux发行版路径略有差异但也能找到具体描述。(接下来都是猜测)不知道你们是否记得之前为了找头文件搜索的系统默认路径使用的命令gcc -v -E -x c /dev/null这个命令的运行结果很多行其中有行是LIBRARY_PATH。我觉得这里出现的和上文说的环境变量不是一回事这里的LIBRARY_PATH指的就是gcc内置的系统默认库目录。之后我们可以验证一下。现在我们已经明白了库文件搜索的具体规则我们就能够解决库文件找不到问题了。我们先尝试一下环境变量我们发现虽然我们将路径加入到环境变量里了但是仍然是这个错误这是为什么呢这个问题我们先放置不答我们先试试其他的办法我们在系统默认库目录中建立对应的软链接试一试即使在gcc的系统默认库目录中这个错误仍然没有解决。至于-L指定它也无法解决这个问题为什么呢gcc找不到头文件我们指定头文件。gcc找不到库文件我们将它能找到库文件可是为什么它还是不能将源程序编译成目标文件呢虽然我们将库文件放到了gcc的系统默认库目录中或者使用环境变量或-L告知编译器库所在的路径但是一个目录中有很多文件编译器又怎么知道它需要什么库呢所以除了上面的步骤之外我们还需要指明需要链接的具体库名称。指明库名称我们需要使用选项-l(小写)同时需要注意的是这里的库名称指的是libxxx.a中的xxx而非库文件的全称。当我们再使用-l指定库名称之后我们就能够将源代码编译成可执行文件了。具体如图到目前为止我们已经讲了静态库的制作以及使用。我们自己制作的静态库使用时确实比较麻烦不过编译时涉及到的一些选项是可以进行简化的例如使用环境变量将头文件或者库文件放到系统默认路径下。无论我们是否进行简化使用时都不要忘记-l指定库名称。但是我们在编译C/C程序时我们没指定过C/C标准库文件也能够将源程序编译成可执行程序这是为什么因为我们使用的编译器是默认自动链接标准库文件的不需要我们自己指定标准库文件。动态库制作动态库到现在我们虽然谈不上非常了解静态库但是我们已经可以自己制作并使用自己的静态库了。有了这个基础对于动态库的制作也就比较简单了。实际上无论是动态库还是静态库它们都能够被看做已经编译好的目标文件的集合。因此制作动态库第一步便是将库源文件编译成目标文件。不过和静态库不同的是在编译时我们需要添加编译选项-fPIC这个选项的意思是产生位置无关码。具体的问题之后再讲我们先将动态库制作出来然后用起来再说。具体示例如图生成目标文件后我们就需要将目标文件编成库。我们需要使用的指令仍然是gcc这次也需要加上其他选项即-shared它的意思是生成共享库格式。示例如图我们制作了自己的动态库可以看到生成的动态库默认就具有可执行权限但实际上它并不能运行。为什么gcc在生成动态库时要给予它可执行权限呢我们知道程序在运行时会创建对应的进程同时会将磁盘上的内容数据加载到内存上。进程在执行库函数时会跳到对应的函数位置执行相关的代码这说明动态库也需要将自己的内容数据加载到内存上。因为使用动态库时编译器的链接方式是动态链接因此在程序运行时(程序的代码已经加载好)才会加载动态库的代码所以动态库需要具有将内容数据加载到内存的能力所以它需要有可执行权限。使用动态库动态库已经制作完毕了接下来就是使用动态库了我写了一个简单的测试程序main.c同时我将目录的文件结构调整了一下具体如下#include myerror.h #include myprint.h int main() { errlog(hello, 动态库\n); print(); return 0; }使用动态库和使用静态库几乎一模一样在生成可执行文件时我们同样需要注意头文件搜索和库文件搜索的规则具体的之前已经讲过了。示例如下我们生成了可执行文件但运行不了。报错原因是加载共享库(动态库)时无法打开相应库文件并且不是权限的问题而是根本找不到对应的库文件。对于这个错误我们也可以使用指令ldd它会告诉我们程序所依赖的库例如可以看到库libmyio.so的地址是未知的。明明我们在编译时已经告诉了编译器路径为什么运行时找不到对应的库文件呢很简单编译器的工作是生成可执行程序程序加载和它就没有关系了。所以我们告诉了编译器没有告诉加载器加载程序时就找不到文件了。那么怎么才能将库文件路径告诉加载器呢我们要知道程序加载时也有一套动态库的搜索规则它的搜索优先级如下1. 环境变量LD_LIBRARY_PATH指定的目录(注意和LIBRARY_PATH进行区分)。示例如图2. 可执行文件的rpath路径。这个路径可以在编译时指定我们可以使用-Wl,-rpath./lib添加路径运行时加载器会自动搜索这个路径。示例如下3. 系统配置文件下的目录。在程序加载时加载器还会搜索系统配置文件/etc/ld.so.conf或者/etc/ld.so.conf.d/记录的路径。我们可以将动态库所在路径加入/etc/ld.so.conf文件中或者在/etc/ld.so.conf.d/目录下新建一个conf文件然后使用sudo ldconfig更新缓存即可示例如下4. 默认系统动态库目录。在没有找到动态库时加载器最终都会在系统的默认目录中搜索对应的库文件所以我们只要将自己的库文件放在对应目录下就可以了。系统默认目录有很多例如/lib,/usr/lib,/usr/local/lib等等。示例如下讲到这里我们已经能够自己制作并使用动静态库了。我们一直说的安装一个库简单地说就是将我们下载的成品库的路径进行设置(例如复制创建软链接或者配置环境变量)从而然我们编译和运行时能够简单一点但在使用第三方库进行编译时指明需要的库名称是必不可少的。本篇对于动静态库的讲解到此结束本文为个人观点如有看法欢迎在评论区讨论。

相关新闻

BiTCN-BiGRU-SHAP:可解释时序分类预测模型解析

BiTCN-BiGRU-SHAP:可解释时序分类预测模型解析

1. 项目概述:BiTCN-BiGRU-SHAP可解释分类预测模型在时序数据分类预测领域,传统机器学习方法往往难以捕捉复杂的非线性特征和长期依赖关系。我们提出的BiTCN-BiGRU-SHAP混合模型,通过结合双向时序卷积网络(BiTCN)和双向门控循环单元(BiGRU)的优…

2026/7/23 19:55:21 阅读更多 →
色浆辊涂工艺全解:高效率量产涂装的精密控制技术

色浆辊涂工艺全解:高效率量产涂装的精密控制技术

在现代家具和人造板表面涂装领域,色浆辊涂工艺凭借其极高的生产效率、精准的膜厚控制以及出色的涂膜均匀性,已经成为平板类工件量产涂装的主流技术方案。无论是量身定制的板式家具生产线,还是大规模的人造板贴面和涂装工厂,辊涂流…

2026/7/23 19:54:20 阅读更多 →
从页面到端到端:AI Native时代前端如何升级成为全栈工程师(收藏版)

从页面到端到端:AI Native时代前端如何升级成为全栈工程师(收藏版)

随着AI技术的发展,前端工程师的角色正在从传统的页面实现者向端到端交付者转变。文章详细阐述了AI Native团队的工作模式和所需能力,并提出了前端工程师转型AI全栈的具体学习路线和实施步骤。强调在AI时代,前端工程师需要具备业务理解、系统拆…

2026/7/23 19:54:20 阅读更多 →

最新新闻

学生工作管理系统介绍及功能特点

学生工作管理系统介绍及功能特点

✅作者简介:合肥自友科技 📌核心产品:智慧校园平台(包括教工管理、学工管理、教务管理、考务管理、后勤管理、德育管理、资产管理、公寓管理、实习管理、就业管理、离校管理、科研平台、档案管理、学生平台等26个子平台) 。公司所有人员均有多…

2026/7/23 20:04:24 阅读更多 →
2026年Agent开发爆发!小白程序员必备的收藏指南,助你高薪上岸!

2026年Agent开发爆发!小白程序员必备的收藏指南,助你高薪上岸!

随着AI技术的发展,Agent和大模型开发成为职场新宠。传统软件开发需求下降25%,而AI应用和智能体开发需求增长超过60%。 2026年,Agent开发爆发了! 如果你还沉浸在“只要写好CRUD就能混到退休”的旧梦当中,现实的“冷水”…

2026/7/23 20:04:24 阅读更多 →
OpenWrt 软路由 IPv6 DDNS 动态解析实战指南

OpenWrt 软路由 IPv6 DDNS 动态解析实战指南

1. 为什么你需要IPv6 DDNS?从“找不到家”到随时访问 如果你家里有OpenWrt软路由,并且宽带已经拿到了IPv6公网地址,那你可能已经体验过那种“直连”的快感——手机用流量直接访问家里的NAS,速度快得飞起,不用再忍受内网穿透的转发延迟。但高兴没两天,问题就来了:运营商…

2026/7/23 20:04:24 阅读更多 →
接入6家大模型API后的适配器设计模式总结

接入6家大模型API后的适配器设计模式总结

我总结的6家大模型API接入实战经验与踩坑实录前不久接了一个企业内部智能助手的项目,客户是一家拥有数千名员工的传统制造企业。他们希望把内部知识库和几个主流的大模型能力打通,做一个能问业务数据、也能写代码辅助的聊天机器人。说实话,一…

2026/7/23 20:04:24 阅读更多 →
Stable Diffusion提示词异常问题排查与解决

Stable Diffusion提示词异常问题排查与解决

1. 问题现象:Stable Diffusion提示词中的神秘"xiao yi xian"最近在使用Stable Diffusion生成图片时,发现一个奇怪的现象:无论输入什么提示词,最终生成的图片描述中总会莫名其妙地出现"xiao yi xian"这个词汇。…

2026/7/23 20:04:24 阅读更多 →
OBSGRID软件安装

OBSGRID软件安装

1. 进入OBSGRID目录2. ./configure 选择3部署 NCL 环境 export NCARG_ROOT/work/home/......./apprepo/ncl export PATH$NCARG_ROOT/bin:$PATHNETCDF要在NCARG_ROOT之前 ​​​​​​​export LD_LIBRARY_PATH$NETCDF/lib:$NCARG_ROOT/lib:$LD_LIBRARY_PATH3. 修改configure.oa…

2026/7/23 20:03:24 阅读更多 →

日新闻

从单点好评到指数级传播:AI副业主理人必须掌握的4层口碑渗透模型(含ROI测算表)

从单点好评到指数级传播:AI副业主理人必须掌握的4层口碑渗透模型(含ROI测算表)

更多请点击: https://intelliparadigm.com 第一章:从单点好评到指数级传播:AI副业主理人必须掌握的4层口碑渗透模型(含ROI测算表) 当AI副业主理人不再仅满足于单次服务交付,而是主动构建可复用、可裂变、可…

2026/7/23 0:00:25 阅读更多 →
AI写作开头钩子设计:为什么你的AI文案完读率不足18%?——基于2,346篇A/B测试报告的归因分析

AI写作开头钩子设计:为什么你的AI文案完读率不足18%?——基于2,346篇A/B测试报告的归因分析

更多请点击: https://codechina.net 第一章:AI写作开头钩子设计:为什么你的AI文案完读率不足18%?——基于2,346篇A/B测试报告的归因分析 在对2,346篇跨行业AI生成文案的A/B测试数据进行聚类分析后,我们发现&#xff1…

2026/7/23 0:01:26 阅读更多 →
Chitchatter完整指南:免费开源的终极点对点安全聊天工具

Chitchatter完整指南:免费开源的终极点对点安全聊天工具

Chitchatter完整指南:免费开源的终极点对点安全聊天工具 【免费下载链接】chitchatter Secure peer-to-peer chat that is serverless, decentralized, and ephemeral 项目地址: https://gitcode.com/gh_mirrors/ch/chitchatter Chitchatter是一款革命性的安…

2026/7/23 0:01:26 阅读更多 →

周新闻

Go语言静态资源打包方案对比与实践指南

Go语言静态资源打包方案对比与实践指南

1. 项目背景与核心需求在Go语言开发中,我们经常需要处理静态资源文件的打包问题。无论是Web应用的模板文件、前端资源,还是配置文件、证书等,都需要随程序一起分发。传统做法是将这些文件与编译后的二进制文件放在同一目录下,但这…

2026/7/22 8:58:19 阅读更多 →
Go语言实现高性能LDAP认证服务的架构与实践

Go语言实现高性能LDAP认证服务的架构与实践

1. 项目背景与核心价值LDAP(轻量级目录访问协议)作为企业级身份认证的黄金标准,已经服务了超过80%的财富500强公司。我在金融科技领域实施统一认证体系时,发现传统Java方案存在启动慢、内存占用高等痛点。而Go语言凭借其协程并发模…

2026/7/22 19:43:43 阅读更多 →
【AI面试官实战指南】:用ChatGPT模拟10类高频技术岗面试,3天提升应答精准度92%

【AI面试官实战指南】:用ChatGPT模拟10类高频技术岗面试,3天提升应答精准度92%

更多请点击: https://intelliparadigm.com 第一章:AI面试官实战指南的核心价值与适用场景 AI面试官并非替代人类HR的“黑箱工具”,而是以可解释、可审计、可迭代的方式,赋能招聘全链路的关键基础设施。其核心价值在于将主观经验沉…

2026/7/23 17:49:47 阅读更多 →

月新闻