C and Haskell sitting in a tree...

A few days ago I thougth I’d take a look at calling C functions from haskell. I wrote up the following set of files:


    int foo(int i);


    foo(int i)
        return i * i;


    module Main where
    import Foreign.C.Types
    main = do
        r <- foo 2
        putStrLn $ show r
    foreign import ccall safe "foo.h foo" foo :: CInt -> IO CInt

Compiling the C file was of course no problem:

% gcc -c foo.c

The haskell file offered some resistance:

% ghc -c Foo.hs
Foo.hs:9:8: parse error on input `import'

It took me a round on haskell-cafe before I found out that ghc needs to be told to use the foreign function interface, -ffi or -fffi:

% ghc -c -fffi Foo.hs

Linking is a snap after that:

% ghc -o foo foo.o Foo.o
% ./foo

It’s also possible to build and link it all in one go:

% ghc --make -fffi -o foo foo.c Foo.hs

Now, that’s pretty nice, however it’d be even nicer to use cabal to do the building. At the same time I decided to put c2hs to use. It seemed to be a lot easier than having to create the import statements manually. I ended up with the following:


    #ifndef _FOO_H_
    int foo(int);


    #include "foo.h"
    foo(int i)
        return i * i;

I couldn’t get cabal to accept Foo.chs as the file containing the Main module in my project. So I ended up putting all the relevant code in Foo and then have a dummy Main.


    module Foo where
    #include "foo.h"
    import Foreign.C.Types
    main = do
        r <- {# call foo #} 2
        putStrLn $ show r

Here’s the dummy Main.


    module Main where
    import qualified Foo
    main = Foo.main

The cabal file is rather straight forward. It took me a round on haskell-cafe to find out how to let the compiler know that I need the foreign function interface without putting compiler directives in the source file.


name: cnh
version: 0.1
build-depends: base

executable: cnh
main-is: Main.hs
hs-source-dirs: src
include-dirs: csrc
c-sources: csrc/foo.c
extensions: ForeignFunctionInterface
other-modules: Foo

Nothing special is needed in the Setup.hs:

    #! /usr/bin/env runhaskell

    import Distribution.Simple
    main = defaultMain

Make it executable and you can build in two easy steps:

% ./Setup.hs configure && ./Setup.hs build


That would be “.hsc” not “.chs”. Maybe that was the problem…


Possibly, though I doubt it. Please report back once you’ve tried it out yourself :-)


excellent, thank you

Leave a comment