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
)。你应该用未版本的sonamelibsomething.so
来完成它
为了实现这一点,在构建机器上,您应该编译并安装soname(ELFsoname
)等于libsomething.so
(无版本)的库,以便链接器可以在构建可执行文件时选择此soname
根据,您可以在构建库时通过所需的未版本化soname:
gcc -shared -Wl,-soname,libsomething.so -o libsomething.so.X objectsomething.o
然后,一旦安装库并运行ldconfig
,您就有:
- 符号链接
指向机器A上的/lib/libsomething.so
李>/lib/libsomething.so.1
- 符号链接
指向机器B上的/lib/libsomething.so
/lib/libsomething.so.2
ldd
)将选择未版本的符号链接,无论它指向何处:
在机器A上李>libsomething.so=>/lib/libsomething.so(0xNNNNNNNN)
在机器B上libsomething.so=>/lib/libsomething.so(0xNNNNNNNN)
ld.so
)根据可执行文件中写入的soname值(ELFNEEDED
)解析库。在构建可执行文件时,从库文件(ELFSONAME
)复制该值。只要目标系统上有一个符号链接与可执行文件中记录的soname相匹配,就会加载该符号链接指向的库
让我们运行您的设置并显示用于验证假设的命令。 我使用Fedora 18
X86_64
进行测试,并将输出调整为i686
,以清晰显示
- 编译
和libsomething.so.1
。确保libsomething.so.2
设置为unversionedSONAME
: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
最后一个输出在两台机器上都是相同的,因为可执行文件是使用soname构建的,没有版本。这使加载程序在目标计算机上获取未版本的符号链接。根据机器的不同,符号链接可以指向库ldd executable libsomething.so => /lib/libsomething.so (0xNNNNNNNN)
或libsomething.so.1
的不同实现libsomething.so.2