linux dll hell--链接库real name, soname, link name

DLL hell 是指 Windows 系统上动态库的新版本覆盖旧版本,且新版本不能兼容旧版本的问题。

例如:装新软件,但原有的软件运行不起来了。

Linux 系统下也同样面临着和 Windows 一样的动态库多版本的问题,其严重影响软件的升级和维护。

那么此问题该如何解决的呢?
Linux 系统为解决这个问题,引入了一套机制,如果遵守这个机制来做,就可以避免这个问题。
但是这只事一个约定,不是强制的。
但是建议遵守这个约定,否则同样也会出现 Linux 系统版的 DLL hell 问题。

下面来介绍一个这个机制。
这个机制是通过文件名,来控制共享库(Shared Library)的版本,它有三个名字,分别又有不同的目的。

1)第一个是共享库的实际文件名(Real Name),
  它是编译器产生共享库时或人为修改名字后的文件名,该实际文件名就是为了直观地控制共享库版本。
  其格式为:lib + math + .so + 主版本号 + 小版本号 + 制作号
  如:libmath.so.1.1.1234。
 
  lib      是 Linux 系统上的库的约定前缀名,
  math     是库自已的名字,
  so       是共享库的后缀名,
  1.1.1234 是共享库的版本号,
           格式:主版本号 + 小版本号 + 制作(build)号。
              主版本号 - 代表当前共享库的版本,
                     如果共享库提供的接口函数有变化的话,那么这个版本号就要加壹(1);
              小版本号 - 如果引入了新的特性(Feature)的话,那么这个版本号就要加壹(1);
              制作号  - 一般仅表示修正了Bug。

2)第二个是共享库的简短文件名(soname - Short for shared object name),
  它是可执行程序加载它时,要寻找的文件名。
  其格式为:lib + math + .so + 主版本号
  如:libmath.so.1
  注:在编译链接生成一个实际文件名的共享库时,同时也将简短文件名写进了共享库的文件头里面。
    可以用此命令来查看:$readelf -d 共享库的实际文件名

3)第三个是共享库的连接文件名(Link Name),
  是专门为可执行程序生成阶段链接共享库时用的名字,不带任何版本信息的。
  其格式为:lib + math + .so
  如:libmath.so。

在可执行程序链接共享库时:首先会用到共享库的连接文件名,通过连接文件名找到共享库; 然后会取出共享库的简短文件名,并写在共享库自己的文件头里面。
在可执行程序加载共享库时: 通过共享库的简短文件名在给定的路径下寻找共享库。

举例说明:

一 源代码

//hello.h

void hello();

//hello.c

#include "hello.h" 
 #include <stdio.h>
 void hello() {
     printf("libhello");
 }

//main.c

#include "hello.h"
int main() {
     hello(); 
}

二 生成

1.生成动态链接库

# gcc hello.c -shared -fPIC -Wl,-soname,libhello.so.0 -o libhello.so.0.0.0

 

2.运行readelf -d libhello.so.0.0.0显示:

[[email protected] tst]$ readelf -d libhello.so.0.0.0 
Dynamic section at offset 0xe08 contains 25 entries:
Tag Type Name/Value
0x0000000000000001 (NEEDED) Shared library: [libc.so.6]
0x000000000000000e (SONAME) Library soname: [libhello.so.0]
0x000000000000000c (INIT) 0x588
0x000000000000000d (FINI) 0x708
0x0000000000000019 (INIT_ARRAY) 0x200de8
0x000000000000001b (INIT_ARRAYSZ) 8 (bytes)
0x000000000000001a (FINI_ARRAY) 0x200df0
0x000000000000001c (FINI_ARRAYSZ) 8 (bytes)
0x000000006ffffef5 (GNU_HASH) 0x1f0
0x0000000000000005 (STRTAB) 0x380
0x0000000000000006 (SYMTAB) 0x230
0x000000000000000a (STRSZ) 190 (bytes)
0x000000000000000b (SYMENT) 24 (bytes)
0x0000000000000003 (PLTGOT) 0x201000
0x0000000000000002 (PLTRELSZ) 72 (bytes)
0x0000000000000014 (PLTREL) RELA
0x0000000000000017 (JMPREL) 0x540
0x0000000000000007 (RELA) 0x480
0x0000000000000008 (RELASZ) 192 (bytes)
0x0000000000000009 (RELAENT) 24 (bytes)
0x000000006ffffffe (VERNEED) 0x460
0x000000006fffffff (VERNEEDNUM) 1
0x000000006ffffff0 (VERSYM) 0x43e
0x000000006ffffff9 (RELACOUNT) 3
0x0000000000000000 (NULL) 0x0

 

3. 执行ldconfig -vn .  (有点),在当前目录县生成soname链接到 libhello.so.0.0.0,此时如下:

运行前:

[[email protected] tst]$ ll
total 20
-rw-rw-r--. 1 qingze qingze 79 Nov 29 13:47 hello.c
-rw-rw-r--. 1 qingze qingze 14 Nov 29 12:44 hello.h
-rwxrwxr-x. 1 qingze qingze 8005 Nov 29 15:19 libhello.so.0.0.0
-rwxrwxr-x. 1 qingze qingze 48 Nov 29 15:26 main.c

运行后:

[[email protected] tst]$ ll
total 20
-rw-rw-r--. 1 qingze qingze 79 Nov 29 13:47 hello.c
-rw-rw-r--. 1 qingze qingze 14 Nov 29 12:44 hello.h
lrwxrwxrwx. 1 qingze qingze 17 Nov 29 15:30 libhello.so.0 -> libhello.so.0.0.0
-rwxrwxr-x. 1 qingze qingze 8005 Nov 29 15:19 libhello.so.0.0.0
-rwxrwxr-x. 1 qingze qingze 48 Nov 29 15:26 main.c

 

4.运行 ln -s libhello.so.0 libhello.so:

[[email protected] tst]$ ll
total 20
-rw-rw-r--. 1 qingze qingze 79 Nov 29 13:47 hello.c
-rw-rw-r--. 1 qingze qingze 14 Nov 29 12:44 hello.h
lrwxrwxrwx. 1 qingze qingze 13 Nov 29 15:33 libhello.so -> libhello.so.0
lrwxrwxrwx. 1 qingze qingze 17 Nov 29 15:30 libhello.so.0 -> libhello.so.0.0.0
-rwxrwxr-x. 1 qingze qingze 8005 Nov 29 15:19 libhello.so.0.0.0
-rwxrwxr-x. 1 qingze qingze 48 Nov 29 15:26 main.c

 

5.运行gcc main.c -o main -Wl,-rpath=./ -L. -lhello

[[email protected] tst]$ ll
total 32
-rw-rw-r--. 1 qingze qingze 79 Nov 29 13:47 hello.c
-rw-rw-r--. 1 qingze qingze 14 Nov 29 12:44 hello.h
lrwxrwxrwx. 1 qingze qingze 13 Nov 29 15:33 libhello.so -> libhello.so.0
lrwxrwxrwx. 1 qingze qingze 17 Nov 29 15:30 libhello.so.0 -> libhello.so.0.0.0
-rwxrwxr-x. 1 qingze qingze 8005 Nov 29 15:19 libhello.so.0.0.0
-rwxrwxr-x. 1 qingze qingze 8538 Nov 29 15:36 main
-rwxrwxr-x. 1 qingze qingze 48 Nov 29 15:26 main.c

 

gcc编译链接动态库时,很有可能编译通过,但是执行时,找不到动态链接库,那是

因为-L选项指定的路径只在编译时有效,编译出来的可执行文件不知道-L选项后面的值,

当然找不到。可以用ldd <your_execute>看看是不有 ‘not found’在你链接的库后面,

解决方法是通过-Wl,rpath=<your_lib_dir>,使得execute记住链接库的位置

个人理解:

参考了网上一些资料,一步步执行时会发生错误,我按照以上方法成功了,所以我认为当动态链接库版本发生变化时只要重新执行第4步,将libhello.so链接到新版本即可!

有待求证!!!

时间: 2024-10-27 11:11:35

linux dll hell--链接库real name, soname, link name的相关文章

Linux下 静态链接库 和 动态链接库

先来说说C/C++编译过程 编译: 检查语句符号定义,将C/C++代码翻译生成中间语言. 链接: 将中间代码整合,生成可执行的二进制代码. 简单的说,库文件都是一种特殊的中间语言文件,静态库还是一种特殊格式的归档文件(打包的文件). 使用静态库: 1. 先编写库函数 1 #ifndef _PRINT_TEST_H_ 2 3 #define _PRINT_TEST_H_ 4 #ifdef __cplusplus 5 extern "C" 6 { 7 #endif 8 9 extern i

linux下静态链接库的用法

最近在Linux下编程发现一个诡异的现象,就是在链接一个静态库的时候总是报错,类似下面这样的错误: (.text+0x13): undefined reference to `func' 关于undefined reference这样的问题,大家其实经常会遇到.在此,我以详细示例给出常见错误的各种原因以及解决办法,希望对初学者有所帮助. 1.  链接时缺失了相关目标文件(.o) 编译命令: gcc -c test.c gcc -c main.c 得到两个.o文件,一个是main.o,一个是tes

Linux编程中链接库的使用

链接库本质上是一段可执行的二进制代码,可以被操作系统载入内存执行.按加载的时机不同,链接库可以分为静态链接库和动态链接库. 静态链接库:编译过程中加载进可执行文件的库(静态库省去了运行时加载的消耗,但会导致可执行文件体积增大)动态链接库:程序运行过程中,动态加载进内存的库(动态库加载需要资源消耗,但可以显著降低可执行文件体积) 什么情况下使用链接库?1.大型软件项目中,不同模块可以各自完成,然后封装成链接库供上层模块调用.2.一些通用的功能,如文件处理.数据库接口.算法等,可以封装成库,从而避免

linux下的动态链接库和静态链接库到底是个什么鬼?(二)动态链接库的编译与使用

上一篇文章里讲解了linux下静态链接库的编译与使用,下面我们来聊聊动态链接库的编译与使用方法. 所谓动态链接库,也就是说编译的时候不会真的把你引用到的库给编到你的执行程序里,而是在执行时候才会去加载相关的库,所有用到此库的程序可以共享一份代码,这样带来的好处是可执行程序所占的空间变小了,同时,如果库需要升级,你并不需要重新编译你的程序,只要把相关的库升级即可. 接下来我们来看看动态链接库的编译与使用方法,代码还是和上文中的一样,分别为?sum.c, sum.h, 和main.c, 在linux

Linux-静态链接库和动态链接库

博文说明[前言]: 本文将通过个人口吻介绍Linux中静态链接库和动态链接库相关知识,在目前时间点[2017年6月14号]下,所掌握的技术水平有限,可能会存在不少知识理解不够深入或全面,望大家指出问题共同交流,在后续工作及学习中如发现本文内容与实际情况有所偏差,将会完善该博文内容. 本文参考文献引用链接: 1.http://developer.51cto.com/art/201107/275783.htm[动态链接库]2.http://www.jianshu.com/p/8743a0edb1ee

C++基础知识 动态链接库和静态链接库

动态链接库 dll: Dynamic-link Library 是一种不可执行的二进制程序文件,包含被可执行程序和其他dll调用的函数. windows中最重要的dll: Kernel32.dll:管理内存.进程.线程. User32.dll:执行用户界面任务,比如窗口的创建和消息的传送. GDI32.dll:画图和显示文本. dll不是唯一的扩展名,如linux下常常是.so. 使用: 需要文件1:.lib(引入库):注意不是静态库,包含该dll导出的函数和变量符号名. 需要文件2 : dll

GCC 编译过程和链接库

GCC 加工程序的过程 在Linux下进行C语言编程,必然要采用GNU GCC来编译C源代码生成可执行程序. 一.GCC使用 Gcc指令的一般格式为:Gcc [选项] 要编译的文件 [选项] [目标文件] 其中,目标文件可缺省,Gcc默认生成可执行的文件名为:a.out 我们来看一下经典入门程序"Hello World!" # vi  main.c #include <stdio.h> void main () { printf("hello world!\n&q

Java框架JNA调用C方法(windows链接库dll文件、linux链接库so文件)

介绍 给大家介绍一个最新的访问本机代码的Java框架-JNA. JNA(Java Native Access)框架是一个开源的Java框架,是SUN公司主导开发的,建立在经典的JNI的基础之上的一个框架. JNA项目地址:https://jna.dev.java.net/ 非常强大.易用,功能上类似与.NET的P/Invoke. 不堪回首的JNI 我们知道,使用JNI调用.dll/.so共享类库是非常非常麻烦和痛苦的. 如果有一个现有的.dll/.so文件,如果使用JNI技术调用,我们首先需要另

linux下动态链接库.so文件 静态链接库.a文件创建及使用

转摘网址为:http://www.cnblogs.com/fengyv/archive/2012/08/10/2631313.html Linux下文件的类型是不依赖于其后缀名的,但一般来讲:    .o,是目标文件,相当于windows中的.obj文件    .so 为共享库,是shared object,用于动态连接的,和dll差不多    .a为静态库,是好多个.o合在一起,用于静态连接    .la为libtool自动生成的一些共享库,vi编辑查看,主要记录了一些配置信息.可以用如下命令