Как структурировать библиотеку C ++ с помощью языковых оболочек? - PullRequest
0 голосов
/ 27 мая 2018

У меня есть вопрос о передовой практике написания библиотеки C ++, которая включает в себя оболочки для других языков, таких как Python и Matlab.Это может быть простой вопрос или дубликат, но я не нашел хорошего ресурса или другого ответа, который помог бы объяснить, как это сделать.

Для фона я работаю над проектом библиотеки C ++, в котором есть CОбертки включены специально для совместимости с другими языками.Библиотека является научной вычислительной библиотекой, написанной на C ++, и я уже написал оболочки C для функций и классов, которые будут использоваться как часть общей библиотеки.

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

Например, у меня есть следующая структура каталогов, где каждая папка содержит код, относящийся к другому языку / модулю.

top
├─ matlab
│  ├─ CMakeLists.txt
│  ├─ matlab_wrapper.hpp
│  └─ matlab_wrapper.cc
├─ python
│  ├─ CMakeLists.txt
│  ├─ python_wrapper.hpp
│  └─ python_wrapper.cc
├─ src
│  ├─ CMakeLists.txt
│  ├─ c_wrapper.hpp
│  ├─ c_wrapper.cc
│  └─ other code...
└─ CMakeLists.txt

Я понимаю, что каждая папка должна быть самодостаточной и создаваемой сама по себе, но мне сложно понять, как распространять код так, чтобы он включал оболочки C.По сути, у меня есть реализация C в файлах c_wrapper, и я хотел бы использовать ее в библиотеках matlab и python.

Обычно я включал бы другие исходные файлы на этапе сборки и покончил с этим (это может быть просто ответом), но все в папке src создается и распространяется как его собственная общая библиотека,Кажется излишним либо переписать оболочки C в файлы matlab_wrapper и python_wrapper (в основном создавая 3 версии одной и той же функции), либо включить файлы c_wrapper в шаг сборки других библиотек, поскольку они уже включеныв основной библиотеке C ++.

Я не эксперт в упаковке общих библиотек, так как лучше всего это сделать?Должен ли я просто включить исходные файлы c_wrapper как часть этапа сборки, переписать оболочки C ++ в каждом модуле или есть другой способ включить код в c_wrapper в библиотеки оболочек?В идеале каждый модуль будет использовать один и тот же (или очень похожий) API, поэтому было бы замечательно, если бы был способ включить этот код без переписывания одной и той же функции каждый раз, когда добавляется новая обертка Си.Любая помощь или совет с благодарностью.

1 Ответ

0 голосов
/ 29 мая 2018

Возможно, вы сможете создать одну общую библиотеку для всех целей: PyInit_foo, которую Python ищет , в конце концов будет просто игнорироваться Matlab.Но вы все еще можете не захотеть изменять свою основную библиотеку для поддержки такого использования: возможно, у нее есть другие скомпилированные клиенты, которые не нуждаются в обертке, или, возможно, она должна быть установлена ​​отдельно от специальных оболочек, или, возможно, ее нужно использовать на машине безустановленные хосты.

Другой вариант - создать одну общую библиотеку для каждого конечного клиента.Объединение одних и тех же объектных файлов в каждый из них лишает некоторые цели общих библиотек, таких как разделение памяти между процессом Matlab и параллельным процессом Python, каждый из которых использует вашу библиотеку.Это может (я не уверен) также в конечном итоге запускать глобальные конструкторы более одного раза, но в любом случае их лучше избегать.Эти проблемы могут не иметь значения для ваших вариантов использования, но применимы те же проблемы сборки, что и раньше для реальной библиотеки C ++.

В противном случае у вас будет несколько общих библиотек в одном процессе (одна для «настоящего» C ++).библиотека и еще один для основного языка модуля).Здесь проблем с ABI ;Один из способов избежать их - предоставить, как вы предложили, C API в базовой библиотеке.Конечно, есть и другие способы решения этих проблем, особенно когда вы управляете всеми компиляциями.

Существует еще больше подходов: основная библиотека может включать интерфейс для одного основного языка (особенно, если это возможно).также служит C API), но не другой, или одна общая библиотека может обслуживать несколько языков, не включая ядро ​​C ++.Учитывая C API, вы можете использовать FFI из языка хоста (ctypes для Python) вместо написания (подробнее) C специально для хоста.

Какую бы стратегию связи вы не выбрали, компиляция всегда одинакова: просто #include независимо от того, какие из ваших заголовков являются релевантными (те, которые для C API, если это уместно), и любые, необходимые для основного языка (еслилюбой) и иди.

...