为了与较早的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
无关,但我怀疑它还有一些令人讨厌的细节。