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