Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use a DLL in a Haskell project?

I would like to use an external library, RDFox, in a Haskell project.

Context: I am working on Windows and Linux, both 64 bits, using GHC 7.10 and stack. RDFox is programmed in C++. RDFox shared libraries (.dll, .so) can be downloaded with Java and Python wrappers.

Aim: I would like to reuse the compiled libraries from RDFox (.dll, .so) in my project in Haskell, so I need to create a Haskell wrapper for RDFox.

Issues: Being relatively new to Haskell, I have difficulty to know where to start. I found several pages about the subject (from the Haskell wiki and StackOverflow), but the workflow and configuration are not clear to me.

Questions: I would like to know:

  1. How to configure stack and cabal to use external library, to build on Windows or Linux (different machines, same repository).
  2. How to configure GHCi for interactive testing on this external library.
  3. Is the translation of the Python wrapper to Haskell the best way to go? I would like to avoid the analysis of the RDFox C++ code.
like image 846
Der Vogel Avatar asked Jul 03 '15 07:07

Der Vogel


2 Answers

  1. You'll need to use extra-lib-dirs and extra-libraries in the executable section of your .cabal file like so:

    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 your dll and .so in lib. Be warned, you'll run into link order problems if you use a static library (.a instead of .so) on linux.

    See this for an example. Don't be fooled by the name as it works fine with .so files.

  2. stack ghci should just work provided it can find your library (LD_LIBRARY_PATH on linux).

  3. The C API (mentioned in the comments on your question) is already there. You just need to write the Haskell FFI signatures, for example:

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

    I'd very strongly advise using safe ccalls, and don't wrap the functions in unsafePerformIO.

    If you need to pass non opaque structs, you might want to investigate c2hs or hsc2hs, but I don't think you'll need to. See this question for more details.

like image 151
Simon Bourne Avatar answered Oct 03 '22 00:10

Simon Bourne


You need to create a C-exported wrapper for the C++ api and Haskell wrapper to FFI to C-exported wrapper.

Marshaling between C# and Haskell described here: Calling Haskell from C#

but it very similar marshaling between C++ and Haskell

For example, create C++ export function:

extern "C" __declspec(dllexport) int __cdecl addFive(int number);

extern "C" __declspec(dllexport) int __cdecl addFive(int number)
{
    return number + 5;
}

In Haskell you need import code:

foreign import ccall "addFive" addFive :: Int -> Int

Then you can use addFive in Haskell as typical Haskell-function

For compbound data types (classes and structures) you need create C++ data-type analog in Haskell. Then you need describe how marshal data types from C++ to Haskell and from Haskell to C++.

In Haskell it means that you need create Storable instance for you data types.

like image 37
Bet Avatar answered Oct 03 '22 02:10

Bet