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

Статическая ссылка библиотеки С++ с библиотекой Haskell

Настройка: у меня есть библиотека Haskell HLib, которая делает вызовы на бэкэнд C/С++ CLib для эффективности. Бэкэнд небольшой и специализирован для использования с HLib. Интерфейс CLib будет отображаться только через HLib; Тесты HLib, тесты HLib и сторонние библиотеки в зависимости от HLib не будут направлять прямые вызовы FFI на CLib. С точки зрения тестирования/бенчмарка/третьей стороны, HLib должен отображаться чисто Haskell. Это означает, что в разделах файла кэша для, например, тестов HLib не должно быть ссылок на -lCLib, libCLib и т.д., Только build-depends на HLib, и что исполняемым файлам не нужно искать для динамической библиотеки CLib. Мне нужно иметь возможность создавать и запускать все исполняемые файлы в HLib и сторонних библиотеках, а также запускать cabal repl для разработки.

Первоначально CLib был написан в чистом C. Кабаль имеет поддержку для этого случая, и я могу интегрировать CLib в HLib точно так, как описано выше, используя include-dirs, c-sources и includes в файле cabal.

CLib превратился в библиотеку С++, и я не мог понять, как легко интегрировать кэбаль. Вместо этого я прибегал к make файлу с пользовательской сборкой и Setup.hs, например this. Вы можете увидеть небольшой пример этого метода здесь 1,2.

В этом примере я не могу запустить cabal repl в HLib, потому что "Загрузка архивов не поддерживается". Это действительно означает, что мне нужна динамическая библиотека С++, которая достаточно проста для создания (там есть прокомментированная строка в make файле CLib). Однако, если я делаю динамическую С++-библиотеку, тест для HLib завершается с ошибкой во время выполнения из-за отсутствия такого файла или каталога libclib.so. Это плохо (в дополнение к сбою), потому что тестовый исполняемый файл связан с динамической библиотекой, чего я не хочу.

Конкретно, тесты для HLib и SimpleLib должны пройти, и я должен иметь возможность запускать cabal repl в каталогах HLib и SimpleLib.

Другие вещи, которые я пробовал: этот ответ, этот ответ (который я не могу получить для компиляции), this и чтение документов (приводит к ошибкам "перемещения" ).

Я использую GHC-7.10.3 на данный момент, хотя, если это значительно проще в 8.0, это прекрасно.

[1] Упрощено из lol/problems.

[2] Загрузите и запустите ./sandbox-init. Это создает HLib (который неявно строит CLib и SimpleLib, который является библиотекой Haskell, которая зависит от HLib.

4b9b3361

Ответ 1

Включение библиотеки C или С++ с библиотекой Haskell тривиально, если вы знаете несколько трюков.

Я получил ядро ​​из этой статьи хотя, похоже, это слишком сложно. Вы можете использовать cabal (в настоящее время 1.25) с типом сборки Simple (т.е. Специальным Setup.hs), без make файла и без внешних инструментов, таких как c2hs.

Чтобы включить символы из чистой библиотеки C:

  • В вашем файле кэша добавьте Include-dirs: relative/path/to/headers/ или Includes: relative/path/to/myheader.h.
  • Добавить C-sources: relative/path/to/csources/c1.c, relative/path/to/csources/c2.c, etc.

Там есть пара дополнительных бит для С++:

  1. Вы можете добавить файлы .cpp в поле C-sources в файле cabal.
  2. Для всех функций в файлах .cpp, к которым нужен доступ Haskell, добавьте extern "C", чтобы избежать изменения имени.
  3. Обведите весь не-чистый код в заголовочных файлах с помощью #ifdef __cplusplus ... #endif (см. n.m. answer).
  4. Если вы используете стандартную библиотеку С++, вам нужно добавить extra-libraries: stdc++ в свой файл cabal и связать с g++ с помощью ghc-options: -pgmlg++.
  5. Возможно, вам придется немного поиграть с порядком, в котором вы указываете файлы .c(pp) в файле cabal, если вы хотите, чтобы динамическая компоновка (т.е. cabal repl) работала. Подробнее см. этот билет.

Что это! Вы можете увидеть полный рабочий пример здесь, который работает как с stack, так и с cabal.

Ответ 2

GHC не может понять файлы заголовков С++. Он нуждается в чистом C-коде. Общий способ для файла заголовка С++ для предоставления интерфейса C состоит в том, чтобы изолировать части С++ с помощью #ifdef __cplusplus, например:

#ifdef __cplusplus
extern "C" {         // C compilers and various C-based FFIs don't like this
#endif

void foo();

#ifdef __cplusplus
}
#endif

Кроме того, GHCi, как известно, имеет проблемы со связыванием кода на С++. Например, в какой-то момент он не понимал слабые символы (часто создаваемые компилятором в сочетании с встроенными функциями и экземплярами шаблонов). Возможно, вы столкнулись с одной из этих проблем. Я бы рекомендовал подать отчет об ошибке команде GHC.