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

Хорошая практика написания динамических библиотек C [DSO] (двоичная совместимость + управление памятью)

У меня есть опыт написания библиотек C, но я никогда не читал никаких официальных документов, описывающих хорошие практики при написании таких библиотек. Мой вопрос касается главным образом 2 тем:

  • Как поддерживать двоичную совместимость? (Я слышал о идиоме pImpl, d-указателе)
  • Как создать интерфейсы, которые остаются обратно совместимыми?

Самое главное в бинарной совместимости, которую я вижу из моих исследований, это то, что я могу сделать бинарные библиотеки библиотек с помощью идиомы pImpl, но изменение структуры/добавление новых элементов данных и т.д. может повлиять на ее двоичную совместимость даже при использовании pImpl. Кроме того, есть ли способ добавить новые методы/функции в библиотеку, не нарушая при этом бинарную совместимость? Я предполагаю, что добавление этих вещей изменило бы размер, расположение библиотеки, нарушая при этом совместимость.

Есть ли инструмент для проверки совместимости двоичных файлов?

Я уже читал эти статьи. Есть ли другие документы, которые я могу просмотреть?

http://en.wikipedia.org/wiki/Opaque_pointer

http://techbase.kde.org/Policies/Binary_Compatibility_Issues_With_C++

Кроме того, существуют статьи, описывающие проблемы владения памятью в контексте проектирования интерфейсов библиотеки. Каковы общие соглашения? Кому принадлежит память, как долго, кто несет ответственность за освобождение памяти и т.д.?

4b9b3361

Ответ 1

Ключевыми проблемами совместимости являются:

  • сигнатуры функций
  • формат любых данных, доступных как библиотекой, так и вызывающим абонентом
  • глобальные переменные в библиотеке, доступ к которой осуществляется вызывающим абонентом
  • код библиотеки, который попадает в вызывающий объект из-за макросов/встроенных функций в заголовках
  • #define/enum постоянные значения в общих заголовках

Итак, лучший список рекомендаций, которые я могу дать, это:

  • Никогда не изменяйте подписи (типы возврата/аргументов) любого открытого интерфейса. Если вам нужно расширить интерфейс, вместо этого добавьте новую функцию, которая принимает больше аргументов (подумайте dup по сравнению с dup2 или wait по сравнению с waitpid).
  • В максимально возможной степени используйте указатели на полностью инкапсулированные непрозрачные объекты данных и даже не публикуйте определения таких структур в публичных заголовках (сделайте их неполными struct).
  • Если вы хотите разделить структуру, устраивайте, чтобы вызывающий объект никогда не объявлял переменные этого типа структуры и вместо этого вызывал явные функции allocate/free в библиотеке. Никогда не изменяйте тип существующих участников или удаляйте существующих участников; вместо этого добавьте новые элементы только в конце структуры.
  • Не выставляйте глобальные переменные из библиотек, период. Если вы не понимаете "копирование переездов", лучше не спрашивать, почему. Просто не делай этого.
  • Не помещайте встроенные функции или макросы, содержащие код, в общедоступные заголовки библиотеки, если только использование документированного, открытого интерфейса не будет постоянным. Если они ткнут во внутренние объекты непрозрачных объектов данных, они вызовут проблемы, когда вы решите изменить внутренние элементы.
  • Не перенумеруйте существующие константы #define/enum. Добавляйте только новые константы с ранее неиспользуемыми значениями.

Если вы будете следовать этим рекомендациям, я думаю, что вы покрыты не менее чем на 95%.

Ответ 2

Есть ли инструмент для проверки совместимости двоичных файлов?

ABI Compliance Checker - инструмент для проверки обратной двоичной совместимости общей библиотеки C/С++ (DSO).

Есть ли другие документы, которые я могу просмотреть?

Смотрите этот длинный список статей по двоичной совместимости разделяемых библиотек.

Как создать интерфейсы, которые остаются обратно совместимыми?

Использование полей зарезервировано/дополнений - это общий метод сохранения совместимости библиотек C. Но есть и много других.

Кроме того, есть ли способ добавить новые методы/функции в библиотеку, не нарушая при этом бинарную совместимость? Я предполагаю, что добавление этих вещей изменило бы размер, расположение библиотеки, нарушая при этом совместимость.

Добавлены функции C не нарушают двоичную совместимость DSO на Linux и Mac. То же самое можно сказать о Windows и Symbian, но вы должны добавлять новые функции только в конец файла .DEF. Однако передняя совместимость всегда прерывается добавленными функциями.

Добавленные методы С++ ломают бинарную совместимость тогда и только тогда, когда они являются виртуальными или чисто-виртуальными, поскольку макет v-table может измениться. Но ваш вопрос, похоже, касается только C.

Ответ 3

Несколько вещей, чтобы добавить к тому, что сказал Р.:

Так как кажется, что вы говорите о C ABI, а не о С++ ABI:

изменение структуры/добавление новых элементов данных и т.д. может повлиять на ее двоичную совместимость даже при использовании pImpl

Это не должно быть при использовании pIMpl - если внешние пользователи объекта имеют только непрозрачный указатель/дескриптор объекта, а только библиотека имеет дело с внутренними элементами структуры, то по определению вещь, которая имеет дело с внутренними структурами, совместимыми с ним.

Есть ли способ добавить новые методы/функции в библиотеку, не нарушая при этом бинарную совместимость? Я предполагаю, что добавление этих вещей изменило бы размер, расположение библиотеки, нарушая при этом совместимость.

Добавление новых функций или изменение размера или макета общей библиотеки не нарушает совместимость с двоичными файлами. Поскольку привязка к адресу функции не выполняется до тех пор, пока в процесс не будет загружена общая библиотека, изменение местоположения целевой функции не является проблемой.