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

2024-10-24 08:51:00
admin
原创
68
摘要:问题描述:我需要将在 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++,则应用程序也必须动态链接到它。这只是我的观察,我希望得到您的评论。

相关推荐
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   601  
  华为IPD与传统研发模式的8大差异在快速变化的商业环境中,产品研发模式的选择直接决定了企业的市场响应速度和竞争力。华为作为全球领先的通信技术解决方案供应商,其成功在很大程度上得益于对产品研发模式的持续创新。华为引入并深度定制的集成产品开发(IPD)体系,相较于传统的研发模式,展现出了显著的差异和优势。本文将详细探讨华为...
IPD流程是谁发明的   7  
  如何通过IPD流程缩短产品上市时间?在快速变化的市场环境中,产品上市时间成为企业竞争力的关键因素之一。集成产品开发(IPD, Integrated Product Development)作为一种先进的产品研发管理方法,通过其结构化的流程设计和跨部门协作机制,显著缩短了产品上市时间,提高了市场响应速度。本文将深入探讨如...
华为IPD流程   9  
  在项目管理领域,IPD(Integrated Product Development,集成产品开发)流程图是连接创意、设计与市场成功的桥梁。它不仅是一个视觉工具,更是一种战略思维方式的体现,帮助团队高效协同,确保产品按时、按质、按量推向市场。尽管IPD流程图可能初看之下显得错综复杂,但只需掌握几个关键点,你便能轻松驾驭...
IPD开发流程管理   8  
  在项目管理领域,集成产品开发(IPD)流程被视为提升产品上市速度、增强团队协作与创新能力的重要工具。然而,尽管IPD流程拥有诸多优势,其实施过程中仍可能遭遇多种挑战,导致项目失败。本文旨在深入探讨八个常见的IPD流程失败原因,并提出相应的解决方法,以帮助项目管理者规避风险,确保项目成功。缺乏明确的项目目标与战略对齐IP...
IPD流程图   8  
热门文章
项目管理软件有哪些?
云禅道AD
禅道项目管理软件

云端的项目管理软件

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

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

内置subversion和git源码管理

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

免费试用