GCC链接到共享对象';s链接器名称

GCC链接到共享对象';s链接器名称,gcc,linker,ld,shared-objects,Gcc,Linker,Ld,Shared Objects,假设我有: 机器A上的/usr/lib/libsomething.so.1 机器B上的/usr/lib/libsomething.so.2 两台机器都有/usr/lib/libsomething。因此符号链接到各自的lib 如果我使用gcc与-lsomething(甚至/usr/lib/libsomething.so)链接,它将跟随符号链接,并且机器A上的ldd生成如下内容: libsomething.so.1 => /usr/lib/libsomething.so.1 这意味着它将

假设我有:

  • 机器A上的
    /usr/lib/libsomething.so.1
  • 机器B上的
    /usr/lib/libsomething.so.2
两台机器都有
/usr/lib/libsomething。因此
符号链接到各自的lib

如果我使用
gcc
-lsomething
(甚至
/usr/lib/libsomething.so
)链接,它将跟随符号链接,并且机器A上的
ldd
生成如下内容:

libsomething.so.1 => /usr/lib/libsomething.so.1
这意味着它将无法在机器B上找到库

现在我知道这些是主要的版本号更改,我知道它们可能不兼容,但我愿意冒这个风险。我想告诉链接器的是查找
libsomething.so
,不要跟随符号链接,这样
ldd
就会显示出来

libsomething.so => /usr/lib/libsomething.so.1
但是

libsomething.so => /usr/lib/libsomething.so.2
然后加载程序将跟随符号链接到任何版本

另外,我不希望延迟加载dlopen或任何东西。我希望它在编译时链接到共享对象

这可能吗

这意味着它将无法在机器B上找到库

反正也不应该这样

根据的定义,
libsomething.so.2
表示API/ABI与
libsomething.so.1
不兼容。因此,只需在要加载的程序库表中添加
libsomething.so
,实际上是错误的。
libsomething.so
symlink仅作为ld默认选择哪个版本的提示


对于ld最终实际打开的任何文件,都将使用DTNAME/SONAME字段在程序中进行编码。如果你不想那样,就不要用索纳姆来装备你的东西。但它很容易变成痛苦。。。从运行程序时遇到不可用的符号开始。

当然可以使用任何可用版本的共享库制作可执行文件。

问题是您将可执行文件链接到了特定于版本的soname(
libsomething.so.1
libsomething.so.2
)。你应该用未版本的soname
libsomething.so
来完成它

为了实现这一点,在构建机器上,您应该编译并安装soname(ELF
soname
)等于
libsomething.so
(无版本)的库,以便链接器可以在构建可执行文件时选择此soname

根据,您可以在构建库时通过所需的未版本化soname:

gcc -shared -Wl,-soname,libsomething.so -o libsomething.so.X objectsomething.o
然后,一旦安装库并运行
ldconfig
,您就有:

  • 符号链接
    /lib/libsomething.so
    指向机器A上的
    /lib/libsomething.so.1
  • 符号链接
    /lib/libsomething.so
    指向机器B上的
    /lib/libsomething.so.2
加载程序(运行
ldd
)将选择未版本的符号链接,无论它指向何处:

  • libsomething.so=>/lib/libsomething.so(0xNNNNNNNN)
    在机器A上
  • libsomething.so=>/lib/libsomething.so(0xNNNNNNNN)
    在机器B上
Linux动态加载程序(
ld.so
)根据可执行文件中写入的soname值(ELF
NEEDED
)解析库。在构建可执行文件时,从库文件(ELF
SONAME
)复制该值。只要目标系统上有一个符号链接与可执行文件中记录的soname相匹配,就会加载该符号链接指向的库


让我们运行您的设置并显示用于验证假设的命令。

我使用Fedora 18
X86_64
进行测试,并将输出调整为
i686
,以清晰显示

  • 编译
    libsomething.so.1
    libsomething.so.2
    。确保
    SONAME
    设置为unversioned
    libsomething。因此

    readelf -a libsomething.so.1 | grep SONAME
    0xNNNNNNNN (SONAME)             Library soname: [libsomething.so]
    
    readelf -a libsomething.so.2 | grep SONAME
    0xNNNNNNNN (SONAME)             Library soname: [libsomething.so]
    
  • 将库安装到
    /lib/
    目录下各自的计算机中。在两台机器上运行
    ldconfig-v
    ,并验证输出

    ldconfig -v 2>&1 | grep something
    libsomething.so -> libsomething.so.1 (changed)
    
    ldconfig -v 2>&1 | grep something
    libsomething.so -> libsomething.so.2 (changed)
    
  • 编译可执行文件,并确保它引用的是相同的soname,而不是
    NEEDED
    中的版本

    readelf -a executable | grep NEEDED
    0xNNNNNNNN (NEEDED)             Shared library: [libsomething.so]
    
  • 您的可执行文件依赖于未版本化的
    libsomething。所以现在。将可执行文件复制到两台计算机上,并对两个副本运行
    ldd

    ldd executable
    libsomething.so => /lib/libsomething.so (0xNNNNNNNN)
    
    最后一个输出在两台机器上都是相同的,因为可执行文件是使用soname构建的,没有版本。这使加载程序在目标计算机上获取未版本的符号链接。根据机器的不同,符号链接可以指向库
    libsomething.so.1
    libsomething.so.2
    的不同实现


我不是在建这个库,我想真正的答案是不要按照我的建议去做,如果你真的想作弊,就用符号链接吧。这提供了一些很好的信息,所以我接受。