英文:
Both main program and dlopen'ed library need different versions of libsqlite3.so
问题
我有一个依赖于 libsqlite3.so
的主程序。通过运行 LD_DEBUG=libs ./my_executable
,我观察到以下情况(我编辑了搜索路径以使其看起来更简单):
386600: find library=libsqlite3.so.0 [0]; searching
386600: search path=/a:/b:/c:/d:/e (RPATH from file /home/me/my_executable)
386600: trying file=/a/libsqlite3.so.0
386600: trying file=/b/libsqlite3.so.0
386600: trying file=/c/libsqlite3.so.0
386600: trying file=/d/libsqlite3.so.0
386600: trying file=/e/libsqlite3.so.0
到目前为止一切正常,运行时链接器正确使用了来自 my_executable
的 RPATH
最终在 /e
中找到了 libsqlite3.so
。
随后,my_executable
继续运行一个 Python 解释器。最终,一个 Python import
调用尝试加载 libsqlite3
,它根据 my_executable
的 RPATH
进行解析,ldd
报告了有关未解析符号的错误。
幸运的是,在这种特定情况下,我可以运行 LD_DEBUG=libs python -c "import IPython"
来查看 Python 需要什么:
396818: find library=libsqlite3.so.0 [0]; searching
396818: search path=/home/me/miniconda3/lib/python3.9/lib-dynload/../.. (RPATH from file /home/me/miniconda3/lib/python3.9/lib-dynload/zlib.cpython-39-x86_64-linux-gnu.so)
396818: trying file=/home/me/miniconda3/lib/python3.9/lib-dynload/../../libsqlite3.so.0
因此,my_executable
和 Python 需要不同版本的 libsqlite3
。首先,是否可以在运行时使用 dlopen
打开共享库的第二个版本,以及如何告诉 dlopen
忽略来自 my_executable
的 RPATH
?
英文:
I have a main program that depends on libsqlite3.so
. By running it with LD_DEBUG=libs ./my_executable
, I observe the following (I edited the search paths to look simpler):
386600: find library=libsqlite3.so.0 [0]; searching
386600: search path=/a:/b:/c:/d:/e (RPATH from file /home/me/my_executable)
386600: trying file=/a/libsqlite3.so.0
386600: trying file=/b/libsqlite3.so.0
386600: trying file=/c/libsqlite3.so.0
386600: trying file=/d/libsqlite3.so.0
386600: trying file=/e/libsqlite3.so.0
So far so good, the runtime linker correctly uses the RPATH
from my_executable
to eventually find libsqlite3.so
in /e
.
Later on, my_executable
goes on to run a python interpreter. Eventually, a python import
call tries to load libsqlite3
and it gets resolved according to the RPATH
from my_executable
, and ldd
throws an error about unresolved symbols.
Thankfully, in this specific case, I can just run LD_DEBUG=libs python -c "import IPython"
to see what Python wants:
396818: find library=libsqlite3.so.0 [0]; searching
396818: search path=/home/me/miniconda3/lib/python3.9/lib-dynload/../.. (RPATH from file /home/me/miniconda3/lib/python3.9/lib-dynload/zlib.cpython-39-x86_64-linux-gnu.so)
396818: trying file=/home/me/miniconda3/lib/python3.9/lib-dynload/../../libsqlite3.so.0
So, my_executable
and python want different versions of libsqlite3
. First of all, is it possible to dlopen
a second version of a shared library at runtime, and how do I tell dlopen
to ignore the RPATH
from my_executable
?
答案1
得分: 0
首先,可以在运行时使用dlopen
打开共享库的第二个版本,只要这两个库在其SONAME
上不同(它们可能不同,但您可以对其中一个或两个进行二进制修补)。
然而,这样做实际上是一个非常糟糕的主意——这两个库很可能会定义相同的一组符号,而且Linux的规则是第一个定义会生效。
这样做可能会导致非常难以调试的崩溃。
实际上,这里发生的情况是你有两个具有相同SONAME
但ABI不同的库(我们知道ABI不同,因为如果它们相同,你就不会遇到未解析的符号——一切都会正常工作)。
然后,如何告诉dlopen
忽略my_executable
的RPATH?
你不能。但是,您可以使用绝对路径(假设具有不同SONAME
)dlopen()
另一个libsqlite3.so.0
。
您最好的选择可能是按照n.m.的建议做:在主程序中使用dlmopen
将您的libsqlite3.so.0
版本加载到单独的加载器命名空间。
英文:
> First of all, is it possible to dlopen a second version of a shared library at runtime
Yes, so long as the two libraries differ in their SONAME
(which they probably don't, but you can binary-patch one or both).
However, doing that is really bad idea -- the two libraries are exceedingly likely to define the same set of symbols, and the linux rules are that the first definition wins.
Doing this will probably cause very hard to debug crashes.
Effectively what's happened here is that you have two libraries with the same SONAME
, but different ABI (we know the ABI's are different because if they weren't, you would not have gotten unresolved symbols -- it would all have just worked).
> and how do I tell dlopen to ignore the RPATH from my_executable
You can't. But you can dlopen()
the other libsqlite3.so.0
using absolute path (provided it has different SONAME
).
Your best bet is probably to do what n.m. suggested: use dlmopen
in your main program to load your version of libsqlite3.so.0
into a separate loader namespace.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论