【问题标题】:Linux shared library that uses a shared library undefined symbol使用共享库未定义符号的 Linux 共享库
【发布时间】:2011-02-28 19:30:25
【问题描述】:

两个共享库 liba.so 和 libb.so。 liba.so 使用 libb.so。所有 c 文件都使用 -fPIC 编译。链接使用-shared。当我们在 liba.so 上调用 dlopen 时,它无法在 libb.so 中找到符号……我们得到“未定义符号”错误。我们可以 dlopen libb.so 没有错误。我们知道 liba 正在查找 libb,因为我们没有收到文件未找到错误。删除 libb.so 时出现文件未找到错误。我们尝试了 -lutil,但没有成功。

有什么想法吗????

哦,是的。 gcc 4.1.2

更新:我们在链接 liba 时使用 rpath,以便它可以找到 libb。

ldd liba.so 返回:

linux-gate.so.1 => (0xffffe000)  
libb.so => ./libb.so (0xf6ef9000)  <-------- LIBB 
libutil.so.1 => /lib/libutil.so.1 (0xf6ef5000)  
libdl.so.2 => /lib/libdl.so.2 (0xf6ef1000)  
libm.so.6 => /lib/libm.so.6 (0xf6ec9000)  
libpthread.so.0 => /lib/libpthread.so.0 (0xf6eb1000)  
librt.so.1 => /lib/librt.so.1 (0xf6ea8000)  
libc.so.6 => /lib/libc.so.6 (0xf6d62000)  
/lib/ld-linux.so.2 (0x007d0000)   

libb末尾没有.#是不是很重要???

【问题讨论】:

  • 您是说:您创建了两个库(-fPIC -shared),liba.so 和 libb.so。 liba.so 与 libb.so 动态链接(或者应该...)并使用它。在程序 X 中,您在 libb.so 上尝试 dlopen,一切正常;另一个测试程序 Y 尝试 dlopen liba.so 但它失败了,但是您知道 liba.so 正确找到 libb.so,因为您尝试删除 libb.so 并引发了另一个问题...您用于 dlopen 的选项?
  • 你没问题。现在我们没有使用任何选项,因为 dlopen 是从我们无法控制的某个程序中调用的。
  • 命令ldd liba.so 说什么?
  • ldd 说 libb.so => ./libb.so (0xf6ef9000) 等等。所有其他行在 so 名称之后都有一个额外的 .#,例如“libutil.so.1 => /lib/libutil.so.1 (0xf6ef5000)”。 libb.so之后没有.#是不是很重要???
  • 在这种情况下,您应该检查符号的定义 - 是否已定义或刚刚声明

标签: linux gcc shared


【解决方案1】:

您可以使用ldd 命令轻松检查libb.so 的预期位置:

 $ ldd liba.so
    linux-gate.so.1 =>  (0xb77b0000)
    libb.so.1 => not found
    libstdc++.so.6 => /usr/lib/libstdc++.so.6 (0xb75b6000)
    libgcc_s.so.1 => /lib/libgcc_s.so.1 (0xb7572000)
    libc.so.6 => /lib/i686/cmov/libc.so.6 (0xb742b000)
    /lib/ld-linux.so.2 (0xb77b1000)

如果是not foundlibb.so的路径应该添加到/etc/ld.so.conf或shell变量LD_LIBRARY_PATH中。

另一种方法是在liba.so 本身中设置rpath - 它基本上是对其路径进行硬编码,因此当二进制文件启动时,动态链接器将知道在哪里搜索共享库。

如果没有设置rpath,它将首先搜索LD_LIBRARY_PATH,然后搜索/etc/ld.so.conf(或/etc/ld.so.conf.d/)中提到的路径。添加到ls.so.conf后别忘了执行/sbin/ldconfig

动态链接器通过它们的soname(如果已设置)搜索依赖的共享库 - 如果未设置soname(例如使用 -Wl,-soname,libb.so.1),它将被搜索图书馆的名字。

示例:libb.so.1.0 是您的实际库,具有 soname - libb.so.1。您通常具有以下文件结构:

libb.so -> libb.so.1
libb.so.1 -> libb.so.1.0
libb.so.1.0

libb.solibb.so.1 是符号链接。

在构建某些应用程序或其他库时,您通常链接到libb.so,具体取决于libb.so

gcc -shared -Wl,-soname,liba.so.1 -o liba.so.1.2 -L/libb/path -lb

当应用程序启动(或执行 dlopen - 你的情况) - 动态链接器将搜索名称为 libb.so.1 的文件 - 依赖库的 soname,如果设置了 soname,而不是 @987654350 @。

这就是为什么你需要那个符号链接libb.so.1,指向实际的库。

如果您使用ld.so.confldconfig,它将创建带有soname 名称的符号链接,指向库文件,如果此符号链接缺失。

您可以查看ld-linux 手册页以获取更多有用信息。


如果找到该库但缺少某些符号,请尝试使用 -Wl,--no-undefined 选项构建 libb.so
gcc -shared -Wl,-soname,libb.so.1 -Wl,--no-undefined -o libb.so.1.2

如果你错过了定义一些符号,它应该会给你一个错误。

【讨论】:

  • 我们确实使用 rpath。我们很确定它找到了库,因为我们在删除 libb 后尝试运行该应用程序,但我们得到了一个找不到文件的错误。当我们使用 libb 运行时,我们得到一个未定义的符号错误。
  • 我可能没有理解关于 soname 的部分...你能澄清一下吗?
  • 我会解决这个问题,看看会发生什么。此外,liba 使用 libb。应用程序调用 dlopen(liba) 并获取有关 libb 中 liba 使用的符号的错误。
  • 是的,我的错误,我混淆了什么取决于什么,现在应该修复它。
  • 顺便说一句,我假设 libb 以某种方式找不到,但它可能没有定义一些符号。请参阅我上次关于 no-undefined 选项的编辑。
【解决方案2】:

在链接所有 obj 和库以生成可执行文件时,不要忘记库顺序(所有 -lxxx 参数)很重要(至少在 gcc 中)。

简短示例:

LIBS=-L。 -ltest1 -ltest2

OBJS=code1.o code2.o

gcc $(LIBS) $(OBJS) -o mysoft

在某些情况下可能会失败,而

gcc $(OBJS) -o mysoft $(LIBS)

不会

【讨论】:

  • 嘿,这个答案保存了我的编译。我在其他地方查看了它,没有其他人提到 -o 标志的顺序(仅对象和库的顺序),尽管在您的示例中,您将库移动到 -o 之后以及对象之后。你知道这是否重要吗?
  • 这对我有用,但我不明白为什么?
  • 因为链接器从左到右搜索,并在搜索过程中记录未解析的符号。对于循环依赖库,您还需要多次指定每个库。更多信息:stackoverflow.com/questions/45135/…
猜你喜欢
  • 1970-01-01
  • 2016-10-16
  • 2018-04-14
  • 2011-07-19
  • 1970-01-01
  • 1970-01-01
  • 2015-03-08
  • 2021-08-20
  • 1970-01-01
相关资源
最近更新 更多