While cabal has support for including a C and C++ libraries in a Haskell package, there are a few bugs. First, if you have data (rather than a function) defined in b.o
that is used in a.o
, and list the C-sources: a.c, b.c
, then cabal will be unable to find the data. This is documented in #12152. A workaround when using cabal is to reorder the C-sources
list to be C-sources: b.c, a.c
. This may not work when using stack, because stack always links the C-sources
alphabetically, regardless of the order in which you list them.
Another issues is that you must surround any C++ code in header (.h) files with #ifdef __cplusplus
guards. This is because GHC doesn't understand C++ code in header files. You can still write C++ code in header files, but you must surround it with guards.
ccall
refers to the calling convention; currently ccall
and stdcall
(Pascal convention) are supported. The unsafe
keyword is optional; this reduces overhead for simple functions but may cause deadlocks if the foreign function blocks indefinitely or has insufficient permission to execute1.
For performance reasons, or due to the existence of mature C libraries, you may want to call C code from a Haskell program. Here is a simple example of how you can pass data to a C library and get an answer back.
foo.c:
#include <inttypes.h>
int32_t foo(int32_t a) {
return a+1;
}
Foo.hs:
import Data.Int
main :: IO ()
main = print =<< hFoo 41
foreign import ccall unsafe "foo" hFoo :: Int32 -> IO Int32
The unsafe
keyword generates a more efficient call than 'safe', but requires that the C code never makes a callback to the Haskell system. Since foo
is completely in C and will never call Haskell, we can use unsafe
.
We also need to instruct cabal to compile and link in C source.
foo.cabal:
name: foo
version: 0.0.0.1
build-type: Simple
extra-source-files: *.c
cabal-version: >= 1.10
executable foo
default-language: Haskell2010
main-is: Foo.hs
C-sources: foo.c
build-depends: base
Then you can run:
> cabal configure
> cabal build foo
> ./dist/build/foo/foo
42
It is very common for C functions to accept pointers to other functions as arguments. Most popular example is setting an action to be executed when a button is clicked in some GUI toolkit library. It is possible to pass Haskell functions as C callbacks.
To call this C function:
void event_callback_add (Object *obj, Object_Event_Cb func, const void *data)
we first import it to Haskell code:
foreign import ccall "header.h event_callback_add"
callbackAdd :: Ptr () -> FunPtr Callback -> Ptr () -> IO ()
Now looking at how Object_Event_Cb
is defined in C header, define what Callback
is in Haskell:
type Callback = Ptr () -> Ptr () -> IO ()
Finally, create a special function that would wrap Haskell function of type Callback
into a pointer FunPtr Callback
:
foreign import ccall "wrapper"
mkCallback :: Callback -> IO (FunPtr Callback)
Now we can register callback with C code:
cbPtr <- mkCallback $ \objPtr dataPtr -> do
-- callback code
return ()
callbackAdd cpPtr
It is important to free allocated FunPtr
once you unregister the callback:
freeHaskellFunPtr cbPtr
foo
in some object file, and defines the symbol hFoo
which can be called with Haskell code. -}