静态链接 libstdc++:有什么陷阱吗?

2024-10-24 08:51:00
admin
原创
257
摘要:问题描述:我需要将在 Ubuntu 12.10 上使用 GCC 4.7 的 libstdc++ 构建的 C++ 应用程序部署到运行 Ubuntu 10.04 的系统上,该系统附带了相当旧版本的 libstdc++。目前,我正在使用 进行编译-static-libstdc++ -static-libgcc,正如...

问题描述:

我需要将在 Ubuntu 12.10 上使用 GCC 4.7 的 libstdc++ 构建的 C++ 应用程序部署到运行 Ubuntu 10.04 的系统上,该系统附带了相当旧版本的 libstdc++。

目前,我正在使用 进行编译-static-libstdc++ -static-libgcc,正如这篇博客文章所建议的那样:静态链接 libstdc++。作者警告在静态编译 libstdc++ 时不要使用任何动态加载的 C++ 代码,这是我尚未检查的内容。不过,到目前为止一切似乎都很顺利:我可以在 Ubuntu 10.04 上使用 C++11 功能,这正是我想要的。

我注意到这篇文章是 2005 年的,从那时起可能已经发生了很多变化。它的建议仍然适用吗?有什么潜在问题我应该注意吗?


解决方案 1:

那篇博客文章相当不准确。

据我所知,GCC 的每个主要版本都引入了 C++ ABI 变化(即具有不同第一个或第二个版本号组件的版本)。

不对。自 GCC 3.4 以来引入的唯一 C++ ABI 变化是向后兼容的,这意味着 C++ ABI 已经稳定了近九年。

更糟糕的是,大多数主流 Linux 发行版都使用 GCC 快照和/或修补其 GCC 版本,因此几乎不可能在分发二进制文件时确切知道您可能正在处理的 GCC 版本。

发行版的 GCC 修补版本之间的差异很小,并且 ABI 没有变化,例如 Fedora 的 4.6.3 20120306(Red Hat 4.6.3-2)与上游 FSF 4.6.x 版本是 ABI 兼容的,并且几乎可以肯定与任何其他发行版的 4.6.x 兼容。

在 GNU/Linux 上,GCC 的运行时库使用 ELF 符号版本控制,因此很容易检查对象和库所需的符号版本,如果您有一个libstdc++.so提供这些符号的版本,它就会起作用,即使它与您的发行版的另一个版本略有不同,修补版本也没有关系。

但如果要使其工作,则不能动态链接任何 C++ 代码(或任何使用 C++ 运行时支持的代码)。

这也不是事实。

也就是说,静态链接libstdc++.a是您的一个选择。

如果您动态加载库(使用dlopen),则可能无法正常工作的原因是,当您(静态)链接它时,您的应用程序可能不需要它所依赖的 libstdc++ 符号,因此这些符号将不会出现在您的可执行文件中。可以通过将共享库动态链接到libstdc++.so(如果它依赖于它,这无论如何都是正确的做法)来解决此问题。ELF 符号插入意味着可执行文件中存在的符号将被共享库使用,但可执行文件中不存在的其他符号将在libstdc++.so它链接到的任何地方找到。如果您的应用程序不使用,dlopen您无需关心这一点。

另一个选项(也是我更喜欢的选项)是将较新的版本libstdc++.so与您的应用程序一起部署,并确保在默认系统之前找到它libstdc++.so,这可以通过强制动态链接器在正确的位置查找来完成,可以在$LD_LIBRARY_PATH运行时使用环境变量,也可以RPATH在链接时在可执行文件中设置。我更喜欢使用,RPATH因为它不依赖于正确设置的环境来使应用程序工作。如果您将应用程序链接到'-Wl,-rpath,$ORIGIN'(请注意单引号以防止 shell 尝试扩展$ORIGIN),则可执行文件将具有一个RPATH$ORIGIN它告诉动态链接器在与可执行文件本身相同的目录中查找共享库。如果将较新的版本放在与libstdc++.so可执行文件相同的目录中,它将在运行时被发现,问题解决了。(另一个选择是将可执行文件放在中,/some/path/bin/将较新的 libstdc++.so 放在中/some/path/lib/并链接到'-Wl,-rpath,$ORIGIN/../lib'或任何其他相对于可执行文件的固定位置,并设置相对于的 RPATH $ORIGIN

解决方案 2:

除了 Jonathan Wakely 的出色回答之外,还有一个问题,为什么 dlopen() 是有问题的:

由于 GCC 5 中新增了异常处理池(请参阅PR 64535和PR 65434),如果您 dlopen 和 dlclose 静态链接到 libstdc++ 的库,每次都会发生内存泄漏(池对象)。因此,如果您有机会使用 dlopen,静态链接 libstdc++ 似乎是一个非常糟糕的主意。请注意,这是一个真正的泄漏,而不是PR 65434中提到的良性泄漏。

解决方案 3:

Jonathan Wakely 关于 RPATH 的回答补充:

只有当所讨论的 RPATH 是正在运行的应用程序的 RPATH 时,RPATH 才会起作用。如果您有一个库,它通过自己的 RPATH 动态链接到任何库,则该库的 RPATH 将被加载它的应用程序的 RPATH 覆盖。当您无法保证应用程序的 RPATH 与库的 RPATH 相同时,就会出现问题,例如,如果您希望依赖项位于特定目录中,但该目录不是应用程序的 RPATH 的一部分。

例如,假设您有一个应用程序 App.exe,它对 GCC 4.9 的 libstdc++.so.x 具有动态链接依赖关系。App.exe 通过 RPATH 解析了此依赖关系,即

App.exe (RPATH=.:./gcc4_9/libstdc++.so.x)

现在假设有另一个库 Dependency.so,它对 GCC 5.5 的 libstdc++.so.y 有动态链接依赖。这里的依赖关系通过库的 RPATH 来解析,即

Dependency.so (RPATH=.:./gcc5_5/libstdc++.so.y)

当 App.exe 加载 Dependency.so 时,它既不附加也不添加库的 RPATH。它根本不会参考它。唯一要考虑的 RPATH 是正在运行的应用程序的 RPATH,在本例中是 App.exe 的 RPATH。这意味着,如果库依赖于 gcc5_5/libstdc++.so.y 中但不在 gcc4_9/libstdc++.so.x 中的符号,则库将无法加载。

这只是一个警告,因为我以前也遇到过这些问题。RPATH 是一个非常有用的工具,但它的实现仍然存在一些问题。

解决方案 4:

您可能还需要确保不依赖动态 glibc。运行ldd生成的可执行文件并注意任何动态依赖项(libc/libm/libpthread 通常是可疑的)。

额外的练习是使用此方法构建一堆复杂的 C++11 示例,并在真正的 10.04 系统上实际尝试生成的二进制文件。在大多数情况下,除非您对动态加载做了一些奇怪的事情,否则您会立即知道程序是正常运行还是崩溃。

解决方案 5:

我想对 Jonathan Wakely 的回答进行以下补充。

在 Linux 上玩的时候-static-libstdc++,我遇到了 的问题dlclose()。假设我们有一个应用程序“A”静态链接到libstdc++,并且它在运行时动态加载链接到libstdc++插件“P”。这很好。但是当“A”卸载“P”时,会发生分段错误。我的假设是卸载后libstdc++.so,“A”不再可以使用与 相关的符号libstdc++。请注意,如果“A”和“P”都静态链接到libstdc++,或者“A”动态链接而“P”静态链接,则不会发生问题。

摘要:如果您的应用程序加载/卸载可能动态链接到的插件libstdc++,则应用程序也必须动态链接到它。这只是我的观察,我希望得到您的评论。

相关推荐
  政府信创国产化的10大政策解读一、信创国产化的背景与意义信创国产化,即信息技术应用创新国产化,是当前中国信息技术领域的一个重要发展方向。其核心在于通过自主研发和创新,实现信息技术应用的自主可控,减少对外部技术的依赖,并规避潜在的技术制裁和风险。随着全球信息技术竞争的加剧,以及某些国家对中国在科技领域的打压,信创国产化显...
工程项目管理   1565  
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   1354  
  信创国产芯片作为信息技术创新的核心领域,对于推动国家自主可控生态建设具有至关重要的意义。在全球科技竞争日益激烈的背景下,实现信息技术的自主可控,摆脱对国外技术的依赖,已成为保障国家信息安全和产业可持续发展的关键。国产芯片作为信创产业的基石,其发展水平直接影响着整个信创生态的构建与完善。通过不断提升国产芯片的技术实力、产...
国产信创系统   21  
  信创生态建设旨在实现信息技术领域的自主创新和安全可控,涵盖了从硬件到软件的全产业链。随着数字化转型的加速,信创生态建设的重要性日益凸显,它不仅关乎国家的信息安全,更是推动产业升级和经济高质量发展的关键力量。然而,在推进信创生态建设的过程中,面临着诸多复杂且严峻的挑战,需要深入剖析并寻找切实可行的解决方案。技术创新难题技...
信创操作系统   27  
  信创产业作为国家信息技术创新发展的重要领域,对于保障国家信息安全、推动产业升级具有关键意义。而国产芯片作为信创产业的核心基石,其研发进展备受关注。在信创国产芯片的研发征程中,面临着诸多复杂且艰巨的难点,这些难点犹如一道道关卡,阻碍着国产芯片的快速发展。然而,科研人员和相关企业并未退缩,积极探索并提出了一系列切实可行的解...
国产化替代产品目录   28  
热门文章
项目管理软件有哪些?
云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用