Haskell Bindings to C – c2hs

September 22, 2009

When making hsXenCtrl bindings I was thrilled to learn and use hsc2hs – I considered it all that was needed for sugar on top of the FFI. However, the recent Kernel Modules work has opened my eyes to various limitations of hsc2hs and forced me to learn c2hs – which is superior so I’ll go though a simple-stupid tutorial here.

This is intended as a starter companion to the official documentation – not a substitute!  Read the docs, they are quite understandable!

The C Code

Lets consider some basic C code:

struct test {
 int a;
};

struct test *getTheStruct();

struct test t;

struct test *getTheStruct()
{
 return &t;
}

#define add_one(x) (x + 1)

While there are the normal issues of calling functions and accessing structure fields, it’s no coincidence that this code embodies the two issues I came across when using c2hs.  First, it has a macro, for which there is no automatic FFI generation, and secondly it has structures that aren’t typedef’ed to a single keyword.  We’ll see how to handle both those along with the rest of our simple chs code.

The .chs File

We now write a test.chs file that will interface with the code defined in our c header.

{-# LANGUAGE ForeignFunctionInterface #-}

import Foreign.C.Types
import Foreign.Ptr
import Foreign.Storable

#include "test.h"

The boiler plate shouldn’t be surprising – the only new aspect is the inclusion of the header file that defines the types and functions to which we must bind.

Now lets define a pointer type.  Unfortunately this code doesn’t use any typedefs and c2hs can’t parse “struct foo” as a single C type identifier.  To fix this we use a section of C code, which will appear in the file “test.chs.h” once we run c2hs:

#c
typedef struct test test_t;
#endc

We may now define the pointer types using “test_t” instead of “struct test”

{#pointer *test_t as Test#}

This is amazingly simple – it translates into “type Test = Ptr ()”.  You can add the keyword “newtype” at the end to obtain type enforcement if you so desire.

To access fields in this structure you could define a whole storable instance, using c2hs keywords ‘sizeof’, ‘get’, and ‘put’ the whole way – but we didn’t create a ‘newtype’ on which a typeclass instance can be defined.  All we need are a pair of get and set functions – but you can see how to use these and thus create any Storable instance you want.

getA :: Test -> IO Int
getA t = {#get test_t->a#} t >>= return . fromIntegral

setA :: Test -> Int -> IO ()
setA t i = {#set test_t->a#} t (fromIntegral i)

As you can see, use the {#get …} and {#set …} hooks along with the C type (“test_t”) and C field name(s) (“a”)  to create a function that will access the types appropriately.  Now we need to handle the damned macro.  There exists no {#macro …} hook, and function hooks translate directly to “foreign import …” so the first step is using another C section to make a function wrap the macro:

#c
int add_one_(int x)
{
 return (add_one(x));
}
#endc

This doesn’t warrant any more discussion, so lets move onto the function calls!  The function hook is hands-down ugly, but powerful.  First you tell it the C function you’re calling (add_one_).  Then specify the name of the Haskell function; hat (“^”) means convert the C name to camel case (addOne), or you can specify any name you desire (ex: “hs_add_one”).  After the naming is handled then you provide a list of arguments in curry braces – {arg1, arg2, …, argn} – then an arrow and a result Type.  Each argument and return value is a Haskell type and enclosed in a back tick and single quote, such as `Int’.  Before and after each argument you can provide in and out marshalling functions – this is where all the power of c2hs is and is also well stated in the documentation so I won’t be repeating it here – just notice that I marshal CInt to and from Int via “fromIntegral” and no marshalling is needed for the pointer (“Test”) so we use identity (“id”).

{#fun add_one_ as ^
 {fromIntegral `Int' } -> `Int' fromIntegral#}
{#fun get_the_struct as ^
 {} -> `Test' id#}

The remaining task is to define a simple ‘main’ function for testing purposes.

main = do
 s <- getTheStruct
 setA s 5
 a <- getA s
 b <- addOne a
 print a
 print b

Compile and Test

The files test.hs  test.chs.h are generated by c2hs:

c2hs test.chs

For purposes of running this test we can finish this easily:

mv test.chs.h test.chs.c
ghc --make test.hs test.chs.c
./test
5
6

C Bindings and Kernel Code

This is only the beginning - I'm using this with kernel headers and as such test.chs.h will be built using the kernel build system.  For this reason I need to manually modified the generated haskell FFI to use the "regparm3" calling convention or not use the c2hs function hooks ({#fun ...}).  Other than that, and an small gcc non-standard "flexability" that c2hs can't parse without minor correction, it seems c2hs is a great tool for kernel bindings and I hope to have a real (though simple) driver done soon!

About these ads

8 Responses to “Haskell Bindings to C – c2hs”

  1. Uzytkownik Says:

    Last time I used c2hs

    #c
    int function () {

    }
    #endc

    did not worked – at least for libraries (linking errors).

    • tommd Says:

      Uzytkownik:
      “Did not work” isn’t specific enough for me to help you. Since you said linking errors, I’m guessing “c2hs x.chs” worked and you executed something like:

      mv x.chs.h x.chs.c
      ghc –make x.hs x.chs.c -lSomeLib

      but perhaps you forget you need the x.chs.c file or the -l flag?

    • tommd Says:

      (replying here because there is no reply button for the deeper comment)

      But #c and #endc aren’t even functions and won’t appear in your haskell source. What command are you running? Are you complaining that cabal doesn’t run c2hs on .chs files automatically they way it runs chs2hs? That is a problem, but running c2hs manually isn’t that big a deal.

      • Uzytkownik Says:

        I mean that if I have:

        #c
        int function () {

        }
        #endc

        callFunction = {#call function#}

        then all compiles fine untill the linking phase when it complaining about undefined reference to ‘function’.

        I run simply runhaskell Setup.hs build and I have c2hs as tool in .cabal

  2. Sebastián Benítez Says:

    What’s the reason for also implementing the macro? Macros aren’t explorted in libraries, they are replaced by the processor with actual code.

    • tommd Says:

      In the kernel marcos and inlined functions often do hugely useful tasks that you don’t want to repeatedly type. In C, Haskell, or any other language, chances are high that if you find a commonly used expression in one then similar expressions will be needed in the other.

      Another way to look at it is implementing similarly named marcos and functions makes it easier to transition between the two systems as you have similar convenience functions.

  3. single seeds Says:

    Your method of explaining the whole thing in this post is truly
    fastidious, all be capable of easily be aware of it, Thanks a
    lot.


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

%d bloggers like this: