It’s JHC’s turn

It’s been a while since I wrote here.

Today I sat down to try out the relatively new JHC – Haskell compiler created by John Meacham.

After some trivial steps I got it compiled & installed in ~/localopt/jhc-0.7.5/. It worked out of the box.

This compiler has a very interesting property: it compiles Haskell code to Ansi C. It can be processed afterwards by any way you want: cross-compiled by gcc or made into shared library. I found the latter to be pretty simple.

The plan is as follows:

  1. Create Haskell module and use “foreign export” in the file.
  2. Compile it with -fffi and dump C code (-dc).
  3. Use dumped code and a prepared template to compile shared library

Simple and clean.

First let’s create a simple Haskell module with single function “adder” and empty “main” function.

import Foreign
import Foreign.C

foreign export ccall "adder" adder :: CInt -> CInt -> CInt
adder x y = x + y

main :: IO ()
main = return ()

We will also need library initialization code. Let’s put it into some known directory, like ~/localopt/jhc-0.7.5/shared/library_init_template.c.

#define CAT(a,b) XCAT(a,b)
#define XCAT(a,b) a ## b
#define STR(a) XSTR(a)
#define XSTR(a) #a

extern void CAT (__stginit_, MODULE) (void);

static void library_init (void) __attribute__ ((constructor));
static void
library_init (void)
{
    static char *argv[] = { STR (MODULE) ".so", 0 }, **argv_ = argv;
    static int argc = 1;

    hs_init(&argc,&argv_);
    if (jhc_setjmp(&jhc_uncaught))
        jhc_error("Uncaught Exception");

}

static void library_exit (void) __attribute__ ((destructor));
static void
library_exit (void)
{
    hs_exit ();
}

Now we can compile the Haskell code:
jhc -fffi -fjgc adder_ffi.hs -o adder.bin -dc
The code will be written to file “adder.bin_code.c”. We will use it along with the library template above.


touch adder_lib.c
cat adder.bin_code.c >> adder_lib.c
cat ~/localopt/jhc-0.7.5/shared/library_init_template.c >> adder_lib.c

Now we can compile it to the shared library. The only thing we need to remember are two macros: -DMODULE=ADDER sets module name in our template, and -D_JHC_STANDALONE=0 disables default main in adder_lib.c. There are also a few default options as used by JHC.

gcc -DMODULE=ADDER -D_JHC_STANDALONE=0 -fPIC -shared -Wl,-soname,libadder.so.1 '-std=gnu99' -D_GNU_SOURCE '-falign-functions=4' -ffast-math -Wextra -Wall -Wno-unused-parameter -o libadder.so.1 adder_lib.c -DNDEBUG -O3 '-D_JHC_GC=_JHC_GC_JGC'

Now a simple test program:

#include

int adder(int x2,int x3);

int main()
{
    printf("%d\n", adder(3,4));
    return 0;
}

gcc -Wl,-rpath=`pwd` libadder.so.1 test_adder.c -o test_adder
./test_adder
7

It works!

We can wrap all needed commands into simple script (this is zsh syntax, but bash should be similar or even the same):

jhc-shared-lib () {
    jhc -fffi -fjgc $1.hs -o $1.bin -dc

    rm -f $1_lib.c
    touch $1_lib.c
    cat $1.bin_code.c >> $1_lib.c
    cat ~/localopt/jhc-0.7.5/shared/library_init_template.c >> $1_lib.c

    gcc -D_GNU_SOURCE -DMODULE=ADDER -D_JHC_STANDALONE=0 \
        -fPIC -shared -Wl,-soname,lib$1.so.1 \
        '-std=gnu99' '-falign-functions=4' -ffast-math \
        -Wextra -Wall -Wno-unused-parameter \
        -o lib$1.so.1 $1_lib.c -DNDEBUG -O3 '-D_JHC_GC=_JHC_GC_JGC'
}

Invoke it like this:
jhc-shared-lib adder

JHC looks like a lot of fun. Even if it doesn’t support all possible extensions to Haskell it does play really well with C compilers.

Advertisements

~ by Tener on 28/07/2010.

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

 
%d bloggers like this: