Подтвердить что ты не робот

Создание библиотеки с обратно совместимым ABI, который использует Boost

Я работаю над определенной библиотекой С++ (или более фреймворком). Я хочу сделать это назад совместимый с предыдущими версиями, сохраняющий не только совместимость API, но также и ABI (например, отличная работа Qt).

Я использую много функций Boost, и мне кажется, что это делает обратную совместимость просто невозможной, если я не заставляю пользователя иметь точно такую ​​же (иногда старую) версию Boost.

Есть ли способ (без перезаписи 1/2 из Boost), чтобы сделать некоторый "префикс" вокруг своего пространства имен/переименовать его, чтобы предотвратить его вмешательство в пользовательскую версию Boost?

Например, мой libXYZ использует Boost 1.33 и имеет класс boost::foo. В версии 1.35 boost::foo была обновлена ​​и добавлен новый элемент, поэтому boost::foo от 1.33 до 1.35 не совместимы с ABI. Таким образом, пользователь libXYZ должен использовать Boost 1.33 или перекомпилировать libXYZ с Boost 1.35 (возможно, уже был сломан некоторый API таким образом, что XYZ не будет компилироваться).

Примечание.. Я говорю об ОС UNIX/Linux с ELF, где динамическая компоновка похожа на статическую привязку, поэтому вы не можете связываться с двумя разными версиями библиотек, потому что символы будут мешать.

Одним из подходящих решений, о которых я могу думать, является добавление Boost в другое частное пространство имен. Таким образом, libXYZ будет использовать ::XYZ::boost::foo вместо ::boost::foo. Это предотвратит столкновение с другой версией Boost, которую пользователь может использовать.

Итак, libXYZ будет продолжать работать с Boost 1.33, статически или динамически связанным с ним, с другим пространством имен, предполагая, что он:

  • Не будет раскрывать API Boost вне.
  • Будет поддерживать стабильную частную версию открытого API.

Есть ли способ сделать такие вещи с помощью Boost?

Изменить: Наконец, я решил создать script, который переименовал бы все символы boost в источнике в какой-то пользовательский символ.

Обоснование: упрощение процесса сборки, независимо от поддержки видимости компилятора, также, видимость работает только для динамических библиотек, для статичности это не работает, поэтому мне нужны отдельные сборки и зависимости для каждого типа библиотек.

Доступен script: http://art-blog.no-ip.info/files/rename.py

Изменить 2: Последняя версия Boost BCP поддерживает переименование пространства имен.

4b9b3361

Ответ 1

В принципе, просто убедитесь, что публичный интерфейс в вашей библиотеке не предоставляет Boost. Вы всегда можете использовать его, как хотите, внутренне. Как правило, наличие интерфейса библиотеки зависит от другой библиотеки, это плохо (если только она не зависит от стандартной библиотеки, такой как STL). Boost почти вписывается в "стандартную" библиотечную категорию, но ее ABI изменяется настолько, что ваш интерфейс не должен его использовать.

Чтобы убедиться, что вы не показываете символы Boost, вы можете сделать несколько действий:

а. скомпилируйте с -fvisibility=hidden и отметьте все общедоступные символы __attribute__((visibility("default"))). вы можете использовать макрос, чтобы сделать это проще:

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

В. сделайте что-нибудь вроде этого:

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

Вы также должны обернуть это вокруг всех других внутренних символов, которые вы не хотите экспортировать, или объявите это с помощью __attribute__((visibility("hidden"))). Опять же, вы можете использовать макрос, чтобы сделать это проще:

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

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

Кстати, вы можете найти гораздо больше информации о создании DSO в Ulrich Drepper Как писать общие библиотеки.

Ответ 2

В общем, вы не можете полагаться на любой тип ABI в С++ за пределами стандартных привязок C. Но в зависимости от того, сколько вы сделаете допущений, вы можете использовать все больше и больше С++ в своем интерфейсе.

Я нашел эту отличную статью о шагах, чтобы превратить ваш API в стабильный ABI. Например, никогда не пропускайте типы данных стандартной библиотеки С++ (или Boost) на вашем интерфейсе; он может сломаться даже при небольшом исправлении ошибок в библиотеке.

Некоторые примеры проблем, которые следует учитывать при публикации API, совместимого с ABI, следующие:

  • Куча отладки Windows. Вы должны быть уверены, что все распределения и освобождения находятся на одной стороне "модуля" (то есть исполняемого файла или библиотеки DLL).
  • проблема Fragile Binary Interface. Даже если обе стороны вашей системы последовательно используют один и тот же компилятор и библиотеки, вы должны быть осторожны в С++ о том, что вы публикуете в своих файлах .h, и где происходит распределение.

Если вы следуете связанной статье, вы найдете решения по этим и другим вопросам.

Edit

Я также нашел интересную статью опубликованную Microsoft, в которой описывается работа COM-интерфейсов, взяв проект С++ и превратив его в COM. Я полагаю, что одной из основных причин, по которым Microsoft разработала COM, было решение проблемы Fragile Binary Interface, которую имеет С++, поэтому они могут отправлять DLL с объектно-ориентированными API-интерфейсами.

Ответ 3

Рассмотрите возможность использования abi-compliance-checker для поддержки стабильного интерфейса API/ABI.

Ответ 4

Вы должны сделать что-то вроде этого:

namespace XYZ
{
#include <boost/my_library.hpp>
}

И он должен сбрасывать заголовки boost в пространство имен XYZ. Обратите внимание, однако, что это будет работать только с библиотеками только для заголовков.