使用 Boost 创建具有向后兼容 ABI 的库 [英] Creating Library with backward compatible ABI that uses Boost

查看:24
本文介绍了使用 Boost 创建具有向后兼容 ABI 的库的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在研究某个 C++ 库(或更多框架).我想让它倒退与以前的版本兼容,不仅保留了 API 兼容性,还保留了 ABI(就像 Qt 所做的那样出色).

I'm working on a certain C++ library (or more framework). I want to make it backward compatible with previous versions preserving not only API compatibility but also ABI (like the great job Qt does).

我使用了 Boost 的许多功能,在我看来,这使得向后兼容是不可能的,除非我强迫用户使用完全相同(有时是旧)版本的 Boost.

I use lots of functionality of Boost and it seems for me that this makes backward compatibility just impossible, unless I force a user to have exactly the same (sometimes old) version of Boost.

有没有什么办法(不重写 Boost 的 1/2)在它的命名空间周围做一些前缀"/重命名它以防止它干扰用户版本的 Boost?

Is there any way (without rewriting 1/2 of Boost) to make some "prefix" around its namespace/rename it in order to prevent it from interfering with a user version of Boost?

例如我的 libXYZ 使用 Boost 1.33 并且它有类 boost::foo.在 1.35 版 boost::foo 升级并添加了新成员,因此,1.33 和 1.35 中的 boost::foo 是不兼容 ABI.因此,libXYZ 的用户必须使用 Boost 1.33 或重新编译 libXYZBoost 1.35(可能已经以 XYZ 无法编译的方式破坏了某些 API).

For example my libXYZ uses Boost 1.33 and it has class boost::foo. In version 1.35 boost::foo was upgraded and new member was added, so, boost::foo from 1.33 and 1.35 are not ABI compatible. So, a user of libXYZ must use Boost 1.33 or recompile libXYZ with Boost 1.35 (that may be already had broken some API in a way XYZ would not compile).

注意:我说的是带有 ELF 的 UNIX/Linux 操作系统,其中动态链接类似于静态链接,因此您不能链接两个不同版本的库,因为符号会干扰.

Note: I'm talking about UNIX/Linux OS with ELF where dynamic linking is similar to static linking, so you can't link with two different versions of libraries because symbols would interfere.

我可能想到的一个合适的解决方案是将 Boost 放在其他一些私有命名空间中.因此,libXYZ 将使用 ::XYZ::boost::foo 而不是 ::boost::foo.这将防止与用户可能使用的其他版本的 Boost 发生冲突.

One suitable solution I may think of is putting Boost in some other private namespace. So, libXYZ would use ::XYZ::boost::foo instead of ::boost::foo. This would prevent collision with other version of Boost that user may use.

因此,libXYZ 将继续与 Boost 1.33 一起使用,并与其他命名空间静态或动态链接,假设它:

So, the libXYZ would continue to work with Boost 1.33 statically or dynamically linked with it withing other namespace, assuming, that it:

  • 不会将 Boost API 暴露在外面.
  • 将保持公开 API 的稳定私有版本.

有没有办法用 Boost 做这样的事情?

Is there any way to do such things with Boost?

最后我决定创建一个脚本,将源中的所有增强符号重命名为某个自定义符号.

Finally I decided to create a script that would rename all boost symbols in the source to some custom symbol.

基本原理:构建过程的简化,独立于编译器可见性支持,而且,它的可见性仅适用于动态库,对于静态这不起作用,所以我需要为每种类型的库单独构建和依赖.

Rationale: simplification of build process, independent of compiler visibility support, also, it visibility works on dynamic libraries only, for static this does not work, so I need separate builds and dependencies for each type of libraries.

脚本在那里可用:http://art-blog.no-ip.info/files/rename.py

编辑 2:最新版本的 Boost BCP 支持命名空间重命名.

Edit 2: Latest version of Boost BCP supports namespace renaming.

推荐答案

基本上,只需确保库的公共接口不公开 Boost.您可以随时在内部随意使用它.通常,让一个库的接口依赖于另一个库是不好的(除非它依赖于像 STL 这样的标准库).Boost 几乎适合标准"库类别,但它的 ABI 变化太大,以至于您的界面不应该使用它.

Basically, just make sure the public interface to your library does not expose Boost. You can always use it however much you want internally. Generally, having the interface of a library depend on another library is bad (unless it depends on a standard library like STL). Boost almost fits into the "standard" library category, but its ABI changes so much that that your interface shouldn't use it.

为确保不会暴露 Boost 符号,您可以执行以下操作:

To make sure you don't expose the Boost symbols, there are a few things you could do:

A.使用 -fvisibility=hidden 编译并使用 __attribute__((visibility("default"))) 标记所有公共符号.您可以使用宏来简化此操作:

A. compile with -fvisibility=hidden and mark all public symbols with __attribute__((visibility("default"))). you could use a macro to make this easier:

#define ABI __attribute__((visibility("default")))

B.做这样的事情:

#pragma GCC visibility push(hidden)
#include <boost/whatever.hpp>
#pragma GCC visibility pop

您还应该将其包装在您不想导出的所有其他内部符号周围,或使用 __attribute__((visibility("hidden"))) 声明.同样,您可以使用宏来简化此操作:

You should also wrap this around all other internal symbols that you don't want exported, or declare this with __attribute__((visibility("hidden"))). Again, you could use a macro to make this easier:

#define INTERNAL __attribute__((visibility("hidden")))

在这些选项中,我更喜欢 A,因为它让您明确考虑导出哪些符号,因此您不会意外导出您不想要的东西.

Of these options, I like A better, because it makes you explicitly think about which symbols are exported, so you don't accidentally export things you don't want.

顺便说一下,您可以在 Ulrich Drepper 的 How to Write 中找到更多关于制作 DSO 的信息共享库.

By the way, you can find a lot more information about making DSOs in Ulrich Drepper's How to Write Shared Libraries.

这篇关于使用 Boost 创建具有向后兼容 ABI 的库的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆