[Haskell-cafe] [Haskell] Linker flags for foreign export.

Max Bolingbroke batterseapower at hotmail.com
Thu Mar 10 11:27:42 CET 2011


On 10 March 2011 04:04, Jason Dusek <jason.dusek at gmail.com> wrote:
>  I'm trying to hew relatively close to Duncan Coutts'
>  blog posting in working through this; so I have different
>  code and a new Makefile:

Starting with your code I've managed to make it work (OS X 10.6, GHC
7). The Makefile is:

"""
loadfoo: loadfoo.c
    gcc -arch i386 loadfoo.c -o loadfoo

libfoo.dynamic-dynamic.so: Foo.hs fooinit.c
    ghc -fPIC -c fooinit.c
    ghc --make -dynamic -fPIC -c Foo.hs
    ghc -shared -dynamic -o libfoo.dynamic-dynamic.so \
        Foo.o Foo_stub.o fooinit.o \
        -lHSrts_debug-ghc7.0.1.20101215

test: loadfoo libfoo.dynamic-dynamic.so
    ./loadfoo libfoo.dynamic-dynamic.so
"""

(I have to build loadfoo in 32-bit mode because GHC generates 32-bit
code on OS X). The fact that we supply the RTS to the GHC link line is
important because the shared library would not otherwise link against
any particular RTS - in the normal course of things, GHC only decides
on the RTS when linking the final executable.

I'm linking against the debug RTS there but it should work with the
normal one too - I just used the debug version to work out why I got a
bus error upon load..

.. and the reason was that your fooinit.c was buggy - that probably
account for the crashes you were seeing. The problem is that hs_init
takes a *pointer to* argc and argv, not argc and argv directly. You
supplied 0 for both of these so GHC died when it tried to dereference
them.

My new fooinit.c (that works) is as follows:

"""
#include "HsFFI.h"

extern void __stginit_Foo(void);
static void Foo_init (void) __attribute__ ((constructor));
void Foo_init (void) {
  char *arg1 = "fake-main";
  char *argv[1] = { arg1 };
  char **argv_p = argv;
  char ***pargv_p = &argv_p;
  int argc = sizeof(argv) / sizeof(char *);
  hs_init(&argc, pargv_p);
  hs_add_root(__stginit_Foo);
}
"""

(Apologies for the extreme ugliness, it's been so long since I wrote C
in anger the chain of initializers is the only way I could get this to
build without a GCC warning about casts between different pointer
types).

I tested it with this Foo.hs:

"""
{-# LANGUAGE ForeignFunctionInterface #-}
module Foo where

import Foreign.C

foreign export ccall foo    ::  CInt -> CInt

foo                         ::  CInt -> CInt
foo                          =  (+1)
"""

And a change to loadfoo.c that actually tries to calls foo:

"""
       printf("**** %s\n", "symbol lookup okay");
+      printf("%d\n", foo(1336));
     } else {
"""

(You need "int (*foo)(int) = dlsym(dl, "foo")" as well)

The output is 1337 as expected.

Cheers,
Max



More information about the Haskell-Cafe mailing list