Haskell interface with c

I thought it would be nice to create midori plugins with haskell, but it seems almost impossible. The problem is exporting haskell functions via ffi, since the ghc compiler uses a huge number of -u switches.

. Has anyone seen that haskell was used in a similar context without replacing gcc with ghc? If so, how did it happen and what hoops did they go through?

Edit: some examples were requested, so here:

export.hs

{-# LANGUAGE ForeignFunctionInterface #-} module Export where import Foreign.C import Foreign.C.Types foo :: IO Int foo = return 2 foreign export ccall foo :: IO Int 

test.c (ifdefs snipped)

 #include <stdio.h> #include "HsFFI.h" #include "export_stub.h" extern void __stginit_Export(void); int main(int argc, char **argv) { int i; hs_init(&argc, &argv); hs_add_root(__stginit_Export); i = foo(); printf("%d\n", i); hs_exit(); return 0; } 

Compiling with ghc --make -no-hs-main export.hs test.c creates a.out which works. Ghc uses the following command to communicate:

collect2 --build-id --eh-frame-hdr -m elf_i386 --hash-style=both -dynamic-linker /lib/ld-linux.so.2 -o a.out -z relro -u ghczmprim_GHCziTypes_Izh_static_info -u ghczmprim_GHCziTypes_Czh_static_info -u ghczmprim_GHCziTypes_Fzh_static_info -u ghczmprim_GHCziTypes_Dzh_static_info -u base_GHCziPtr_Ptr_static_info -u base_GHCziWord_Wzh_static_info -u base_GHCziInt_I8zh_static_info -u base_GHCziInt_I16zh_static_info -u base_GHCziInt_I32zh_static_info -u base_GHCziInt_I64zh_static_info -u base_GHCziWord_W8zh_static_info -u base_GHCziWord_W16zh_static_info -u base_GHCziWord_W32zh_static_info -u base_GHCziWord_W64zh_static_info -u base_GHCziStable_StablePtr_static_info -u ghczmprim_GHCziTypes_Izh_con_info -u ghczmprim_GHCziTypes_Czh_con_info -u ghczmprim_GHCziTypes_Fzh_con_info -u ghczmprim_GHCziTypes_Dzh_con_info -u base_GHCziPtr_Ptr_con_info -u base_GHCziPtr_FunPtr_con_info -u base_GHCziStable_StablePtr_con_info -u ghczmprim_GHCziBool_False_closure -u ghczmprim_GHCziBool_True_closure -u base_GHCziPack_unpackCString_closure -u base_GHCziIOziException_stackOverflow_closure -u base_GHCziIOziException_heapOverflow_closure -u base_ControlziExceptionziBase_nonTermination_closure -u base_GHCziIOziException_blockedIndefinitelyOnMVar_closure -u base_GHCziIOziException_blockedIndefinitelyOnSTM_closure -u base_ControlziExceptionziBase_nestedAtomically_closure -u base_GHCziWeak_runFinalizzerBatch_closure -u base_GHCziTopHandler_runIO_closure -u base_GHCziTopHandler_runNonIO_closure -u base_GHCziConc_ensureIOManagerIsRunning_closure -u base_GHCziConc_runSparks_closure -u base_GHCziConc_runHandlers_closure /usr/lib/gcc/i486-linux-gnu/4.4.3/../../../../lib/crt1.o /usr/lib/gcc/i486-linux-gnu/4.4.3/../../../../lib/crti.o /usr/lib/gcc/i486-linux-gnu/4.4.3/crtbegin.o -L/usr/lib/ghc-6.12.1/base-4.2.0.0 -L/usr/lib/ghc-6.12.1/integer-gmp-0.2.0.0 -L/usr/lib/ghc-6.12.1/ghc-prim-0.2.0.0 -L/usr/lib/ghc-6.12.1 -L/usr/lib/gcc/i486-linux-gnu/4.4.3 -L/usr/lib/gcc/i486-linux-gnu/4.4.3 -L/usr/lib/gcc/i486-linux-gnu/4.4.3/../../../../lib -L/lib/../lib -L/usr/lib/../lib -L/usr/lib/gcc/i486-linux-gnu/4.4.3/../../.. -L/usr/lib/i486-linux-gnu export.o export_stub.o test.o -lHSbase-4.2.0.0 -lHSinteger-gmp-0.2.0.0 -lgmp -lHSghc-prim-0.2.0.0 -lHSrts -lm -lffi -lrt -ldl -lgcc --as-needed -lgcc_s --no-as-needed -lc -lgcc --as-needed -lgcc_s --no-as-needed /usr/lib/gcc/i486-linux-gnu/4.4.3/crtend.o /usr/lib/gcc/i486-linux-gnu/4.4.3/../../../../lib/crtn.o

Removing the -u switches (leaving only -l, -L and some additional flags) from the previous command does not compile and does not return (and about 50 or more lines)

 /usr/lib/ghc-6.12.1/libHSrts.a(RtsAPI.o): In function `rts_mkFunPtr': (.text+0x5a9): undefined reference to `base_GHCziPtr_FunPtr_con_info' /usr/lib/ghc-6.12.1/libHSrts.a(RtsAPI.o): In function `rts_mkString': (.text+0x60f): undefined reference to `base_GHCziPack_unpackCString_closure' 
+4
source share
2 answers

I was able to solve the problem.

I use the following files:

main.c

 #include <stdio.h> #include "lib_stub.h" int main(int argc, char **argv) { puts("foo"); printf("%d\n", hsfun(5)); return 0; } 

lib.hs

 {-# LANGUAGE ForeignFunctionInterface #-} module Test where import Foreign.C.Types hsfun :: CInt -> IO CInt hsfun x = do putStrLn "Hello from haskell" return (42 * x) foreign export ccall hsfun :: CInt -> IO CInt 

module_init.c

 #include <HsFFI.h> extern void __stginit_Test(void); static void library_init(void) __attribute__((constructor)); static void library_init(void) { static char *argv[] = { "libtest.so", 0 }, **argv_ = argv; static int argc = 1; hs_init(&argc, &argv_); hs_add_root(__stginit_Test); } static void library_exit(void) __attribute__((destructor)); static void library_exit(void) { hs_exit(); } 

I am compiling the library with ghc --make -shared -dynamic -fPIC -o libtest.so lib.hs module_init.c -lHSrts-ghc6.12.1 -optl-Wl,-rpath,/usr/lib/ghc-6.12.1/ -L/usr/lib/ghc-6.12.1 and executable with gcc -c main.c -I/usr/lib/ghc-6.12.1/include -L. -ltest -Wl,-rpath=$PWD gcc -c main.c -I/usr/lib/ghc-6.12.1/include -L. -ltest -Wl,-rpath=$PWD

An important role is that the library is shared and has the rts library linked as well, which does not come by default. Rpath does this so that it can run without LD_LIBRARY_PATH.

http://weblog.haskell.cz/pivnik/building-a-shared-library-in-haskell/

http://www.well-typed.com/blog/30

+2
source

This is probably the related part of the guide:

8.2. Using FFI with GHC

See, in particular, 8.2.1.2. You can create a library written in Haskell and called from C code. Then you only need to write the glue code in C to enable the plugin or something else. But I didn’t do it myself, please wait for more experienced foreign export users to respond.

+1
source

All Articles