GCC 链接到共享对象的链接器名称
假设我
- 在机器 A 上有:
/usr/lib/libsomething.so.1
; - 机器 B 上的
/usr/lib/libsomething.so.2
。
两台机器都有 /usr/lib/libsomething.so
符号链接到各自的库。
如果我使用 gcc
与 -lsomething
(甚至 /usr/lib/libsomething.so
)链接,它将遵循符号链接,并且ldd 会产生如下内容:
libsomething.so.1 => /usr/lib/libsomething.so.1
这意味着它将无法在机器 B 上找到该库。
现在我知道这些是主要版本号更改,并且我知道它们可能不兼容,但我'我愿意冒这个风险。我想告诉链接器的是寻找libsomething.so
,并且不要遵循符号链接,这样ldd
将显示
libsomething.so => /usr/lib/libsomething.so.1
在A上但
libsomething.so => /usr/lib/libsomething.so.2
在B上。然后加载程序将遵循符号链接到任何版本。
另外,我不想使用 dlopen 或其他任何东西延迟加载。我希望它在编译时链接到共享对象。
这可能吗?
Suppose I have:
/usr/lib/libsomething.so.1
on machine A;/usr/lib/libsomething.so.2
on machine B.
Both machines have /usr/lib/libsomething.so
symlinking to their respective libs.
If I link using gcc
with -lsomething
(or even /usr/lib/libsomething.so
) it will follow the symlink, and ldd
on machine A produces something like:
libsomething.so.1 => /usr/lib/libsomething.so.1
This means it won't be able to find the library on machine B.
Now I know these are major version number changes and I know they may not be compatible, but I'm willing to take that risk. What I'd like to tell the linker is to look for libsomething.so
, and don't follow the symlink so ldd
will show
libsomething.so => /usr/lib/libsomething.so.1
on A but
libsomething.so => /usr/lib/libsomething.so.2
on B. And then the loader will follow the symlink to whatever version is there.
Also, I don't want delayed loading with dlopen or anything. I want it to link to the shared object at compile time.
Is this even possible?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
制作使用共享库的任何可用版本的可执行文件当然是可能的。
问题是您将可执行文件链接到特定于版本的soname(
libsomething.soname)。 so.1 和 libsomething.so.2)。您应该使用未版本化的 soname
libsomething.so
来完成此操作。为了实现这一点,在构建机器上,您应该编译并安装soname(ELF
SONAME
)等于libsomething.so
(无版本)的库,以便链接器可以选择构建可执行文件时使用此soname。根据共享库HOWTO,您可以传递所需的未版本化soname 在构建库时:
然后,一旦安装库并运行
ldconfig
,您就会得到:/lib/libsomething.so
指向机器 A 上的/lib/libsomething.so.1
;/lib/libsomething.so
指向机器 B 上的/lib/libsomething.so.2
。加载器(运行
ldd
)将选择无版本控制的符号链接,无论它指向何处:libsomething.so =>;机器 A 上的 /lib/libsomething.so (0xNNNNNNNN)
;libsomething.so =>;机器 B 上的 /lib/libsomething.so (0xNNNNNNN)
。Linux 动态加载程序 (
ld.so
) 根据可执行文件中写入的 soname 值解析库(ELFNEEDED< /代码>)。该值是在构建可执行文件时从库文件 (ELF
SONAME
) 复制的。只要目标系统上存在与可执行文件中记录的soname匹配的符号链接,就会加载该符号链接指向的库。让我们运行一下您的设置并显示命令来验证假设。
我使用 Fedora 18
X86_64
进行测试,并为了清晰起见将输出调整为i686
。编译
libsomething.so.1
和libsomething.so.2
。确保将SONAME
设置为未版本化的libsomething.so
:将库安装到各自计算机的
/lib/
目录下。在两台计算机上运行 ldconfig -v 并验证输出。<前><代码>ldconfig -v 2>&1 | grep 一些东西
libsomething.so ->; libsomething.so.1(已更改)
ldconfig -v 2>&1 | ldconfig -v 2>&1 | grep 一些东西
libsomething.so ->; libsomething.so.2(已更改)
编译可执行文件并确保它引用相同的soname,但
NEEDED
中没有版本。您的可执行文件现在依赖于未版本化的
libsomething.so
。将可执行文件复制到两台计算机并针对两个副本运行ldd
。最后的输出在两台机器上是相同的,因为可执行文件是使用 soname 构建的,没有版本。这使得加载程序在目标机器上采用未版本化的符号链接。根据机器的不同,符号链接可以指向库
libsomething.so.1
或libsomething.so.2
的不同实现。Making executable which uses any available version of shared library is, of course, possible.
The problem was that you linked your executable to version-specific soname (
libsomething.so.1
andlibsomething.so.2
). You should have done it with unversioned sonamelibsomething.so
instead.In order to achieve this, on the build machine you should compile and install library with soname (ELF
SONAME
) equal tolibsomething.so
(without version) so that linker can choose this soname while executable is built.According to the Shared Libraries HOWTO, you can pass required unversioned soname while building the library:
Then, as soon as you install the library and run
ldconfig
, you have:/lib/libsomething.so
pointing to/lib/libsomething.so.1
on machine A;/lib/libsomething.so
pointing to/lib/libsomething.so.2
on machine B.The loader (run
ldd
) will choose unversioned symlinks regardless where it points to:libsomething.so => /lib/libsomething.so (0xNNNNNNNN)
on machine A;libsomething.so => /lib/libsomething.so (0xNNNNNNNN)
on machine B.Linux dynamic loader (
ld.so
) resolves libraries based on their soname value written in the executable (ELFNEEDED
). The value is copied from library file (ELFSONAME
) while building the executable. As long as there is a symlink on the target system matching the soname recorded in the executable, the library pointed by this symlink will be loaded.Let's run through your setup and show commands to verifing assumptions.
I used Fedora 18
X86_64
for the test and adjusted output toi686
for clarity.Compile both
libsomething.so.1
andlibsomething.so.2
. Make sureSONAME
is set to unversionedlibsomething.so
:Install the libraries into their respective machines under
/lib/
directory. Runldconfig -v
on both machines and verify the output.Compile executable and make sure that it refers to the same soname without version in
NEEDED
.You executable depends on unversioned
libsomething.so
now. Copy executable to both machines and runldd
against both copies.The last output is the same on both machines as the executable was built with soname without version. This makes loader take unversioned symlinks on targets machines. And depending on the machine, the symlink can point to different implementation of the library
libsomething.so.1
orlibsomething.so.2
.而且无论如何也不应该找到。
根据版本的定义,
libsomething.so.2
表示 API/ABI 与libsomething.so.1
不兼容。因此,仅仅在要加载的程序的库表中添加libsomething.so
实际上是错误的。 libsomething.so 符号链接仅充当 ld 默认选择哪个版本的提示。无论 ld 最终打开什么文件,它都将使用 DTNAME/SONAME 字段在程序中进行编码。如果您不想这样,请不要为 libsomething 配备 soname。但它很容易变得痛苦......从尝试运行程序时遇到不可用的符号开始。
And it's not supposed to anyway.
By the very definition of soversions,
libsomething.so.2
denotes that the API/ABI is incompatible tolibsomething.so.1
. Therefore, just addinglibsomething.so
in the program's table of libraries to be loaded would be factually wrong. Thelibsomething.so
symlink merely serves as a hint to ld as to which soversion to pick by default.Of whatever file ld actually ended up opening, it will take the DTNAME/SONAME field to encode in the program. If you don't want that, don't equip libsomething with a soname. But it can easily become pain... starting with running into unavailable symbols when trying to run the program.