当前位置: 首页 > news >正文

运行程序时总是提示带so.xx.xx版本号共享库打不开(共享库的不同命名的含义)

运行程序时总是提示带so.xx.xx版本号共享库打不开(共享库的不同命名的含义)

  • 写作目的
  • 正文
  • 总结

写作目的

最近在写 Redis c++客户端的demo,从github上下载了 hiredis库源码,自己编译 hiredis源码得到名为 ‘libhiredis.so’ 的共享库文件,放到我的demo工程中进行使用。编译成功后,运行demo的时候发现一直报错:

ubuntu@linux:~/test/common_redis/build$ ./main-test 
./main-test: error while loading shared libraries: libhiredis.so.1.2.1-dev: cannot open shared object file: No such file or directory

我很奇怪,‘libhiredis.so’ 是存在的,编译也没问题,但运行怎么会报‘‘libhiredis.so.1.2.1-dev’’找不到的错误,想不通‘libhiredis.so.1.2.1-dev’是从哪里来的,CmakeList.txt和代码中都没有出现过‘‘libhiredis.so.1.2.1-dev’’字符串。 之前对共享库的链接原理一直朦朦胧胧,所以这次来探究一下,写下这篇文章记录一下。

正文

先了解动态库三个名字:

  1. linker-name
    linker-name 是链接器链接共享库所用到的名字,其格式为 libxxx.so ,也就是说其不带任何版本号, gcc编译 链接时就是找它,可以是一个软链接。
  2. soname
    soname 是一个很重要的名字,全称是 Shared Object Name(共享对象名称),其格式为 libxxx.so.a,也就是在 linker name 后面加上主版本号,可以是一个软链接。
  3. real-name
    real-name 就是共享库实际文件的真实名称,传统意义上来说,一个共享库的真实名称应该是 libxxx.so.a.b.c 的格式,但实际上并不一定。

要注意的是,soname 是直接被保存在共享库的二进制文件中的,通过‘readelf -d’命令可以查看:

ubuntu@linux:~/test$ readelf -d libhiredis.so
Dynamic section at offset 0x13de0 contains 25 entries:标记        类型                         名称/值0x0000000000000001 (NEEDED)             共享库:[libc.so.6]0x000000000000000e (SONAME)             Library soname: [libhiredis.so.1.2.1-dev]   ##### 看这行0x000000000000000c (INIT)               0x3000...

然而,在编译链接的时候,可执行文件链接的就是共享库的 soname 名称,虽然编译链接时查找的是 linker-name文件,但是可执行文件实际链接 linker-name中的‘SONAME’属性指定的共享库名称, 如下(main-test是C++可执行文件):

ubuntu@linux:~/test$ ldd main-test linux-vdso.so.1 (0x00007ffc53be2000)libhiredis.so.1.2.1-dev => /home/ubuntu/test/libhiredis.so.1.2.1-dev (0x000078740143a000) ##### 看这行...

因此,如果共享库的 soname 文件不存在,运行程序就报 "xxx.so.xx 无法打开!"的错误,导致程序无法启动,这时可以手动创建 soname 文件(软链接,指向 real-name 文件):

ubuntu@linux:~/test$ ln -s libhiredis.so libhiredis.so.1.2.1-dev

这样,程序就能正常运行了。

总结

real-name:共享库实际文件的真实名称,一般带有完整的版本号。
linker-name: 用于编译链接,其格式为 libxxx.so。
soname: 一般带有主版本号,用于兼容性控制,使得共享库的小更新(不影响版本兼容性)不需要重新编译可执行文件,只要重新链接到新的到新版本 real name文件,原来的可执行文件即可以自动加载新版的共享库。
linker-name 和 soname 文件一般都是 指向real-name文件的软链接。

参考链接:https://blog.csdn.net/qq_21746331/article/details/120333736

相关文章:

  • MySQL的登录、访问、退出
  • 伊犁云计算22-1 apache 安装rhel8
  • 如何在 Rust 中通过 Rumqttc 实现 MQTT 通信
  • Cannot read properties of undefined (reading ‘upgrade‘)
  • R包:ggheatmap热图
  • Redis发布和订阅
  • C++三大特性——继承性(超万字详解)
  • 【推荐一个好用的AI】
  • 小程序-生命周期与WXS脚本
  • Java之线程篇六
  • <Java>String类型变量的使用
  • 构建高可用和高防御力的云服务架构第五部分:PolarDB(5/5)
  • 四款负载均衡工具Nginx、HAProxy、MetalLB、gobetween 比较
  • 【HTTP】认识 URL 和 URL encode
  • Android 使用反射 反射获取activity
  • CentOS7 安装JDK
  • Essential Studio for ASP.NET Web Forms 2017 v2,新增自定义树形网格工具栏
  • ES学习笔记(12)--Symbol
  • JavaScript 一些 DOM 的知识点
  • jdbc就是这么简单
  • mysql常用命令汇总
  • React系列之 Redux 架构模式
  • 服务器之间,相同帐号,实现免密钥登录
  • 个人博客开发系列:评论功能之GitHub账号OAuth授权
  • 力扣(LeetCode)965
  • 前端存储 - localStorage
  • 前端面试之CSS3新特性
  • 使用 @font-face
  • 腾讯优测优分享 | Android碎片化问题小结——关于闪光灯的那些事儿
  • 要让cordova项目适配iphoneX + ios11.4,总共要几步?三步
  • ​香农与信息论三大定律
  • #QT项目实战(天气预报)
  • ${ }的特别功能
  • (145)光线追踪距离场柔和阴影
  • (19)夹钳(用于送货)
  • (delphi11最新学习资料) Object Pascal 学习笔记---第8章第2节(共同的基类)
  • (LLM) 很笨
  • (附源码)小程序儿童艺术培训机构教育管理小程序 毕业设计 201740
  • (三分钟了解debug)SLAM研究方向-Debug总结
  • (十六)串口UART
  • (收藏)Git和Repo扫盲——如何取得Android源代码
  • (一)插入排序
  • (转)Sql Server 保留几位小数的两种做法
  • (转)清华学霸演讲稿:永远不要说你已经尽力了
  • (转)树状数组
  • (转)自己动手搭建Nginx+memcache+xdebug+php运行环境绿色版 For windows版
  • .L0CK3D来袭:如何保护您的数据免受致命攻击
  • .net framework profiles /.net framework 配置
  • .NET 依赖注入和配置系统
  • .NET 中让 Task 支持带超时的异步等待
  • .NET/C# 编译期能确定的字符串会在字符串暂存池中不会被 GC 垃圾回收掉
  • .NET3.5下用Lambda简化跨线程访问窗体控件,避免繁复的delegate,Invoke(转)
  • .NET中GET与SET的用法
  • //TODO 注释的作用
  • @Controller和@RestController的区别?