Как использовать DLL в проекте Haskell?
Я хотел бы использовать внешнюю библиотеку RDFox в проекте Haskell.
Контекст: Я работаю над Windows и Linux, как с 64 битами, используя GHC 7.10, так и stack. RDFox запрограммирован на С++. Общие библиотеки RDFox (.dll,.so) могут быть загружены с помощью оболочек Java и Python.
Цель: Я хотел бы повторно использовать скомпилированные библиотеки из RDFox (.dll,.so) в моем проекте в Haskell, поэтому мне нужно создать оболочку Haskell для RDFox.
Проблемы: Будучи относительно новым для Haskell, я с трудом знаю, с чего начать. Я нашел несколько страниц по теме (из Haskell wiki и StackOverflow), но рабочий процесс и конфигурация мне не понятны.
Вопросы: Я хотел бы знать:
- Как настроить stack и cabal для использования внешней библиотеки, для создания на Windows или Linux (разные машины, один и тот же репозиторий).
- Как настроить GHCi для интерактивного тестирования этой внешней библиотеки.
- Является ли перевод оболочки Python на Haskell лучшим способом? Я бы хотел избежать анализа кода RDFox С++.
Ответы
Ответ 1
-
Вам нужно использовать extra-lib-dirs
и extra-libraries
в разделе executable
вашего файла .cabal
так:
name: MyApp
version: 0.1.0.0
synopsis:
homepage:
author: simon.bourne
category:
build-type: Simple
cabal-version: >=1.10
library
exposed-modules: HelloWorld
build-depends: base >= 4.7 && < 5
hs-source-dirs: src
default-language: Haskell2010
executable MyApp
main-is: Main.hs
extra-lib-dirs: lib
extra-libraries: helloWorld
build-depends: base >= 4.7 && < 5,
MyApp
hs-source-dirs: app
default-language: Haskell2010
Поместите свою dll и .so в lib
. Будьте осторожны, вы столкнетесь с проблемами порядка ссылок, если вы используете статическую библиотеку (.a
вместо .so
) в linux.
См. этот для примера. Не обманывайте себя именем, так как он отлично работает с файлами .so
.
-
stack ghci
должен работать только при условии, что он может найти вашу библиотеку (LD_LIBRARY_PATH
в Linux).
-
API C (упомянутый в комментариях к вашему вопросу) уже существует. Вам просто нужно написать сигнатуры FFI Haskell, например:
foreign import ccall safe "helloWorld" c_helloWorld :: IO ()
Я бы очень рекомендовал использовать safe
ccalls и не переносить функции в unsafePerformIO
.
Если вам нужно передать непрозрачные структуры, вы можете изучить c2hs
или hsc2hs
, но я не думаю, что вам нужно будет. Подробнее см. question.
Ответ 2
Вам нужно создать C-экспортированную оболочку для С++ api и оболочки Haskell для FFI в C-экспортированную оболочку.
Маршалинг между С# и Haskell описан здесь:
Вызов Haskell с С#
но он очень похож на маршалинг между С++ и Haskell
Например, создайте функцию экспорта С++:
extern "C" __declspec(dllexport) int __cdecl addFive(int number);
extern "C" __declspec(dllexport) int __cdecl addFive(int number)
{
return number + 5;
}
В Haskell вам нужен код импорта:
foreign import ccall "addFive" addFive :: Int -> Int
Затем вы можете использовать addFive в Haskell как типичную функцию Haskell
Для составных типов данных (классов и структур) вам нужно создать аналог типа данных С++ в Haskell. Затем вам нужно описать, как типы данных маршала от С++ до Haskell и от Haskell до С++.
В Haskell это означает, что вам нужно создать экземпляр Storable для ваших типов данных.
Ответ 3
Ответ эта документация:
ghc -c Adder.hs
ghc -c StartEnd.c
ghc -shared -o Adder.dll Adder.o Adder_stub.o StartEnd.o