什么(如果有的话)是处理Mac上libc ++和stdlibc ++之间ABI不一致的好方法?
问题:许多c ++ 11特性需要C ++标准库的新libc ++实现。但是libc ++与旧的libstdc ++不是ABI兼容的,而目前大多数软件通常都与后者相关联。例如,系统编译器仍然使用stdlibc ++,这意味着我用macports安装的所有库对于像字符串这样的std类都有不同的ABI,并且对于大量使用c ++ 11的项目是不可链接的。
我当前的黑客解决方案:保留两个版本的库,这通常会导致问题(boost,opencv等)并链接到相应的。
我想有人可能会建议,如果我真的想要使用libc ++,我应该使用stdlibc ++清除我的系统,并确保macports(或其他任何地方)的任何内容只与libc ++链接。你可以看到这个任务看起来多么令人生畏。
有没有人找到一个很好的方式来解决我们生活在这个“stdlib-limbo”之间的问题? :)
编辑:我更明确地提出了一个隐含的后续问题:Apple将libc ++和libstdc ++与他们的系统一起发布。假设有人攻击了潜在的问题并尝试转换到libc ++ - 仅。从libstdc ++切换到libc ++的推荐方法是什么,因为系统上当前安装的100%的库(一些随系统一起提供,大多数通过macport,一些通过手动编译)链接到libstdc ++(如果有的话) )?有没有人这样做并活了下来?
答案 0 :(得分:13)
除了标准库类型的“隐藏”使用之外,将libc ++和libstdc ++混合在一个程序中是完全安全的,其中一些TU(或库或模块)使用libc ++而一些使用libstdc ++。只要TU之间的接口不使用不兼容的类型,就不会有任何问题。
libc ++使用内联命名空间来帮助确保ABI不兼容类型不会被误认为彼此;如果接口直接使用libc ++ std::string
,则期望libstdc ++ std::string
的库将不会链接到接口,因为实际符号不同:std::string
与std::__1::string
。
libc ++还确保异常和动态内存分配等低级功能与ABI兼容(假设您使用相同的abi库构建libstdc ++和libc ++),因此在使用libc ++的TU中释放内存是安全的。使用libstdc ++在TU中分配内存,或者从libc ++上的代码构建中抛出异常,并使用libstdc ++在代码中捕获它。
当接口中的类型隐藏标准库类型时,可能会出现问题;给定使用struct S { std::string s; };
的接口,类型S
的定义将根据TU认为std::string
的不同而不同,从而违反了一个定义规则。
然而,听起来你的真正问题是做在接口中使用标准库类型的库。
我想有人可能会建议,如果我真的想要使用libc ++,我应该使用stdlibc ++清除我的系统,并确保macports(或其他任何地方)的任何内容只与libc ++链接。你可以看到这个任务看起来多么令人生畏。
您只需要确保在接口中使用标准库的TU使用libc ++。您不需要完全清除libstdc ++。不在其界面中使用标准库的库仍然可以与libstdc ++进行链接。
编辑:我更明确地提出了一个隐含的后续问题:Apple将libc ++和libstdc ++与他们的系统一起发布。假设有人攻击了潜在的问题并尝试转换到libc ++ - 仅。从libstdc ++切换到libc ++的推荐方法是什么,因为系统上当前安装的100%的库(一些随系统一起提供,大多数通过macport,一些通过手动编译)链接到libstdc ++(如果有的话) )?有没有人这样做并活了下来?
请记住,只有在接口中使用标准库时才有意义。希望这些库在为OS X构建时已经自行切换到libc ++。如果没有,也许他们会接受修补程序。
使用适当的库构建自己的二进制文件不是“黑客”;没有上游项目为你做这件事是正确的。如果您始终在自己的代码中使用libc ++,那么您将不需要构建任何库的多个版本;只有libc ++版本。
libc ++的abi兼容性参考:http://lists.cs.uiuc.edu/pipermail/cfe-dev/2012-September/024594.html
答案 1 :(得分:1)
你不会喜欢这个。
您根本不能拥有使用其定义在不同系统上更改的类型的ABI。当你有一个使用std::string
的ABI(例如),然后使用不同的编译器或不同的平台编译它时,你正在做的事情。
在修复此问题时,我首选的方法 - 如果可能 - 将从ABI中删除所有特定于编译器的内容,并将其替换为本机类型或库定义的类型。反过来,这些库定义的类型只能暴露ABI中的非编译器内容。
有时你可以通过简单的替换来解决问题。其他时候你需要采取更激烈的步骤。一种方法可能是围绕诸如std::string
之类的东西提供一种桥接或包装类。也许是这样的:
class MyString
{
public:
virtual const char* c_str() const = 0;
static MyString* Make();
virtual MyString* Clone() const = 0;
protected:
MyString();
};
在图书馆本身:
class MyStringImpl
:
public MyString
{
public:
const char* c_str() const
{
return mStr.c_str();
}
MyString* Clone() const
{
return new MyStringImpl (*this);
}
MyStringImpl ()
{
}
MyStringImple (const MyString& rhs)
:
mStr (rhs.c_str())
{
}
private:
std::string mStr;
};
MyString* MyString::Make()
{
return new MyStringImpl;
}
毛。可能效率低下。写的代码很多。但这是你自己画的角落。