Calling C library functions dynamically in Haskell

Tweet
Posted on January 28, 2014 by Kwang Yul Seo
Tags: Haskell, FFI, C

Haskell FFI is used to call functions from C and for C to call Haskell functions. A classic example from Haskell Wiki page FFI Introduction is to call a C library function, sin from Haskell. In this method, you have to declare the type of C function you want to call using foreign import ccall.

{-# LANGUAGE ForeignFunctionInterface #-}
import Foreign.C
 
foreign import ccall "sin" c_sin :: CDouble -> CDouble
  
sin1 :: Double -> Double
sin1 d = realToFrac (c_sin (realToFrac d))

What if you don’t know the type of a C function you want to call until you run your program (e.g., JIT compilation). You can’t use foreign import ccall because you don’t know the function type statically. In this case, you can use the Haskell binding for libffi, a Portable Foreign Function Interface Library.

import System.Posix.DynamicLinker
import Foreign.C
import Foreign.Ptr
import Foreign.LibFFI
 
sin2 :: Double -> IO Double
sin2 d = do
    sin <- dlsym Default "sin"
    ret <- callFFI sin retCDouble [argCDouble (realToFrac d)]
    return $ realToFrac ret

Now you don’t need to declare it using foreign import ccall. You can just pass the return type and the list of argument types to callFFI function.

So far so good, but there is one problem with this approach. sin2 is no longer a pure function. The return type must be IO Double because calling callFFI function requires IO monad. If you call a impure C function with side effects, this is okay though.

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