【问题标题】:How do I build my Linux c++ app to link to an old version of libc?如何构建我的 Linux c++ 应用程序以链接到旧版本的 libc?
【发布时间】:2012-07-09 00:08:45
【问题描述】:

我在 Ubuntu 12.04 上构建了一个应用程序,并尝试在嵌入式系统上运行它。我在我的开发机器上运行了apt-cache show libc6,它显示(除其他外)

Package: libc6
Priority: required
Section: libs
Architecture: i386
Source: eglibc
Version: 2.15-0ubuntu10
Replaces: belocs-locales-bin, libc6-i386
Provides: glibc-2.13-1, libc6-i686

嵌入式设备上存在的 libc6 版本是 2.8.90。在设备上的 \lib 目录中,我有 2 个库

libc-2.8.90.so
libc.so.6

当我将应用程序复制到嵌入式设备上时,出现以下错误

/usr/lib/libc.so.6: version `GLIBC_2.15` not found (required by ./ServerSocketApp)

我知道,如果可能的话,当我在我的开发机器上构建应用程序时,我需要强制它链接到与嵌入式设备上存在的相同版本的 libc6。我遇到的问题是我根本不知道该怎么做。我现在找到的任何答案对我来说都毫无意义。我需要将某些选项传递给 g++ 以使其链接到 2.8.90 版本吗??

在绝望中,我在想是否可以将我的开发机器上的 libc 复制到嵌入式设备上来代替已经存在的设备并希望最好???我似乎无法在网上找到任何文档来简单地解释你是如何做到这一点的,所以任何建议都会非常受欢迎,因为我在这里扯头发。

【问题讨论】:

  • 您是否尝试过将 .so 文件的完整路径直接传递给它(而不是 -lc)?
  • 还没有,我一定会试一试 - 感谢您的建议。
  • 你试过静态链接吗?您还可以使用较旧的 glibc 版本设置 chrooted 环境,并使用它为嵌入式系统进行编译。
  • @HristoIliev 我已经考虑过静态链接,它很可能必须是前进的方向。我真的很想知道如何做这个问题似乎出现了很多。我对嵌入式东西真的很陌生,所以我目前正在吸收很多信息,但没有取得太大进展。我一定会根据你的建议做一些研究。谢谢。

标签: c++ linux linker g++ embedded-linux


【解决方案1】:

好的,这里有一个更长的解释,但要小心。我仍然强烈建议您设置 chrooted 环境以匹配嵌入式设备上可用的环境,并在构建过程的最后阶段使用它。

您应该了解动态链接的 ELF 可执行文件是如何加载和执行的。有一种称为运行时链接编辑器 (RTLD) 的东西,也称为动态链接器,它负责加载所有必要的动态链接库、修复重定位等。动态链接器的名称在 32 位 Linux 系统上为 /lib/ld-linux.so.2glibc2,在 64 位 Linux 系统上为 /lib64/ld-linux-x86-64.so.2 glibc2。动态链接器与glibc2非常紧密耦合,通常只能处理该库的匹配版本。它的路径也被链接器硬编码到可执行文件中(通常是ld,由编译器隐式调用以进行链接)。您只需执行 ldd some_elf_executable 即可轻松检查最后一条语句的有效性 - 运行时链接编辑器会显示完整路径:

$ ldd some_elf_executable
linux-vdso.so.1 =>  (0x00007fffab59e000)
libm.so.6 => /lib64/libm.so.6 (0x0000003648400000)
libc.so.6 => /lib64/libc.so.6 (0x0000003648800000)
/lib64/ld-linux-x86-64.so.2 (0x0000003648000000) <--- the RTLD

为了生成一个动态链接的可执行文件,它使用与系统上安装的版本不同的glibc2 版本,可执行文件将在其中运行,您应该使用以下一组选项将您的代码链接到@987654330 @:

  • -rpath=/path/to/newer/libs - 这个命令指示动态链接器在尝试解析库依赖项时首先搜索 /path/to/newer/libs/path/to/newer/libs 应该与您在嵌入式设备上复制较新的glibc2 版本的路径相匹配
  • -rpath-link=/path/to/newer/libs - 此选项指示链接器(而不是动态链接器)在链接期间解析共享库之间的依赖关系时使用 /path/to/newer/libs - 在您的情况下通常不需要这样做
  • --dynamic-linker=/path/to/newer/libs/ld-linux.so.2 - 这个覆盖了嵌入到可执行文件中的 RTLD 的路径

ld 提供这些选项的方式通常是通过GCC 的-Wl 选项。

-rpath=/path/to/newer/libs

变成:

-Wl,-rpath,/path/to/newer/libs

(注意=, 取代)

--dynamic-linker=/path/to/newer/libs/ld-linux.so.2

变成:

-Wl,--dynamic-linker,/path/to/newer/libs/ld-linux.so.2

您应该将/lib/ld-linux.so.2 从您的开发系统复制到嵌入式设备上的/path/to/newer/libs/。您还应该复制libc.so.6、数学库libm.so.6 以及可执行文件使用或可能间接加载的所有其他库。请注意libc.so.6libm.so.6 实际上是指向真实库的符号链接,其名称类似于libc-2.&lt;version&gt;.so。您应该复制这些库文件并创建适当的符号链接以使每个人都开心。

【讨论】:

  • 非常感谢您的回答,我明天将首先尝试。它还为我提供了一些额外的关键字来进行研究。来自 windows 的我真的很震惊,要掌握在 linux 上开发一些可以在不同配置的机器上运行的东西是多么困难。我不敢相信网上没有更多关于这种事情的教程。再次感谢。
【解决方案2】:

这基本上是不正确的。虽然您可能能够拼凑出一种链接旧 libc 的方法,但问题在于您的环境设置。

当您为嵌入式系统开发应用程序时。你在主机上这样做。通常,主机和嵌入式设备不在同一架构上。例如,您的主机通常是在 x86 上运行的台式机/笔记本电脑,而嵌入式系统可能在 ARM 上。如果您碰巧与您的嵌入式设备使用相同的架构,那纯属巧合。仍应遵循标准实践环境设置:

  • 主机应该有一个工具链设置来将应用程序交叉构建到嵌入式架构中
  • 主机应该有一个完整的 rootfs 副本,该副本存在于您的嵌入式设备中。这将包含您的交叉工具将用于为嵌入式系统编译应用程序的所有库

如果您以这种方式设置它。开发将很容易。您将能够设置简单、干净的 make 文件来构建您的应用程序,然后只需 scp 将二进制文件转移到嵌入式系统并运行。

【讨论】:

  • 您能建议使用哪些工具来执行此操作 - 或提供这样做的在线资源吗?
  • 我不知道你们嵌入式系统的细节。但通常公司会提供一个工作基地。例如,飞思卡尔提供的 ltib 允许您为您购买的参考板构建或提取功能性 u-boot、rootfs、内核等。如果您只是在寻找工具链而没有提供,您可以自己构建它:kegel.com/crosstool。尽管听起来您的嵌入式设备的架构与您的主机相同。所以你不需要交叉编译。您只需要一个干净的开发环境和设备的 rootfs。
  • 是的,架构是一样的。所以我基本上只需要找到一种方法将文件系统从我的板上提取到我的机器中,在主机上构建必要的库和二进制文件然后复制回设备?
  • 是的,如果没有为您提供最小的 rootfs。另一种方法是您可以将嵌入式设备的基本目录中的所有内容 tar 并将其 scp 到您的主机。我建议制定一个干净的项目树,以便您可以合理地设置路径。示例 /project/embedded_device/applications/... /project/embedded_device/bootloader/... /project/embedded_device/rootfs/... /project/embedded_device/kernel/...
【解决方案3】:

使用 LSB SDK (http://www.linuxfoundation.org/collaborate/workgroups/lsb/download) 编译时可能会有一些运气,它限制了可执行文件可用的符号。

【讨论】:

  • 感谢这个建议,我一定会探索这个选项。
猜你喜欢
  • 2021-05-22
  • 2011-05-01
  • 1970-01-01
  • 1970-01-01
  • 2012-02-16
  • 1970-01-01
  • 2010-12-30
  • 2013-11-10
  • 2021-12-04
相关资源
最近更新 更多