C++ 全栈知识体系C++ 全栈知识体系
✿导航
  • 基础
  • 函数
  • 知识点
  • IO框架
  • 新版本特性
  • 数据库原理
  • SQL语言
  • SQL - MySQL
  • NoSQL - Redis
  • NoSQL - ElasticSearch
  • 算法基础
  • 常见算法
  • 领域算法
  • 分布式算法
  • 数据结构与算法
  • 计算机网络
  • 操作系统
  • 计算机组成
  • 开发
  • 测试
  • 架构基础
  • 分布式系统
  • 微服务
  • 中间件
  • 概念
  • 理论
  • 架构设计原则
  • 设计模式
  • 协议
  • 技术选型
  • 编码规范
  • 流水线构建 - CI/CD
  • 知识点 - Linux
  • 网站 - Nginx
  • 容器化 - Docker
  • 容器编排 - Kubernetes
  • 服务网格 - Service Mesh Istio
  • 常用快捷键 - Shortcut
  • 工具使用 - Tools
  • 开源项目
  • 学习项目
  • 个人项目
  • 项目开发
  • 项目Idea
  • 并发
  • 部署
  • 分布式
  • 知识
  • 问题
  • 编程语言与技术
  • 系统与架构
  • 软件开发实践
  • 数据处理与应用设计
  • 个人
  • 产品
  • 团队
  • 知识体系
  • Vue
关于
✿导航
  • 基础
  • 函数
  • 知识点
  • IO框架
  • 新版本特性
  • 数据库原理
  • SQL语言
  • SQL - MySQL
  • NoSQL - Redis
  • NoSQL - ElasticSearch
  • 算法基础
  • 常见算法
  • 领域算法
  • 分布式算法
  • 数据结构与算法
  • 计算机网络
  • 操作系统
  • 计算机组成
  • 开发
  • 测试
  • 架构基础
  • 分布式系统
  • 微服务
  • 中间件
  • 概念
  • 理论
  • 架构设计原则
  • 设计模式
  • 协议
  • 技术选型
  • 编码规范
  • 流水线构建 - CI/CD
  • 知识点 - Linux
  • 网站 - Nginx
  • 容器化 - Docker
  • 容器编排 - Kubernetes
  • 服务网格 - Service Mesh Istio
  • 常用快捷键 - Shortcut
  • 工具使用 - Tools
  • 开源项目
  • 学习项目
  • 个人项目
  • 项目开发
  • 项目Idea
  • 并发
  • 部署
  • 分布式
  • 知识
  • 问题
  • 编程语言与技术
  • 系统与架构
  • 软件开发实践
  • 数据处理与应用设计
  • 个人
  • 产品
  • 团队
  • 知识体系
  • Vue
关于
  • 编程语言与技术

    • Effective C++: 改善程序与设计的55个具体做法

      • 第2章 - 构造/析构/赋值运算(一)
      • 第2章 - 构造/析构/赋值运算(二)
      • 第2章 - 构造/析构/赋值运算(三)
      • 第3章 - 资源管理
      • 第4章 - 设计与声明(一)
      • 第4章 - 设计与声明(二)
      • 第5章 - 实现(一)
      • 第5章 - 实现(二)
      • 第6章 - 继承与面向对象设计
      • 第7章 - 模板与泛型编程
    • 深度探索C++对象模型

      • 第1章 - 关于对象
      • 第2章 - 构造函数语意学
      • 第3章 - Data 语意学
    • STL源码剖析

      • 第1章 - STL概论和版本简介
      • 第2章 - 空间配置器
      • 第3章 - 迭代器(iterators)概念与traits编程技法(一)
      • 第3章 - 迭代器(iterators)概念与traits编程技法(二)
      • 第4章 - 序列式容器 vector
      • 第4章 - 序列式容器 list
      • 第4章 - 序列式容器 deque
      • 第4章 - 序列式容器 stack和queue
      • 第4章 - 序列式容器 heap
      • 第4章 - 序列式容器 priority_queue
      • 第4章 - 序列式容器 slist
      • 第5章 - 关联式容器 RB-tree
      • 第5章 - 关联式容器 set和map
      • 第5章 - 关联式容器 hashtable
      • 第6章 - 算法
      • 第6章 - 算法之set
      • 第7章 - 仿函数
      • 第8章 - 配接器
  • 系统与架构

    • 深入理解计算机系统

      • 第1章 - 计算机系统漫游
      • 第2章 - 信息的表示和处理
      • 第3章 - 程序的机器级表示
      • 第5章 - 优化程序性能
      • 第6章 - 存储器层次结构
      • 第7章 - 链接
      • 第8章 - 异常控制流
      • 第9章 - 虚拟内存
      • 第10章 - 系统级I/O
      • 第11章 - 网络编程
      • 第12章 - 并发编程
    • 大型网站技术架构——核心原理与案例分析

      • 第1章 - 大型网站架构演化
      • 第2章 - 大型网站架构模式
      • 第3章 - 大型网站核心架构要素
      • 第4章 - 瞬时响应:网站的高性能架构
      • 第5章 - 万无一失:网站的高可用架构
      • 第6章 - 永无止境:网站的伸缩性架构
      • 第7章 - 随需应变:网站的可扩展架构
      • 第8章 - 固若金汤:网站的安全架构
    • 从零开始学架构

      • 架构基础
      • 架构设计原则
      • 高性能架构
      • 高可用架构
    • 程序员的自我修养————链接、装载与库

      • 第1章 - 简介
      • 第2章 - 静态链路
      • 第3章 - 目标文件里有什么
      • 第4章 - 静态链接
      • 第7章 - 动态链接
      • 第8章 - 共享库版本
      • 第10章 - 内存
      • 第11章 - 运行库
      • 第12章 - 系统调用与API
      • 第13章 - 运行库实现
  • 软件开发实践

    • 重构改善既有代码的设计

      • 第1章 - 重构,第一个示例
      • 第2章 - 重构的原则
      • 第3章 - 代码的坏味道
      • 第5章 - 重构列表
      • 第6章 - 重新组织函数
      • 第7章 - 在对象之间搬移特性
      • 第8章 - 重新组织数据
      • 第9章 - 简化条件表达式
      • 第10章 - 简化函数调用
      • 第11章 - 处理概括关系
      • 第12章 - 设计之大型重构
    • 代码大全2

      • 第1章 - 欢迎进入软件构建的世界
      • 第2章 - 用隐喻来更充分地理解软件开发
      • 第3章 - 三思而后行: 前期准备
      • 第4章 - 关键的构建决策
      • 第5章 - 软件构建中的设计
    • Linux多线程服务端编程——使用muduo C++ 网络库

      • Buffer类的设计
      • 设计与实现
      • 定时器与TimerQueue
      • Protobuf网络传输和Protobuf编解码器与消息分发器
      • EventLoop类剖析
      • EventLoopThread和EventLoopThreadPool剖析
      • TCP网络库和核心类
      • Connector剖析
      • TcpClient剖析
      • 学习总结
      • timing wheel
      • 消息广播服务
      • 线程安全的对象生命期管理
  • 数据处理与应用设计

    • 数据密集型应用系统设计

      • 第1章 - 可靠、可扩展与可维护的应用系统
      • 第2章 - 数据模型与查询语言
      • 第3章 - 数据存储与检索
      • 第4章 - 数据编码与演化
      • 第5章 - 数据复制
      • 第6章 - 数据分区
      • 第7章 - 事务

第8章 共享库版本

  • 共享库兼容性
  • 共享库版本命名
  • SO-NAME
  • 符号版本
  • 共享库系统路径
  • 环境变量

文章总结

共享库版本

共享库兼容性

共享库的更新可以被分为两类:

  • 兼容更新。所有的更新只是在原有的共享库基础上添加一些内容,所有原有的接口都保持不变。
  • 不兼容更新。共享库更新改变了原有的接口,使用该共享库原有接口的程序可能不能运行或运行不正常。

我们所说的接口是二进制接口,即ABI(Application Binary Interface)。共享库的ABI跟程序语言有着很大的关系,不同的语言对于接口的兼容性要求不同。ABI对于不同的语言来说,主要包括一些诸如函数调用的堆栈结构、符号命名、参数规则、数据结构的内存分布等方面的规则。

导致C语言共享库ABI改变的行为:

  • 导出函数的行为发生改变。
  • 导出函数被删除。
  • 导出数据的结构发生变化。
  • 导出数据的接口发生变化,如函数返回值、参数被更改。

对于C++来说,ABI问题就更为严重了。由于C++非常复杂,它支持诸如模板等一些高级特性,这些特性对于ABI兼容来说简直就是灾难。因为C++标准对于C++的ABI没有做出规定,所以不同的编译器甚至同一个编译器的不同版本对于c++的一些特性的实现都有着各自的方案,而相不兼容,比如虚函数表、模板实例化、多重继承等。

  • 不要在接口类中使用虚函数,万不得已要使用虚丞数时,不要随意删除、添加或在子类中添加新的实现函数,这样会导致类的虚函数表结构发生变化。
  • 不要改变类中任何成员变量的位置和类型。
  • 不要删除非内嵌的public或protected成员函数。
  • 不要将非内嵌的成员函数改变成内嵌成员函数。
  • 不要改变成员函数的访问权限。
  • 不要在接口中使用模板。
  • 最重要的是,不要改变接口的任何部分或干脆不要使用C++作为共享库接口!

共享库版本命名

Linux有一套规则来命名系统中的每一个共享库,它规定共享库的文件名规则必须如下: libname.so.x.y.z

最前面使用前缀“lib”、中间是库的名字“name”和后缀“so”,最后面跟着的是三个数字组成的版本号。“x”表示主版本号(Major Version Number),“y”表示次版本号(Minor Version Number),“z”表示发布版本号(Release Version Number)三个版本号的含义不一样。

  • 主版本号表示库的重大升级,不同主版本号的库之间是不兼容的。
  • 次版本号表示库的增量升级,即增加一些新的接口符号,且保持原来的符号不变。
  • 发布版本号表示库的一些错误的修正、性能的改进等,并不添加任何新的接口,也不对接口进行更改。

SO-NAME

对于新的系统来说,包括Solaris和Linux,普遍采用一种叫做SO-NAME的命名机制来记录共享库的依赖关系。每个共享库都有一个对应的“SO-NAME”,这个SO-NAME即共享库的文件名去掉次版本号和发布版本号,保留主版本号。比如一个共享库叫做libfoo.so.2.6.1,那么它的SO-NAME即libfoo.so.2。

那么以“SO-NAME”为名字建立软接有什么用处呢?实际上这个软链接会指向目录中主版本号相同、次版本号和发布版本号最新的共享库。

符号版本

Linux下的Glibc从版本2.1之后开始支持一种叫做基于符号的版本机制(Symbol Versioning)的方案。这个方案的基本思路是让每个导出和导入的符号都有一个相关联的版本号,它的实际做法类似于名称修饰的方法。

Linux系统下共享库的符号版本机制并没有被广泛应用,主要使用共享库符号版本机制的是Glibc软件包中所提供的20多个共享库。目前2.6的Glibc中的C语言运行库libc-2.6.1.so来说,它的符号版本演化如下:

GLIBC_2.0、GLIBC_2.1、GLIBC_2.1.1、GLIBC_2.1.2、GLIBC_2.1.3、GLIBC_2.2、GLIBC_2.2.1 ...

共享库系统路径

目前大多数包括Linux在内的开源操作系统都道守一个叫做FHS(File Hierarchy Standard)的标准,这个标准规定了一个系统中的系统文件应该如何存放,包括各个目录的结构、组织和作用,这有利于促进各个开源操作系统之间的兼容性。

FHS规定,一个系统中主要有3个存放共享库的位置,它们分别如下:

  • /lib,这个位置li要存放系统最关键和基础的共享库
  • /usr/lib,这个目录下主要保存的是一些非系统运行时所需要的关键性的共享库
  • /usr/local/lib,这个目录用来放置一些跟操作系统本身并不十分相关的库,主要是一些第三方的应用程序的库。

环境变量

LD_LIBRARY_PATH:可以临时改变某个应用程序的共享库查找路径,而不会响系统中的其他程序。

LD_PRELOAD:可以指定预先装载的一些共享库甚或是目标文件。由于全局符号介入这个机制的存在,LD_PRELOAD里面指定的共享库或目标文件中的全局符号就会覆盖后面加载的同名全局符号,这使得我们可以很方便地做到改写标准c库中的某个或某几个函数而不影响其他函数,对于程序的调试或测试非常有用。

LD_DEBUG:可以打开动态链接器的调试功能,它会在运行时打印出各种有用的信息。

[root@VM-16-6-centos test]# LD_DEBUG=files ./fun_temp
     11198:
     11198:     file=/$LIB/libonion.so [0];  needed by ./fun_temp [0]
     11198:     file=/$LIB/libonion.so [0];  generating link map
     11198:       dynamic: 0x00007f71a5878040  base: 0x00007f71a5775000   size: 0x0000000000105d40
     11198:         entry: 0x00007f71a5776060  phdr: 0x00007f71a5775040  phnum:                  5
     11198:
     11198:
     11198:     file=libstdc++.so.6 [0];  needed by ./fun_temp [0]
Last Updated:
Contributors: klc407073648
Prev
第7章 - 动态链接
Next
第10章 - 内存