将libstdc ++编译的库与clang ++ -stdlib = libc ++一起使用


72

我在Mac OS X(10.8.2)下使用C ++进行工作,最近我提出了使用C ++ 11功能的需求,这些功能可以通过使用libc ++ stdlib的clang ++编译器获得。但是,我还需要使用一些针对libstdc ++编译并链接的旧式库(来自MacPorts)。

这样做时,我遇到了链接错误,因为使用(例如)的遗留库的标头std::string需要针对std::__1::basic_string(即libc ++实现std::string)而不是针对std::basic_string实现进行解析。

有没有办法在开发中混合这两个库(例如,通过使用一些预处理器标志?)

Answers:


95

您将看到使用内联名称空间来实现ABI版本控制。

那是什么意思:

libstdc ++std::string与libc ++是不同的数据结构std::string。前者是参考计数设计,而后者不是。尽管它们与API兼容,但与ABI不兼容。这意味着,如果您std::string使用libstdc ++构造一个,然后将其传递给与libc ++链接的其他代码,则接收代码会认为它具有libc ++ std::string。即,接收器将不知道应该增加还是减少参考计数。

没有内联名称空间,结果将是运行时错误。您可能希望的最好是崩溃。使用内联名称空间,此运行时错误将转换为链接时间错误。

对您而言,程序员libstdc ++std::string和libc ++std::string看起来像是同一类型。但是对于链接器来说,它们看起来是完全不同的类型(线索是std::__1名称空间)。并且链接器的视图是正确的。它们完全不同的类型。

所以是的,您可以操纵一些预处理器标志来链接东西。但是随后您将很费时地调试由此产生的运行时错误。

做您想要做的唯一方法是使这些dylib之间的接口不涉及std::诸如的类型string。例如,您可以传递的数组char。您甚至可以将内存所有权从libstdc ++链接的代码转移到libc ++链接的代码,反之亦然(它们都将进入同一个malloc池)。


7
因此,总而言之,没有希望将旧版库(即,与libstdc ++链接的库)与libc ++一起使用。这确实是一个严重的限制
user1690715 2012年

13
最大的希望是:您可以在一个过程中混合使用这两个库,只要您不跨越dylib边界传递版本化的符号即可。而且,如果您不小心这样做,则会在链接时捕获错误。您可以std::exception跨dylib边界引发派生的异常,并跨dylib边界转移内存所有权。我怀疑这可能比gcc提供自己的4.2版本更好的ABI兼容性。请注意,根据标准规范,std::stringC ++ 98/03和C ++ 11之间甚至不兼容ABI。前者被广泛引用,而后者则被禁止。
Howard Hinnant 2012年

3
另一个示例:C ++ 11之前的gccstd::list与的C ++ 11规范ABI不兼容std::list。换句话说:您对libc ++的评论也同样适用于libstdc ++的C ++ 11之前版本。与C ++ 11兼容的libstdc ++相比,libc ++不再是与C ++ 11之前的libstdc ++不兼容的ABI。
Howard Hinnant 2012年

2
@ user1690715可以更准确地说,当两个运行时在API上公开STL对象时,针对两个运行时建立互通库是没有希望的-一直以来这都是一个非常简单的命题。
marko

3
不可能为std :: string创建一个分配重载到std :: _ 1 :: string,反之亦然吗?
2014年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.