在一个过程中提供两个版本的libstdc ++

时间:2018-08-28 09:48:12

标签: c++ linux shared-libraries std

为了与较早的GNU / Linux发行版兼容,我们考虑将框架与特定版本的libstdc++链接,并将其与框架的二进制文件一起分发。该框架使用C ++编写,但仅提供C-API。已发布的框架如下所示:

$ ls
framework.h  libframework.so  libstdc++.so.6.0.24
$ readelf -d libframework.so
...
0x0000000000000001 (NEEDED)  Shared Library: [libstdc++.so.6.0.24]
...
0x000000000000001d (RUNPATH) Library runpath: [$ORIGIN]
...

通过这种方式,框架的客户端可以使用自己的和可能不同的libstdc ++版本,例如

$ ls
client  client.cpp  framework.h  libframework.so  libstdc++.so.6.0.24
$ readelf -d client
...
0x0000000000000001 (NEEDED)  Shared library: [libframework.so]
0x0000000000000001 (NEEDED)  Shared library: [libstdc++.so.6]
...
0x000000000000001d (RUNPATH) Library runpath: [$ORIGIN]
...
$ ldd client
    libframework.so => /home/phlipsy/client/./libframework.so
    libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6
    ...
    libstdc++.so.6.0.24 => /home/phlipsy/client/./libstdc++.so.6.0.24
    ...

在具有明显较旧的LD_DEBUG=bindings的系统上使用libstdc++时,我得到了预期的行为:绝大多数C ++符号由系统的libstdc++.so.6解析。 libframework.so中只有libstdc++.so.6中不需要的那些符号才来自libstdc++.so.6.0.24。借助符号版本控制,可以将符号与这两个标准库区分开。

另一方面,如果当前的libstdc++.so.6比分布式的libstdc++.so.6.0.24还要新,那么每个符号都将由系统libstdc++.so.6解析。

问题:这种方法是否存在一些我尚未发现的巨大缺点?可能的候选人是:

  • 系统libstdc++.so.6和分布式libstdc++.6.0.24之间的不兼容ABI
  • 符号版本错误或不完整
  • 如果仅使用部分函数,​​则内部库状态不一致

更新I:适用于不同发行版本的多个二进制文件:该框架已经跨平台,这意味着我们已经拥有适用于Windows,macOS和GNU / Linux的32位和64位二进制文​​件。我真的很想将必需的GNU / Linux二进制文件的数量保持在较低水平,因为我们必须构建,测试和部署它们。此外:我们非常热衷于那些新颖的C ++ 11功能。只要我们支持那些旧发行版,这种简单的方法就无法使用。

更新II:静态链接libstdc++不幸的是,这种方法本身也有严重的缺点:

  • 该框架广泛使用dlopen()以便在运行时加载插件。因此,将libstdc++静态链接到框架也意味着将每个插件静态链接到libstdc++。否则,该框架必须发布其插件使用的每个符号。
  • libstdc++.a中有默认可见性的符号,更糟糕的是,它们没有版本化。这意味着在任何情况下,框架都会发布符号,即使这些符号来自标准库的错误版本,它们也将被用作客户端。
  • 内存泄漏:libstdc++中有一个池对象,用于保存引发异常的内存。由于libstdc++的开发人员认为其寿命与整个过程相同,因此无法释放该池。
  • 在框架和插件之间引发和捕获异常:这可能与现代版本的libstdc++libgcc_s无关,但我怀疑它还有一些令人讨厌的细节。

0 个答案:

没有答案