找到一个linux静态库动态库的好资料.3

# 正文

继续整理从这个页面学到的东西:https://tldp.org/HOWTO/Program-Library-HOWTO。

之前的在这里:
找到一个linux静态库动态库的好资料.0
找到一个linux静态库动态库的好资料.1
找到一个linux静态库动态库的好资料.2
这一篇继续看这个: https://tldp.org/HOWTO/Program-Library-HOWTO/shared-libraries.html

这个页面主要讲共享库,原文是shared libraries。就是linux里常见的后缀为.so的文件,其中so是缩写了“shared object”[e1]。共享库是在程序启动时就加载。只要共享库是被正确得安装了,那么后续启动的所有程序都会自动使用新的共享库。共享库的设计十分精巧,这些设计精巧到支持你这么整:
- 如果新的共享库与之前的不兼容,就可以让一些程序仍然使用旧库的前提下,让新程序使用新的库。
- 在执行某个程序时使用指定的、“重写”过的库或“重写”过的函数[e2]
- 在程序正在使用着已有共享库的过程中做上边2件事情。

要做到上边说的事情,得遵守若干关于共享库的惯用方式。要搞清楚这些共享库的惯用方式,首先要搞清楚共享库的各种名字,比如so名、真实名。还得搞清楚共享库该保存在哪里。这的“so名”和“真实名”是直接翻译自原文的“soname”和“real name”,我觉得这里使用原词更方便一些,所以下文就是用“soname”和“real name”了。先上个图:

上图红色圆圈里的,就是soname,就说libselinux.so.1吧,“lib”是个前缀,“.so”是扩展名,“.1”是个版本号。一般最底层的C库名字并不以“lib”作为前缀,好比上图的linux-vdso.so.1。原文还有一个概念叫“fully-qualified soname”,就是带路径的soname。一个“fully-qualified soname”通常是个软连接,比如下图的/lib64/libpcap.so.2:

上边图上的/lib64/libcap.so.2.48就是real name了,其中的“.2”的2是次版本号,“.48”的48是release号;release号是可选的,不一定得有。“.2.48”这种次版本号+release号的约定,是为了让人看到即知晓具体的库版本。

还有一个名字,就是编译器调用共享库时使用的名字,即以“.so”结束的,比如/lib64/libcap.so。原文作者管这个叫“linker name”,咱也跟着叫吧。

原文作者认为要盘共享库,关键就是搞清楚这些个名字。还说:
列出程序需要的共享库时,只列出so名即可(上上个图,带圆圈的那个);
然后说,当创建一个共享库时,只是创建了一个带有版本信息的文件;
当需要安装一个新版本的共享库时,就要把它放到指定的目录,再执行ldconfig(8)。
ldconfig会检查目录里有哪些文件,创建指向文件的符号链接、同时设置缓存文件/etc/ld.so.cache

ldconfig不会去管linker name(链接器使用的名字)的事情。
通常,linker name是在安装共享库时手动设置:即创建一个指向最新版本的共享库的软连接。
原文作者说他问过H.J. Lu[e3]这个问题:为何ldconfig不设计为自动设置linker name?得到的回答基本是这个意思:用户也有可能想让开发环境使用旧的库,所以ldconfig不做任何假定,而是让用户必须单独进行一下更新软连接的操作。

总结一下:/usr/lib/libreadline.so.3是个“fully-qualified soname”,它通常是个由ldconfig创建的软连接,指向一个真实名类似 /usr/lib/libreadline.so.3.0的共享库文件;还有一个链接器使用的名字linker name,/usr/lib/libreadline.so,它是指向/usr/lib/libreadline.so.3的软连接,通常是手动设置的。

到这里应该去试一下的,但是要试一下就得用ldconfig,所以还得再说一下ldconfig。我们要先知道有一个东东叫程序加载器,原词program loader,它是操作系统的提供的,负责在启动程序时将程序文件和库文件放到内存里,并为程序的执行做一些准备性工作[e4]。有的程序需要很多的共享库,那么在启动时查找若干目录并加载它们,这就很低效,所以就引入了缓存机制。

ldconfig(8)就是用来建立这些缓存的,如此,程序启动时程序加载器就直接使用缓存里的共享库,效率就比较高了[e5]

现在我们去看ldconfig(8)的man page。上边说ldconfig会搜索一些目录,创建一些必要的符号连接,这些符号连接指向最新的共享库(shared linraries);“一些目录”包含命令行传入的目录、/etc/ld.so.conf里配置的目录、以及/lib、/usr/lib(/lib64、/usr/lib64)。这些缓存由run-time linker(即ld.so或ld-linux.so)使用。

ldconfig创建的缓存都是保存在/etc/ld.so.cache里。/etc/ld.so.cache是一个二进制文件,保存了动态库的列表;ldconfig -p可以打印这个列表:



 

好了,我们现在编一个动态库,试试上边说的这些。其实《找到一个linux静态库动态库的好资料.1.docx》里面的共享库示例就说到一个,刚才看了下,其实很适合贴到这里来。不过我打算再练习一下,弄得稍微不一样一点儿,所以再试一次,一边试一边记录,写到哪里算哪里。

前边说ldconfig会根据/etc/ld.so.conf配置的目录创建缓存,而/etc/ld.so.conf里面只有一行:include ld.so.conf.d/*.conf:

所以我们在/etc/ld.so.conf.d/目录下新加一个配置文件test.conf,里面配上本次测试用的目录/root/nice-teammate:

现在我们编一个real name为libhello.so.0.0的共享库,命令贴在这里了:
gcc -fPIC -shared -Wl,-soname,libhello.so.0 -o libhello.so.0.0 libhello.c -lc

然后,我们使用ldconfig将其加入缓存:

我们发现ldconfig创建了一个软链接名曰libhello.so.0。

看起来这个libhello.so.0与gcc的选项-Wl,-soname,libhello.so.0有关,所以去掉这个选项再试一把:

可以发现ldconfig列出的soname为libhello.so.0.0,也不创建什么软连接了(因为也不需要)。

现在我们还是按指定soname为libhello.so.0的方式:

然后手动创建一个软连接:ln -sf libhello.so.0 libhello.so

创建一个main.c代码如下:

然后编译可执行程序main,使用命令:gcc -o main main.c -L ./ -lhello

哦,可能是不手动创建给编译器用的软链接libhello.so,那gcc的-lhello就不方便了。

看起来已经是一片相当凑合的文章了,欧。

# ENDNOTES

e1

e2

这里的“重写”即override,类似java语法里子类重写父类方法的意思,原文是:override specific libraries or even specific functions in a library when executing a particular program.

e3

e4

在unix系统中,程序加载器除了去调exec系统调用(原文是:The loader is the handler for the system call execve().),任务还包括:
- 校验权限,内存需求等
- 把保存着指令的可执行文件放入内存
- 把命令行的参数放到内存
- 初始化寄存器
- 跳到程序的入口

参考:https://en.wikipedia.org/wiki/Loader_(computing)
看下了《UNIX环境高级编程》的8.3节,基本也是这个意思。

e5

这一个小自然段就是https://tldp.org/HOWTO/Program-Library-HOWTO/shared-libraries.html上的,原文是:Searching all of these directories at program start-up would be grossly inefficient, so a caching arrangement is actually used. The program ldconfig(8) by default reads in the file /etc/ld.so.conf, sets up the appropriate symbolic links in the dynamic link directories (so they'll follow the standard conventions), and then writes a cache to /etc/ld.so.cache that's then used by other programs. This greatly speeds up access to libraries. The implication is that ldconfig must be run whenever a DLL is added, when a DLL is removed, or when the set of DLL directories changes; running ldconfig is often one of the steps performed by package managers when installing a library. On start-up, then, the dynamic loader actually uses the file /etc/ld.so.cache and then loads the libraries it needs.

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/65488.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

nginx 基于 geoip 模块限制地区访问

1、安装 geoip 库 [rootVM-0-15-centos ~]# yum -y install geoip geoip-devel 2、下载并安装 MaxMind 的免费 GeoIP 数据库。这里我选择下载 GeoLite2 数据库,适用于大多数应用。 访问 maxmind 官网(https://www.maxmind.com/)&#xff0c…

openfeign-一些配置

之前整理过一篇 openfeign的快速使用。openfeign简化服务间调用-笔记-CSDN博客 今天补充一下一些个性化配置。 一 日志: 默认的openfeign不输出日志,想看日志需要单独配置下。 日志级别 public static enum Level {NONE,BASIC,HEADERS,FULL;private…

【回溯】LeetCode经典题目总结:组合、排列、子集、分割、N皇后、单词搜索

回溯 组合问题组合总和全排列子集分割回文串N皇后电话号码的字母组合单词搜索括号生成 组合问题 给定两个整数 n 和 k,返回 1 … n 中所有可能的 k 个数的组合。 示例: 输入: n 4, k 2 输出: [ [2,4], [3,4], [2,3], [1,2], [1,3], [1,4], ] 树形结构&#xff1…

HEIC 是什么图片格式?如何把 iPhone 中的 HEIC 转为 JPG?

在 iPhone 拍摄照片时,默认的图片格式为 HEIC。虽然 HEIC 格式具有高压缩比、高画质等优点,但在某些设备或软件上可能存在兼容性问题。因此,将 HEIC 格式转换为更为通用的 JPG 格式就显得很有必要。本教程将介绍如何使用简鹿格式工厂&#xf…

【实战示例】面向对象的需求建模

前言 博主准备写一个以面向对象为核心思想的软件需求建模、领域建模的系列,总结一整套可落地的DDD的打法,前面几篇文章论述了如何进行面向对象的需求建模,本文将以一个简单的购物商城的需求来演示如何进行面向对象的需求建模。 面向对象的需…

04-微服务02

我们将黑马商城拆分为5个微服务: 用户服务 商品服务 购物车服务 交易服务 支付服务 由于每个微服务都有不同的地址或端口,相信大家在与前端联调的时候发现了一些问题: 请求不同数据时要访问不同的入口,需要维护多个入口地址…

Node.js 工具:在 Windows 11 中配置 Node.js 的详细步骤

一、概述 记录时间 [2024-12-25] 本文讲述如何在 Windows 11 中进行 Node.js 工具的安装和配置。 以下是详细的步骤和说明。 二、安装 Node.js 1. 官网下载 通过官网,下载 Node.js,上面有好几种下载方式,文中下载的是 zip 压缩包。 如图&…

Element-plus自动导入

安装 npm i element-plus 自动引入 1. 安装两个插件 npm install -D unplugin-vue-components unplugin-auto-import2. 配置插件 vue3项目修改vite.config.js,把两个插件添加入即可,注意:不是覆盖原有配置 Vite // vite.config.js import { define…

基于FISCO BCOS的电子签章系统

概述 本项目致力于构建一个安全、高效且功能完备的电子印章系统,通过整合区块链技术与传统数据库管理,为用户提供了可靠的电子签章解决方案,有效应对传统电子签章系统的数据安全隐患,满足企业和个人在数字化办公环境下对电子文档…

【2025最新计算机毕业设计】基于SpringBoot+Vue在线考试系统(源码包运行)【提供源码+答辩PPT+文档+项目部署】

作者简介:✌CSDN新星计划导师、Java领域优质创作者、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和学生毕业项目实战,高校老师/讲师/同行前辈交流。✌ 主要内容:🌟Java项目、Python项目、前端项目、PHP、ASP.NET、人工智能…

如何设置Edge浏览器访问软件

使用Edge浏览器访问分销ERP A\V系列软件时会出现各种报错,如何设置Edge浏览器使其正常访问,请看下面的具体操作。 一、打开Edge浏览器,点击右上角的 设置及其他,如图: 二、在弹出界面中,点击 扩展&#xff…

[创业之路-222]:波士顿矩阵与GE矩阵在业务组合选中作用、优缺点比较

目录 一、波士顿矩阵 1、基本原理 2、各象限产品的定义及战略对策 3、应用 4、优点与局限性 二、技术成熟度模型与产品生命周期模型的配对 1、技术成熟度模型 2、产品生命周期模型 3、技术成熟度模型与产品生命周期模型的配对 三、产品生命周期与产品类型的对应关系 …

计算机图形学知识点汇总

一、计算机图形学定义与内容 1.图形 图形分为“图”和“形”两部分。 其中,“形”指形体或形状,存在于客观世界和虚拟世界,它的本质是“表示”;而图则是包含几何信息与属性信息的点、线等基本图元构成的画面,用于表达…

Tomcat介绍、下载安装、使用(部署项目)

天行健,君子以自强不息;地势坤,君子以厚德载物。 每个人都有惰性,但不断学习是好好生活的根本,共勉! 文章均为学习整理笔记,分享记录为主,如有错误请指正,共同学习进步。…

2024.12.29(进程线程实现并发服务器)

作业 多进程多线程并发服务器实现一遍提交。 服务器 #include <myhead.h> #define PORT 12345 #define IP "192.168.124.123"void *fun(void *fd) {int newfd *(int *)fd;char buff[1024];while(1){int res recv(newfd,buff,sizeof(buff),0);if(res 0){p…

初学STM32 ---高级定时器互补输出带死区控制

互补输出&#xff0c;还带死区控制&#xff0c;什么意思&#xff1f; 带死区控制的互补输出应用之H桥 捕获/比较通道的输出部分&#xff08;通道1至3&#xff09; 死区时间计算 举个栗子&#xff08;F1为例&#xff09;&#xff1a;DTG[7:0]250&#xff0c;250即二进制&#x…

brupsuite的基础用法常用模块(1)

proxy模块&#xff1a; Options: 设置代理端口&#xff0c;默认为8080端口&#xff0c;若8080端口被占用可在该界面更改代理端口. HTTP history: 拦截的历史请求&#xff0c;右键可做更多操作&#xff0c;很多操作与其他模块有关。&#xff08;清除历史的话右键选择clear p…

Linux 笔记 SELinux 常见操作与介绍

SELinux&#xff08;Security-Enhanced Linux&#xff09;是 Linux 操作系统中的一种安全模块&#xff0c;旨在提供更细粒度的访问控制。它最初由美国国家安全局&#xff08;NSA&#xff09;开发&#xff0c;目的是增强 Linux 系统的安全性。SELinux 通过强制访问控制&#xff…

Postman接口测试03|执行接口测试、全局变量和环境变量、接口关联、动态参数、断言

目录 七、Postman 1、安装 2、postman的界面介绍 八、Postman执行接口测试 1、请求页签 3、响应页签 九、Postman的环境变量和全局变量 1、创建环境变量和全局变量可以解决的问题 2、postman中的操作-全局变量 1️⃣手动设置 2️⃣代码设置 3️⃣界面获取 4️⃣代…

旅游管理系统|Java|SSM|VUE| 前后端分离

【技术栈】 1⃣️&#xff1a;架构: B/S、MVC 2⃣️&#xff1a;系统环境&#xff1a;Windowsh/Mac 3⃣️&#xff1a;开发环境&#xff1a;IDEA、JDK1.8、Maven、Mysql5.7 4⃣️&#xff1a;技术栈&#xff1a;Java、Mysql、SSM、Mybatis-Plus、VUE、jquery,html 5⃣️数据库…