From HaskellWiki
Jump to navigation Jump to search

libffi is a binding to the C library libffi, allowing C functions to be called whose types are not known before run-time.

It was designed to easily enable the addition of an foreign function interface to a (not-yet-released) new interpreter.

How to use it

The main function it exports is:

 callFFI :: FunPtr a -> RetType b -> [Arg] -> IO b

In addition, many values like retWord64 :: RetType Word64 and argCULong :: CULong -> Arg are exported.

The main module to import is Foreign.LibFFI. Importing the other modules should only be necessary when one wants to extend the API to support passing/returning new types to C.


And because code is worth a thousand words, here a small program that uses C calls to write a 1Gb buffer of uninitialized garbage to a file:

import System.Posix.DynamicLinker
import Foreign.LibFFI
main = do
    malloc <- dlsym Default "malloc"
    creat  <- dlsym Default "creat"
    write  <- dlsym Default "write"
    let sz = 2 ^ 30
    buf <- callFFI malloc (retPtr retVoid) [argCSize sz]
    fd  <- callFFI creat  retCInt          [argString "/tmp/test", argCUInt 0o644]
    n   <- callFFI write  retCSize         [argCInt fd, argPtr buf, argCSize sz]
    putStrLn $ show n ++ " bytes written"

More interesting examples are included in examples/ in the package.

Does it work?

It should work on any 32/64bits machine on which libffi works, but has been primarily tested on linux x86_64. The current libffi is not exception-safe (exception = memory leak) and callFFI has quite some overhead that would be unnecessary with another api. It is, however, very easy to use.

In the long term, I am not sure whether it will survive in its current form: Although easy, the current API makes it impossible to be really efficient (with the lists, decoding and initialization for each call). In addition, libffi doesn't work on windows, and I am not sure whether e.g. a C/Invoke binding would use the same API.

How to get and install it

A cabal package is available here.

If you have cabal-install installed, this should also work:

cabal install libffi