了解动态链接在 UNIX 上的工作原理
考虑我们有以下情况:
- 一个名为
program
的程序动态依赖于libfoo.so
, - 但
libfoo.so
不依赖于任何东西(嗯,它取决于libstdc++
和其他东西,但我想我们可以忽略它)
program
运行完美。
突然,libfoo
代码发生了变化,某些函数现在在内部使用 func_bar()
另一个库 libbar.so
提供的函数。
libfoo.so
已重新编译,现在依赖于 libbar.so
。 program
保持不变,它仍然仅依赖于 libfoo.so
。
现在,当我执行program
时,它抱怨找不到func_bar()
。
这是我的问题:
libfoo.so
接口没有改变,只有它的实现。为什么program
必须显式与libbar.so
链接?- 依赖树不是递归的吗?我本以为,由于
libfoo.so
依赖于libbar.so
,因此libbar.so
会自动添加到libbar.so
的依赖列表中代码>程序,无需重新编译。然而,ldd 程序
表明情况并非如此。
每当库的依赖项发生变化时,就必须重新编译(重新链接)每个依赖于某个库的二进制文件,这似乎很奇怪。我有什么解决方案可以防止这种情况发生?
Consider we have the following situation:
- a program named
program
which depends dynamically onlibfoo.so
libfoo.so
that depends on nothing (well, it depends onlibstdc++
and stuff but I guess we can omit that)
program
runs perfectly.
Suddenly, libfoo
codes changes, and some function now uses internally func_bar()
a function that is provided by another library libbar.so
.
libfoo.so
is recompiled and now depends on libbar.so
. program
remains unchanged, it still depends only on libfoo.so
.
Now when I execute program
it complains that he can't find func_bar()
.
Here are my questions:
libfoo.so
interface didn't change, only its implementation. Why doesprogram
have to explicitely link withlibbar.so
?- Isn't the dependency tree recursive ? I would have think that since
libfoo.so
depends onlibbar.so
,libbar.so
would have been automatically added to the dependency list ofprogram
, without recompilation. However,ldd program
shows that it is not the case.
It seems weird that one has to recompile (relink) every binary that depends on some library everytime that library's dependencies change. What solutions do I have here to prevent this ?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
当您没有将
libfoo.so
链接到libbar
时,就会出现问题。当您编译可执行文件时,默认情况下链接器不会让您留下未定义的引用。但是,当您编译共享库时,它会 - 并且它会期望它们在链接时得到满足。这样libfoo
就可以使用program
本身导出的函数 - 当您尝试运行它时,动态链接器期望func_bar()
由程序
提供。问题如下所示:(foo.c
is selfcontained)此时,
./p
正确运行,正如您所期望的那样。然后,我们创建libbar.so
并修改foo.c
以使用它:此时,
./p
给出您所描述的错误。如果我们检查ldd libfoo.so
,我们会注意到它不依赖于libbar.so
- 这就是错误。要纠正错误,我们必须正确链接libfoo.so
:此时,
./p
再次正确运行,并且ldd libfoo.so
显示对libbar.so
的依赖。The problem arises when you have not linked
libfoo.so
againstlibbar
. When you are compiling an executable, by default the linker will not let you leave undefined references. However, when you're compiling a shared library, it will - and it will expect them to be satisfied at link time. This is so thatlibfoo
can use functions exported byprogram
itself - when you try to run it, the dynamic linker is expectingfunc_bar()
to be supplied byprogram
. The problem is illustrated like so:(
foo.c
is selfcontained)At this point,
./p
runs correctly, as you would expect. We then createlibbar.so
and modifyfoo.c
to use it:At this point,
./p
gives the error you describe. If we checkldd libfoo.so
, we notice that it does not have a dependency onlibbar.so
- this is the error. To correct the error, we must linklibfoo.so
correctly:At this point,
./p
again runs correctly, andldd libfoo.so
shows a dependency onlibbar.so
.在 Fedora 上,动态链接由 ld-linux.so.2 执行。
动态链接器使用/etc/ld.so.cache和/etc/ld.so.preload来查找库文件。
运行 ldconfig 告诉系统 libfoo 应在哪里查找 libbar。
ldconfig 查找 /lib、/usr/lib 以及 /etc/ld.so.conf 中列出的任何目录。
您可以使用 ldd 检查程序使用哪些库。
每个命令的手册页上提供了更多详细信息。
这是使用共享库的应用程序的示例。
Program.cc
foo.h
foo.cc
bar.h
bar.cc
使用 libfoo.so 作为共享库进行构建。
g++ -Wall -Wextra -fPIC -shared foo.cc -o libfoo.so
g++ -lfoo -L./ -Wall -Wextra program.cc foo.h -o 程序
ldd程序
...
libfoo.so =>;未找到
更新/etc/ld.so.cache
sudo ldconfig /home/tobias/projects/stubs/so/
ldd 显示动态链接器找到 libfoo.so
ldd程序
...
libfoo.so =>; /home/tobias/projects/stubs/so/libfoo.so (0x00007f0bb9f15000)
在 libfoo.so 中添加对 libbar.so 的调用
新建 foo.cc
构建 libbar.so 并重建 libfoo.so
g++ -Wall -Wextra -fPIC -shared bar.cc -o libbar.so
g++ -Wall -Wextra -fPIC -shared libbar.so foo.cc -o libfoo.so
ldd libfoo.so
...
libbar.so =>;未找到
ldd 程序
...
libfoo.so =>; /home/tobias/projects/stubs/so/libfoo.so (0x00007f49236c7000)
libbar.so =>;未找到
这表明动态链接器仍然找到 libfoo.so 但找不到 libbar.so
再次更新 /etc/ld.so.cache 并重新检查。
sudo ldconfig /home/tobias/projects/stubs/so/
ldd libfoo.so
...
libbar.so =>; /home/tobias/projects/stubs/so/libbar.so (0x00007f935e0bd000)
ldd 程序
...
libfoo.so =>; /home/tobias/projects/stubs/so/libfoo.so (0x00007f2be4f11000)
libbar.so =>; /home/tobias/projects/stubs/so/libbar.so (0x00007f2be4d0e000)
libfoo.so 和 libbar.so 均已找到。
注意最后一步对应用程序没有影响。
如果你真的很严格,运行 ldconfig 就是一种重新链接。
不管奇怪与否,链接器需要知道它链接的库的依赖关系。
有很多其他方法可以实现这一点,但我们选择了这个。
On Fedora dynamic linking is performed by ld-linux.so.2.
The dynamic linker use /etc/ld.so.cache and /etc/ld.so.preload to find library files.
Run ldconfig to tell the system where libfoo should look for libbar.
ldconfig looks in /lib, /usr/lib and any directory listed in /etc/ld.so.conf.
You can check which libraries a program uses with ldd.
More details are available on the manual pages for each command.
Here is an example of an application using shared libraries.
Program.cc
foo.h
foo.cc
bar.h
bar.cc
Build with libfoo.so as a shared library.
g++ -Wall -Wextra -fPIC -shared foo.cc -o libfoo.so
g++ -lfoo -L./ -Wall -Wextra program.cc foo.h -o program
ldd program
...
libfoo.so => not found
Update /etc/ld.so.cache
sudo ldconfig /home/tobias/projects/stubs/so/
ldd shows that the dynamic linker finds libfoo.so
ldd program
...
libfoo.so => /home/tobias/projects/stubs/so/libfoo.so (0x00007f0bb9f15000)
Add a call to libbar.so in libfoo.so
New foo.cc
Build libbar.so and rebuild libfoo.so
g++ -Wall -Wextra -fPIC -shared bar.cc -o libbar.so
g++ -Wall -Wextra -fPIC -shared libbar.so foo.cc -o libfoo.so
ldd libfoo.so
...
libbar.so => not found
ldd program
...
libfoo.so => /home/tobias/projects/stubs/so/libfoo.so (0x00007f49236c7000)
libbar.so => not found
This shows that the dynamic linker still finds libfoo.so but not libbar.so
Again update /etc/ld.so.cache and recheck.
sudo ldconfig /home/tobias/projects/stubs/so/
ldd libfoo.so
...
libbar.so => /home/tobias/projects/stubs/so/libbar.so (0x00007f935e0bd000)
ldd program
...
libfoo.so => /home/tobias/projects/stubs/so/libfoo.so (0x00007f2be4f11000)
libbar.so => /home/tobias/projects/stubs/so/libbar.so (0x00007f2be4d0e000)
Both libfoo.so and libbar.so are found.
Note this last step have no effect on the application program.
If you are really strict running ldconfig is kind of relinking.
Weird or not the linker need to know the dependencies of the libraries it links.
There are a lot of other ways to implement this but this was chosen.
你没有提供任何系统信息,你使用的是glibc吗?如果是,此命令的输出是什么:
LD_DEBUG=files program
另请检查 “如何编写共享(ELF) ) 库"(pdf)(无论您是否使用 glibc)
You did not give any system information, are you using glibc? If yes what is the output of this command:
LD_DEBUG=files program
Also check "How to write shared (ELF) libraries"(pdf) (whether you are using glibc or not)
您的程序不必与 libbar.so 链接。
我认为该问题是由于在构建后者时未能将
libbar.so
指定为libfoo.so
的依赖项引起的。我不确定您使用的是什么构建系统,但在 CMake 中可以按如下方式完成:
如您所见
program
仅与foo
(libfoo. so
) 和foo
仅与bar
(libbar.so
) 一起使用。或者可能是找不到
libbar.so
。尝试在 LD_LIBRARY_PATH 环境变量中指定其目录的路径。Your program doesn't have to link with libbar.so.
I think that the problem is caused by failing to specify
libbar.so
as a dependency oflibfoo.so
when building the later.I am not sure what build system are you using but in CMake it can be done as follows:
As you can see
program
is linked only withfoo
(libfoo.so
) andfoo
only withbar
(libbar.so
).Or it may be that
libbar.so
can't be found. Try to specify the path to its directory inLD_LIBRARY_PATH
environment variable.除非有关 bar_func 符号 的某些内容发生更改,否则情况不应如此。使用“nm”命令获取程序和共享对象中的符号转储 - 查看是否存在不匹配以及原因。
This should not be the case unless something about the bar_func symbol changed. Use the "nm" command to get a dump of the symbols in both your program, and the shared object - see if there is a mismatch and why.