2015-07-03 2 views
42

Я хотел бы использовать внешнюю библиотеку, RDFox, в проекте Haskell.Как использовать DLL в проекте Haskell?

Контекст: Я работаю над Windows и Linux, как 64 бит, используя GHC 7.10, так и stack. RDFox запрограммирован на C++. Общие библиотеки RDFox (.dll, .so) могут быть загружены с помощью оболочек Java и Python.

Цель: Я хотел бы повторно использовать скомпилированные библиотеки из RDFox (.dll, .so) в моем проекте в Haskell, так что мне нужно, чтобы создать оболочку для Haskell RDFox.

Вопросы: Будучи относительно новым для Haskell, я с трудом знаю, с чего начать. Я нашел несколько страниц по этому вопросу (из Haskell wiki и StackOverflow), но рабочий процесс и конфигурация мне не понятны.

Вопросы: Я хотел бы знать:

  1. Как настроить стек и заговорщиков использовать внешнюю библиотеку, чтобы построить на Windows, или Linux (разные машины, то же хранилище).
  2. Как настроить GHCi для интерактивного тестирования этой внешней библиотеки.
  3. Является ли перевод оболочки Python на Haskell лучшим способом? Я бы хотел избежать анализа кода RDFox C++.
+1

Сначала вам, вероятно, потребуется создать C-экспортированную оболочку для C++ api. – alternative

+0

Невозможно напрямую создать обертку в Haskell? Я имею в виду, если мне нужно создать обертку C, а затем Haskell, в чем смысл? –

+1

Соглашения об именах в C++ намного сложнее, чем в C. Я не думаю, что FFI поддерживает манипуляции с именами для вещей, отличных от extern-C. – alternative

ответ

1
  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 
    

    Put ваша dll и .so в lib. Будьте осторожны, вы столкнетесь с проблемами порядка ссылок, если используете статическую библиотеку (.a вместо .so) на linux.

    См. Например, this. Не обманывайте себя именем, так как он отлично работает с файлами .so.

  2. stack ghci должен работать только при условии, что он может найти вашу библиотеку (LD_LIBRARY_PATH на linux).

  3. API C (упомянутый в комментариях к вашему вопросу) уже существует. Вам просто нужно написать подписи Haskell FFI, например:

    foreign import ccall safe "helloWorld" c_helloWorld :: IO() 
    

    Я очень сильно советую использовать safe ccalls, и не завернуть функции в unsafePerformIO.

    Если вам нужно передать непрозрачные структуры, вы можете изучить c2hs или hsc2hs, но я не думаю, что вам это нужно.См. Это question для более подробной информации.

1

Вам необходимо создать C-экспортированную оболочку для C++ api и оболочки Haskell для FFI в C-экспортированную оболочку.

Маршалинг между C# и Haskell описано здесь: Calling Haskell from C#

но очень похоже маршалингом между C++ и Haskell

Например, можно создать C++ функция экспорта:

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

Для типов данных (классов и структур) для сопоставления вам нужно создать аналог типа данных C++ в Haskell. Затем вам нужно описать, как типы данных маршала от C++ до Haskell и от Haskell до C++.

В Haskell это означает, что вам необходимо создать экземпляр Storable для ваших типов данных.