Что (если есть) является хорошим способом обработки ABI-несоответствия между libc ++ и stdlibc ++ на Mac?
Проблема: многие функции c ++ 11 требуют новой реализации libc ++ стандартной библиотеки C ++. Но libc ++ не совместим ABI со старым libstdc ++, в то время как в настоящее время большинство программ обычно ссылаются на последний. Например, системный компилятор все еще использует stdlibc ++, что означает, что все мои библиотеки, установленные с macports, имеют различный ABI для std-классов, таких как string, и не связаны с проектами, которые интенсивно используют c ++ 11.
Мое текущее решение: храните две версии библиотек, в которых это обычно приводит к проблеме (boost, opencv и т. Д.), И ссылайтесь на соответствующую.
Я предполагаю, что можно предположить, что если я действительно хочу использовать libc ++, я должен очистить свою систему от всего, что использует stdlibc ++, и убедиться, что что-либо из macports (или где-либо еще) связывается только с libc ++. Вы могли видеть, насколько сложной выглядит эта задача.
Кто-нибудь разработал хороший способ связать это «промежуточное состояние», в котором мы живем? 🙂
РЕДАКТИРОВАТЬ: Я делаю подразумеваемый последующий вопрос более явным: Apple поставляет libc ++ и libstdc ++ со своими системами. Предполагая, что один атакует основную проблему и пытается переключиться только на libc ++. Каков был бы рекомендуемый способ перехода с libstdc ++ на libc ++, учитывая, что 100% библиотек, установленных в настоящее время в вашей системе (некоторые поставляются с системой, большинство из них через macports, некоторые через ручную компиляцию), связаны с libstdc ++ (если есть) )? Кто-нибудь сделал это и выжил?
За исключением «скрытого» использования стандартных типов библиотек, совершенно безопасно смешивать libc ++ и libstdc ++ в одной программе, где некоторые TU (или библиотеки, или модули) используют libc ++, а некоторые используют libstdc ++. Пока интерфейсы между TU не используют несовместимые типы, не должно быть никаких проблем.
libc ++ использует встроенные пространства имен, чтобы гарантировать, что несовместимые типы ABI нельзя спутать друг с другом; если интерфейс использует libc ++ std::string
непосредственно библиотека, ожидающая libstdc ++ std::string
не будет ссылаться на интерфейс, потому что фактические символы отличаются: std::string
против std::__1::string
,
libc ++ также гарантирует, что низкоуровневые функции, такие как исключения и динамическое выделение памяти, совместимы с ABI (при условии, что вы создаете libstdc ++ и libc ++, используя одну и ту же библиотеку abi), поэтому безопасно освобождать память в TU, который использует, скажем, libc ++, когда память была выделена в TU, использующем libstdc ++, или для создания исключения из сборки кода на libc ++ и перехвата его в коде с использованием libstdc ++.
Может быть проблема, когда типы в интерфейсах скрывают стандартные типы библиотек; дан интерфейс с использованием struct S { std::string s; };
определение типа S
будет отличаться в зависимости от того, что думает ТУ std::string
нарушает одно определение правила.
Однако это звучит так, как будто ваша настоящая проблема с библиотеками, которые делать использовать стандартные типы библиотек в интерфейсах.
Я предполагаю, что можно предположить, что если я действительно хочу использовать libc ++, я должен очистить свою систему от всего, что использует stdlibc ++, и убедиться, что что-либо из macports (или где-либо еще) связывается только с libc ++. Вы могли видеть, насколько сложной выглядит эта задача.
Вам нужно только убедиться, что TU, которые используют стандартную библиотеку в интерфейсах, используют libc ++. Вам не нужно полностью очищать libstdc ++. Библиотеки, которые не используют стандартную библиотеку в своем интерфейсе, могут продолжать связываться с libstdc ++.
РЕДАКТИРОВАТЬ: Я делаю подразумеваемый последующий вопрос более явным: Apple поставляет libc ++ и libstdc ++ со своими системами. Предполагая, что один атакует основную проблему и пытается переключиться только на libc ++. Каков был бы рекомендуемый способ перехода с libstdc ++ на libc ++, учитывая, что 100% библиотек, установленных в настоящее время в вашей системе (некоторые поставляются с системой, большинство из них через macports, некоторые через ручную компиляцию), связаны с libstdc ++ (если есть) )? Кто-нибудь сделал это и выжил?
Помните, это имеет значение только тогда, когда стандартная библиотека используется в интерфейсах. Надеемся, что такие библиотеки уже переходят на libc ++ самостоятельно при сборке для OS X. Если нет, возможно, они примут патчи для этого.
Сборка ваших собственных двоичных файлов с использованием соответствующей библиотеки не является «хаком»; это правильная вещь, если вы не работаете над проектом верхнего уровня. Если вы постоянно используете libc ++ в своем собственном коде, вам не нужно создавать несколько версий какой-либо библиотеки; только версии libc ++.
Ссылка для abi совместимости libc ++: http://lists.cs.uiuc.edu/pipermail/cfe-dev/2012-September/024594.html
Тебе это не понравится.
Вы просто не можете иметь ABI, который использует типы, определения которых меняются в разных системах. Это то, что вы делаете, когда у вас есть ABI, который использует std::string
(например), а затем скомпилируйте это, используя разные компиляторы или на разных платформах.
Чтобы исправить это, мой предпочтительный подход — если возможно — будет состоять в том, чтобы исключить все специфичные для компилятора вещи из 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;
}
Валовой. Возможно, неэффективно. Много кода для записи. Но это тот угол, в который ты покрасил себя.