Создание C ++ API Library - PullRequest
6 голосов
/ 25 июня 2019

Я пытаюсь понять правильный или правильный подход к предоставлению достаточно большого C ++ API для проекта с открытым исходным кодом.Я не хочу предоставлять библиотеку «только заголовок», так как база кода довольно большая и предназначена для закрытого источника.Цели заключаются в следующем:

  • Предоставить собственный API C ++, который пользователи могут создавать экземпляры классов C ++, передавать данные, все в C ++, без оболочки только для C
  • Разрешить методампринимать в качестве параметров и возвращать объекты C ++, особенно типы STL (std :: string, std :: vector и т. д.)
  • Без пользовательских распределителей
  • Большинство отраслевых / канонических методов, позволяющих это сделать,если такой стандарт существует
  • Нет повторного создания COM или использования MS COM
  • Предположим, что все компиляторы C ++ по крайней мере C ++ 11 "совместимы"

IЯ ориентируюсь на Windows, а также на другие платформы (Linux).

Насколько я понимаю, создание библиотеки DLL или общей библиотеки не может быть и речи из-за проблемы с границами DLL.Чтобы решить проблему с границами DLL, DLL и вызывающий код должны быть скомпилированы с динамически связанной средой выполнения (и верной версией, многопоточным / debug / etc для Windows), и тогда все настройки компилятора должны будут соответствовать символам отладки (настройки отладки итератора и т. д.).У меня есть один вопрос: если, скажем, в Windows мы гарантируем, что параметры компилятора совпадают с точки зрения / MD, используя настройки «Debug» и «Releas» по умолчанию в Visual Studio, можем ли мы действительно быть «безопасными» в использованиитаким образом DLL (то есть передача объектов STL туда-сюда и различные вещи, которые, безусловно, были бы опасными / потерпели неудачу в случае несоответствия)?У общего объекта * .so в Linux под gcc такая же проблема?

Решает ли использование статических библиотек эту проблему?Насколько настройки компилятора должны совпадать между статической библиотекой и вызывающим кодом, с которым она связана?Это почти та же проблема, что и DLL (в Windows)?

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

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

Я в порядке со статическими библиотеками, если это решает проблему.Я также мог бы согласиться с идеей иметь набор X-компиляторов с Y-вариациями настроек (где X и Y - заранее определенный список поддерживаемых опций) и иметь систему сборки, которая генерировала бы общие двоичные библиотеки X * Y, если этобыл "безопасен".

Действительно ли ответ заключается только в том, чтобы делать либо интерфейсы C, либо создавать интерфейсы Pure Abstract с фабриками?(если это так, есть ли каноническая книга или руководство по написанию этой статьи, которое не реализует Microsoft COM?).

Мне известно о шаблоне песочных часов Stefanus DuToit: https://www.youtube.com/watch?v=PVYdHDm0q6Y

Я переживаю, что много дублирования кода.

Я не жалуюсь на положение вещей, я просто хочу понять «правильный» путь, и, надеюсь, это послужит хорошим вопросом длядругие в аналогичном положении.

Я рассмотрел следующие ссылки на Stackoverflow:

Когда использовать динамические и статические библиотеки

Как мнебезопасно передавать объекты, особенно объекты STL, в и из DLL?

Распространение библиотеки Windows C ++: как решить, создавать ли статическую или динамическую библиотеку?

Вопрос API статической библиотеки (std :: string vs. char *)

Простой способ гарантировать двоичную совместимость для библиотеки C ++, связи C?

Также рассмотрели:

https://www.acodersjourney.com/cplusplus-static-vs-dynamic-libraries/

https://blogs.msmvps.com/gdicanio/2016/07/11/the-perils-of-c-interface-dlls/

Ответы [ 3 ]

1 голос
/ 25 июня 2019

Учитывая ваши требования, вам понадобится статическая библиотека (например, .lib под windows), которая будет связана с вашей программой на этапе сборки.

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

Вы можете распространять в виде набора библиотек и заголовочных файлов, если они могут быть чисто разбиты на отдельные части - если вы управляете зависимостями между частями. Это необязательно.

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

Основным недостатком является то, что вам нужно будет создать и распространить версию библиотеки для каждого компилятора и хост-системы (в комбинации, которую вы поддерживаете). Стандарт C ++, в частности, поощряет различные типы несовместимостей (например, различные искажения имен) между компиляторами, поэтому, вообще говоря, код, созданный с помощью одного компилятора, не будет взаимодействовать с кодом, созданным с помощью другого компилятора C ++. Практически, ваша библиотека не будет работать с компилятором, отличным от того, с которым она построена, если только эти компиляторы специально не реализованы (например, по соглашению обоих поставщиков) для совместимости. Если вы поддерживаете компилятор, который поддерживает разные ABI между версиями (например, g++), то вам нужно будет распространять версию вашей библиотеки, созданную для каждой версии ABI (например, самую последнюю версию компилятора, которая поддерживает каждый ABI)

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

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

В большинстве случаев вам не понадобятся версии «Debug» и «Release» (или версии с другими настройками оптимизации) вашей библиотеки. Вообще говоря, нет проблем с связанными частями программы, которые компилируются с различными настройками оптимизации. (Это может привести к поломке, если вы - или программист, использующий вашу библиотеку в своей программе - используете экзотические комбинации опций сборки, поэтому сведите их к минимуму). Распространение «отладочной» версии вашей библиотеки позволит вам пройти через вашу библиотеку с помощью отладчика, который кажется противоречащим вашим пожеланиям.

Ничто из вышеперечисленного не мешает вам использовать пользовательские распределители, но также не требует этого.

Вам не нужно будет воссоздавать COM, если вы действительно этого не хотите. Фактически, вы должны стремиться к тому, чтобы ваш код был как можно более стандартным - минимизировать использование специфичных для компилятора функций, не делать особых предположений о размерах типов или расположении типов и т. Д. Использование специфических для поставщика функций, таких как COM, не рекомендуется. -нет, если эти функции не поддерживаются единообразно всеми целевыми компиляторами и системами, которые вы поддерживаете. Какой COM не является.

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

Кроме того, уделите время настройке набора тестов для своей библиотеки и регулярно поддерживайте его, чтобы он был максимально полным. Протестируйте свою библиотеку с этим набором на каждой комбинации компилятора / системы, которую вы поддерживаете.

1 голос
/ 25 июня 2019
  • Предоставляет собственный API C ++, который пользователи могут создавать экземпляры классов C ++, передавать данные, все в C ++, без оболочки только для C

Это исключает COM.

  • Разрешить методам принимать в качестве параметров и возвращать объекты C ++, особенно типы STL (std :: string, std :: vector и т. Д.)

Это исключает библиотеки DLL

  • Большинство отраслевых стандартов / канонический способ сделать это возможно, если такой стандарт существует

Не что-то "стандартное", но есть обычные практики. Например, в DLL, передайте только сырые вещи C.

  • Нет повторного создания COM или использования MS COM

Для этого требуются DLL / COM-серверы

  • Предположим, что все компиляторы C ++ по крайней мере "C ++ 11" совместимы "

Возможно. Обычно да.

Обычно: если источник должен быть доступен, используйте только заголовок (если шаблоны) или h + cpp. Если нет источника, лучше всего DLL. Статические библиотеки - вам нужно собрать много компиляторов, и каждый должен нести свою библиотеку повсюду и ссылка на нее.

0 голосов
/ 25 июня 2019

В linux gcc использует libstdc ++ для стандартной библиотеки c ++, а clang может использовать libc ++ или libstdc ++. Если ваши пользователи собирают с помощью clang и libc ++, они не смогут связываться, если вы строите только с помощью gcc и libstdc ++ (libc ++ и libstdc ++ не являются двоично-совместимыми). Поэтому, если вы не хотите получать целевой файл, вам нужны две версии вашей библиотеки: одна для libstdc ++, а другая для libc ++.

Кроме того, двоичные файлы в linux (исполняемый файл, статическая библиотека, динамическая библиотека) не являются двоично-совместимыми между дистрибутивами. Он может работать на вашем дистрибутиве и не работать на другом дистрибутиве или даже на другой версии вашего дистрибутива. Будьте очень осторожны, чтобы проверить, работает ли он на любом дистрибутиве, на который вы хотите нацелиться. Holy Build Box может помочь вам создать кросс-дистрибутивы. Я хорошо слышал об этом, просто никогда не пробовал. В худшем случае вам, возможно, потребуется собрать все дистрибутивы Linux, которые вы хотите поддерживать.

https://phusion.github.io/holy-build-box/

...