在Linux中强制动态链接器在运行时加载库 [英] Force dynamic linker to load library at runtime in Linux
问题描述
有一点历史,我有3个库:
- 没有依赖项的"lib1.so"
- 与"lib1.so"链接的"lib2.so"
- 没有依赖项的测试"可执行程序
我需要的是在运行时通过"dlopen"方法从测试"可执行文件动态加载"lib2.so".问题在于"lib1.so"由于链接器不知道在哪里找到而无法自动加载.
我首先尝试像这样加载"lib1.so":
void* ptr_lib1 = dlopen("/usr/local/test/lib1.so", RTLD_NOW | RTLD_GLOBAL);
void* ptr_lib2 = dlopen("/usr/local/test/lib2.so", RTLD_NOW | RTLD_GLOBAL);
但是由于某种原因,它不起作用,调用第二个dlopen(dlerror中的文本)后,它给了我错误:
"lib1.so: cannot open shared object file: No such file or directory"
这意味着"lib1.so"正试图加载两次:第一次是当我为"lib1.so"调用dlopen时,第二次是当我为"lib2.so"调用dlopen时.
任何人都可以解释为什么以及如何解决此问题吗?请不要建议在启动可执行文件之前先修改LD_LIBRARY_PATH.另外也不建议修改可执行文件的链接器标志.我需要能够在运行时从任何文件夹加载该库.
更新. 经过一番研究,我做到了:
LD_DEBUG=all ./test
并发现库lib1.so试图被加载两次(第一次,当我调用dlopen时,第二次,当LD试图解决lib2.so的依赖关系时"):
add /usr/local/test/lib1.so [0] to global scope
opening file=/usr/local/test/lib1.so [0]; direct_opencount=1
...
30031: file=lib1.so [0]; needed by /usr/local/test/lib2.so [0]
30031: find library=lib1.so [0]; searching
30031: search path=./tls/x86_64:./tls:./x86_64:. (RPATH from file ./test)
30031: trying file=./tls/x86_64/lib1.so
30031: trying file=./tls/lib1.so
30031: trying file=./x86_64/lib1.so
30031: trying file=./lib1.so
30031: search cache=/etc/ld.so.cache
30031: search path=/lib64/tls/x86_64:/lib64/tls:/lib64/x86_64:/lib64:/usr/lib64/tls/x86_64:/usr/lib64/tls:/usr/lib64/x86_64:/usr/lib64 (system search path)
30031: trying file=/lib64/tls/x86_64/lib1.so
30031: trying file=/lib64/tls/lib1.so
30031: trying file=/lib64/x86_64/lib1.so
30031: trying file=/lib64/lib1.so
30031: trying file=/usr/lib64/tls/x86_64/lib1.so
30031: trying file=/usr/lib64/tls/lib1.so
30031: trying file=/usr/lib64/x86_64/lib1.so
30031: trying file=/usr/lib64/lib1.so
30031:
30031:
30031: file=/usr/local/test/lib2.so [0]; destroying link map
还是不知道发生了什么事...
UPDATE2..完整的 LD_DEBUG日志
注意:还有另一个库lib_other.so,只需忽略它
dlerror (3)以获得一些有用的消息.
所以至少要编码:
void* ptr_lib1
= dlopen("/usr/local/test/lib1.so", RTLD_NOW | RTLD_GLOBAL);
if (!ptr_lib1) {
fprintf(stderr, "dlopen lib1 failure: %s\n", dlerror());
exit(EXIT_FAILURE);
}
,对于其他dlopen
s
请注意,dlerror
给出了详细的错误消息.如果您不理解,请将其放入问题中.
在链接lib1.so
或lib2.so
时,您可能忘记设置一些 rpath .或者您需要显式设置LD_LIBRARY_PATH
或运行ldconfig
阅读Drepper的 如何编写共享库 有关详细信息.仔细阅读 ld-linux(8) >
lib2
的
dlopen
失败,因为未找到其依赖项lib1
.您需要解决此问题(通过rpath,LD_LIBRARY_PATH
,ldconfig
等...)
您可以在lib1
选项中添加一些-Wl,-rpath,/usr/local/test/lib1.so
,等等
您还可以(更简单地)决定所有共享库都放入/usr/local/lib/
中,您将在/etc/ld.so.conf
中提到.然后,您每次在其中添加库后都需要运行ldconfig
.
So a little bit of history, I have 3 libs:
- "lib1.so" with no dependencies
- "lib2.so" which is linked with "lib1.so"
- "test" executable program with no dependencies
What I need is to dynamically load "lib2.so" during runtime from "test" executable via "dlopen" method. The problem is that "lib1.so" cannot be loaded automatically due to linker doesn't know where to find it.
I've tried to load "lib1.so" at first like that:
void* ptr_lib1 = dlopen("/usr/local/test/lib1.so", RTLD_NOW | RTLD_GLOBAL);
void* ptr_lib2 = dlopen("/usr/local/test/lib2.so", RTLD_NOW | RTLD_GLOBAL);
But that's not working by some reason, it gives me error after calling second dlopen (text from dlerror):
"lib1.so: cannot open shared object file: No such file or directory"
It means that "lib1.so" is trying to be loaded twice: first time when I call dlopen for "lib1.so", and second when I call dlopen for "lib2.so".
Can anyone explain why and what to do to fix that? Please, don't advise to modify LD_LIBRARY_PATH before starting executable. Also don't advise to modify linker flags of executable. I need to be able load that libs at runtime from any folder.
UPDATE. After some research I did this:
LD_DEBUG=all ./test
And found that library lib1.so is trying to be loaded twice (first when I call dlopen, second when LD trying to resolve dependency for lib2.so"):
add /usr/local/test/lib1.so [0] to global scope
opening file=/usr/local/test/lib1.so [0]; direct_opencount=1
...
30031: file=lib1.so [0]; needed by /usr/local/test/lib2.so [0]
30031: find library=lib1.so [0]; searching
30031: search path=./tls/x86_64:./tls:./x86_64:. (RPATH from file ./test)
30031: trying file=./tls/x86_64/lib1.so
30031: trying file=./tls/lib1.so
30031: trying file=./x86_64/lib1.so
30031: trying file=./lib1.so
30031: search cache=/etc/ld.so.cache
30031: search path=/lib64/tls/x86_64:/lib64/tls:/lib64/x86_64:/lib64:/usr/lib64/tls/x86_64:/usr/lib64/tls:/usr/lib64/x86_64:/usr/lib64 (system search path)
30031: trying file=/lib64/tls/x86_64/lib1.so
30031: trying file=/lib64/tls/lib1.so
30031: trying file=/lib64/x86_64/lib1.so
30031: trying file=/lib64/lib1.so
30031: trying file=/usr/lib64/tls/x86_64/lib1.so
30031: trying file=/usr/lib64/tls/lib1.so
30031: trying file=/usr/lib64/x86_64/lib1.so
30031: trying file=/usr/lib64/lib1.so
30031:
30031:
30031: file=/usr/local/test/lib2.so [0]; destroying link map
Still don't understand what is going on...
UPDATE2. There is full LD_DEBUG log
Note: there is another library lib_other.so, just ignore it
When dlopen(3) fails, you should use dlerror(3) to get some useful message.
So code at least:
void* ptr_lib1
= dlopen("/usr/local/test/lib1.so", RTLD_NOW | RTLD_GLOBAL);
if (!ptr_lib1) {
fprintf(stderr, "dlopen lib1 failure: %s\n", dlerror());
exit(EXIT_FAILURE);
}
and likewise for other dlopen
s
Notice that dlerror
is giving a detailed error message. If you don't understand it, put it in your question.
You probably forgot to set some rpath when linking lib1.so
or lib2.so
. Or you need to set explicitly LD_LIBRARY_PATH
, or run ldconfig
Read Drepper's How To Write Shared Libraries paper for details. Read carefully ld-linux(8)
dlopen
of lib2
fails because its dependency lib1
is not found. You need to fix that (thru rpath, LD_LIBRARY_PATH
, ldconfig
etc...)
You could add some -Wl,-rpath,/usr/local/test/lib1.so
in lib1
options, etc
You could also (more simply) decide that all your shared libraries go into /usr/local/lib/
which you would mention in /etc/ld.so.conf
. Then you need to run ldconfig
after every library addition there.
这篇关于在Linux中强制动态链接器在运行时加载库的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!