Что такое хороший способ обработки ABI-различий между libС++ и старым libstdС++? - программирование
Подтвердить что ты не робот

Что такое хороший способ обработки ABI-различий между libС++ и старым libstdС++?

Что (если есть) является хорошим способом обработки несоответствия ABI между libС++ и stdlibС++ на Mac?

Проблема: для многих функций С++ 11 требуется новая реализация libС++ стандартной библиотеки С++. Но libС++ не совместим с ABI со старым libstdС++, в то время как в настоящее время большинство программ обычно связывается с последним. Например, системный компилятор по-прежнему использует stdlibС++, что означает, что все мои библиотеки, установленные с macports, имеют разные ABI для std-классов, таких как строка, и несовместимы с проектами, которые сильно используют С++ 11.

Мое текущее решение: сохраняйте две версии библиотек, где это обычно приводит к проблеме (boost, opencv и т.д.) и ссылается на соответствующий.

Я предполагаю, что можно предположить, что если я действительно хочу использовать libС++, я должен очистить мою систему чего-либо, используя stdlibС++, и убедиться, что что-либо из macports (или где-либо еще) связано только с libС++. Вы могли видеть, насколько сложна эта задача.

Кто-нибудь разработал хороший способ связать это "между-stdlib-limbo", в котором мы живем?:)

EDIT: я делаю подразумеваемый последующий вопрос более явным: Apple отправляет как libС++, так и libstdС++ с их системами. Предполагая, что один атакует основную проблему и пытается перейти на libС++ - только. Каким будет рекомендуемый способ перехода с libstdС++ на libС++, учитывая, что 100% библиотек, установленных в вашей системе (некоторые из них поставляются вместе с системой, большинство из них с помощью macports, несколько с помощью ручной компиляции) связаны с libstdС++ (если есть )? Кто-нибудь сделал это и выжил?

4b9b3361

Ответ 1

Запрет "скрытых" использования стандартных типов библиотек совершенно безопасно смешивать libС++ и libstdС++ в одной программе, где некоторые TU (или библиотеки или модули) используют libС++, а некоторые используют libstdС++. Пока интерфейсы между TU не используют несовместимые типы, проблем не должно быть.

libС++ использует inline namespaces, чтобы гарантировать, что ABI несовместимые типы не могут быть ошибочно приняты друг за друга; если интерфейс использует libС++ std::string, то библиотека, ожидающая libstdС++ std::string, не будет ссылаться на интерфейс, потому что фактические символы различны: std::string vs. std::__1::string.

libС++ также гарантирует, что низкоуровневые функции, такие как исключения и динамическое распределение памяти, совместимы с ABI (предполагается, что вы создаете libstdС++ и libС++, используя одну и ту же библиотеку abi), поэтому безопасно освобождать память в TU, который использует, скажем, libС++, когда память была выделена в TU с использованием libstdС++ или выбрала исключение из сборки кода на libС++ и поймала его в коде с помощью libstdС++.

Может возникнуть проблема, когда типы в интерфейсах скрывают стандартные типы библиотек; с использованием интерфейса struct S { std::string s; }; определение типа S будет различным, в зависимости от того, что TU считает std::string, тем самым нарушив одно правило определения.


Однако это звучит так, как будто ваша настоящая проблема связана с библиотеками, которые используют стандартные типы библиотек в интерфейсах.

Я предполагаю, что можно предположить, что если я действительно хочу использовать libС++, я должен очистить мою систему чего-либо, используя stdlibС++, и убедиться, что что-либо из macports (или где-либо еще) связано только с libС++. Вы могли видеть, насколько сложна эта задача.

Вам нужно только убедиться, что TU, которые используют стандартную библиотеку в интерфейсах, используют libС++. Вам не нужно полностью очищать libstdС++. Библиотеки, которые не используют стандартную библиотеку в своем интерфейсе, могут продолжать связываться с libstdС++.

EDIT: я делаю подразумеваемый последующий вопрос более явным: Apple отправляет как libС++, так и libstdС++ с их системами. Предполагая, что один атакует основную проблему и пытается перейти на libС++ - только. Каким будет рекомендуемый способ перехода с libstdС++ на libС++, учитывая, что 100% библиотек, установленных в вашей системе (некоторые из них поставляются вместе с системой, большинство из них с помощью macports, несколько с помощью ручной компиляции) связаны с libstdС++ (если есть )? Кто-нибудь сделал это и выжил?

Помните, что это имеет значение только при использовании стандартной библиотеки в интерфейсах. Надеемся, что такие библиотеки уже переходят на libС++ самостоятельно, когда они строят для OS X. Если нет, возможно, они будут принимать исправления для этого.

Создание собственных двоичных файлов с использованием соответствующей библиотеки не является "взломом"; это правильная вещь, если вы не хотите, чтобы восходящий проект делал это для вас. Если вы последовательно используете libС++ в своем собственном коде, вам не нужно будет создавать несколько версий любой библиотеки; только версии libС++.


ссылка для совместимости libi ++: http://lists.cs.uiuc.edu/pipermail/cfe-dev/2012-September/024594.html

Ответ 2

Вам это не понравится.

У вас просто не может быть 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;
}

Гросс. Возможно, неэффективно. Много кода для написания. Но это тот угол, в который вы нарисовали себя.