了解如何动态链接适用于UNIX
考虑,我们有以下的情况:了解如何动态链接适用于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
本来会自动添加到program
,的依赖列表中,而没有重新编译。但是,ldd program
表明情况并非如此。
这似乎不可思议的是人们必须重新编译(重新链接)每个二进制依赖于某些库,每次该库的依赖关系发生变化。我有什么解决方案来防止这种情况发生?
如果您还没有链接libfoo.so
与libbar
,则会出现问题。在编译可执行文件时,默认情况下,链接程序不会让您留下未定义的引用。但是,当您编译共享库时,它将将 - 它会期望它们在链接时满意。这样libfoo
可以使用由program
本身导出的函数 - 当您尝试运行它时,动态链接器预计func_bar()
由program
提供。问题是出像这样:
(foo.c
是自足)
export LD_RUN_PATH=`pwd`
gcc -Wall -shared foo.c -o libfoo.so
gcc -Wall -L. p.c -lfoo -o p
在这一点上,./p
正确运行,如你所愿。然后,我们创建libbar.so
和修改foo.c
使用它:
gcc -Wall -shared bar.c -o libbar.so
gcc -Wall -shared foo.c -o libfoo.so
在这一点上,./p
给你描述的错误。如果我们检查ldd libfoo.so
,我们注意到它确实有而不是对libbar.so
有依赖 - 这是错误。要纠正错误,我们必须正确链接libfoo.so
:
gcc -Wall -L. -lbar -shared foo.c -o libfoo.so
在这一点上,./p
再次运行正常,并ldd libfoo.so
显示了libbar.so
的依赖。
你说得对:我没有用'libbar.so'链接。现在就像一个魅力!非常感谢 ! – ereOn 2010-11-08 08:22:58
您没有提供任何系统信息,您是否使用glibc?如果是的话,这是什么命令的输出:
LD_DEBUG =文件程序
还要检查"How to write shared (ELF) libraries"(PDF)(无论您使用的glibc与否)
你的程序不具有链接libbar.so。
我认为这个问题是由于在构建后者时未能指定libbar.so
作为libfoo.so
的依赖而造成的。 我不知道什么是您使用的编译系统,但CMake的它可以如下进行:
add_library(bar SHARED bar.c)
add_library(foo SHARED foo.c)
target_link_libraries(foo bar)
add_executable(program program.c)
target_link_libraries(program foo)
正如你可以看到program
仅与foo
(libfoo.so
)和foo
只有bar
(libbar.so
)链接。或者可能找不到libbar.so
。尝试在LD_LIBRARY_PATH
环境变量中指定其目录的路径。
问题是CMake在幕后做了什么,它可能足够聪明,可以为程序 – 2010-11-05 16:39:02
建立正确的链接命令@Peer Stritzinger:很好的问题。我想到了这一点,并做了一些实验(建立'program',而'foo'没有链接到'bar',然后建立'foo'和'bar',但不是'program')并且工作。所以在这种情况下,cmake方面的魔法似乎不太可能,尽管确实很聪明=)。 – vitaut 2010-11-05 16:52:12
这是否真的回答了这个问题?当然,将'libbar'与'libfoo'连接起来,然后*与'program'连接就可以独立工作,而不依赖于构建系统。但是,如果'program'与'libfoo'链接,然后'libfoo'更新为'libbar'链接,则可能不是这种情况。如果你的CMake脚本,如果'libfoo'改变为与libbar链接没有任何魔力,'program'显然与'libfoo'重新链接。 – 2010-11-05 17:12:02
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
#include "foo.h"
#include <iostream>
int main(int argc, char *argv[])
{
for (int i = 0; i < argc; ++i) {
std::cout << func_foo(argv[i]) << std::endl;
}
}
foo.h中
#ifndef FOO_H
#define FOO_H
#include <string>
std::string func_foo(std::string const &);
#endif
foo.cc
#include "foo.h"
std::string func_foo(std::string const &arg)
{
return arg + "|" + __func__;
}
bar.h
#ifndef BAR_H
#define BAR_H
#include <string>
std::string func_bar();
#endif
bar.cc
#include "bar.h"
std::string func_bar()
{
return __func__;
}
使用libfoo.so作为共享库进行构建。
克++ -Wall -Wextra -fPIC -shared foo.cc -o libfoo.so
克++ -lfoo -L./ -Wall -Wextra program.cc foo.h中-o程序
LDD程序
...
libfoo.so =>未找到
更新/etc/ld.so.cache中
须藤LDCONFIG /家庭/托比亚斯/项目/株/所以/
LDD表明动态链接器找到libfoo.so
ldd程序
...
libfoo.so => /home/tobias/projects/stubs/so/libfoo.so(0x00007f0bb9f15000)
添加调用libbar.so在libfoo.so
新foo.cc
#include "foo.h"
#include "bar.h"
std::string func_foo(std::string const &arg)
{
return arg + "|" + __func__ + "|" + func_bar();
}
生成libbar.so和重建libfoo.so
克++ -Wall -Wextra -fPIC -shared bar.cc -o libbar.so
克++ -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的。所以
再次更新/etc/ld.so.cache并重新检查。
须藤LDCONFIG /家庭/托比亚斯/项目/株/所以/
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 => /首页/托比亚斯/项目/存根/ so/libbar.so(0x00007f2be4d0e000)
B找到了libfoo.so和libbar.so。
注意这最后一步对应用程序没有影响。 如果你真的严格的运行ldconfig是一种重新链接。 奇怪或不连接器需要知道它链接的库的依赖关系。 还有很多其他的方法来实现这一点,但这是选择。
感谢您的信息:) – ereOn 2010-11-08 08:21:46
这不应该是这种情况,除非有关bar_func 符号的变化。使用“nm”命令获取程序和共享对象中的符号转储 - 查看是否存在不匹配以及原因。
我读到的问题是,'bar_func()'的变化是以前它没有被使用,但现在它被使用。 – 2010-11-08 06:43:17
你能发布一个最小化的配置来重现问题吗? Vitaut在他的帖子后的评论似乎描述了同样的过程,并没有达到同样的问题。也许如果你采取简单的步骤,我们可以帮助回答这个问题? – 2010-11-05 20:29:35