GHCi doesn't work with FFI export declarations/shared libraries
ffi, ghci, haskell
Solution
You need to specify some more objects to link when invoking GHCi, because the C object `c.o` is particularly picky when it comes to linking order.
First, you need to add the `bytestring` package's object files. This is done by adding `-package bytestring` to the GHCi command line.
Then, you need to add the actual object file that defines `callMeFromC`. When `FFISo.hs` is compiled, it doesn't produce an object file that exports `callMeFromC`. It instead uses the GHC naming convention and exports `Main_zdfcallMeFromCzuak4_closure`, which actually is a static global variable pointing to the closure/"thunk" that contains the actual function definition and environment. This is so that you can't write something like this:
foregin export ccall foo :: IO ()
foo = undefined
...and have the runtime crash as soon as the program starts because the "function value" of `foo` can't be evaluated. The function definition is only inspected once the function is actually used.
GHC generates a stub file, which contains C code for calling the Haskell function from C. This file is called `FFISo_stub.c`, and is compiled into `FFISo_stub.o` for you. This object file exports the "C version" of `callMeFromC` that can be called directly. Feel free to inspect the generated code, it is quite interesting.
All in all, you need to use this command line when invoking GHCi:
ghci -package bytestring FFISo.o c.o FFISo_stub.o FFISo.hs
Problem
I have a problem regarding FFI in Haskell and the interactive mode of GHC. (Source is also available via a gist): FFISo.hs: ``` {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE ForeignFunctionInterface #-} module Main where import qualified Data.ByteString.Char8 as B foreign import ccall "callMeFromHaskell" callMeFromHaskell :: IO () foreign export ccall callMeFromC :: IO () callMeFromC :: IO () callMeFromC = B.putStrLn "callMeFromC" main :: IO () main = do B.putStrLn "main" callMeFromHaskell return () ``` c.c: ``` #include <stdio.h> void callMeFromC(void); void callMeFromHaskell(void) { printf("callMeFromHaskell\n"); callMeFromC(); } ``` Makefile: ``` GHC_OPT := -Wall -O2 -fno-warn-unused-do-bind all: ffiso test: ffiso ./$< ffiso: FFISo.hs c.c ghc --make $(GHC_OPT) $^ -o $@ clean: rm -rf *.hi *.o ffiso *_stub.* ghci0: ffiso echo main | ghci FFISo.hs ghci1: ffiso echo main | ghci FFISo.hs c.o ghci2: ffiso echo main | ghci FFISo.hs c.o FFISo.o ``` Compiling and linking works fine: ``` $ make test ghc --make -Wall -O2 -fno-warn-unused-do-bind FFISo.hs c.c -o ffiso [1 of 1] Compiling Main ( FFISo.hs, FFISo.o ) Linking ffiso ... ./ffiso main callMeFromHaskell callMeFromC ``` However, if I want to use GHCi, it fails with this message: ``` $ make ghci0 echo main | ghci FFISo.hs GHCi, version 7.4.1: http://www.haskell.org/ghc/ :? for help Loading package ghc-prim ... linking ... done. Loading package integer-gmp ... linking ... done. Loading package base ... linking ... done. Ok, modules loaded: Main. Prelude Main> Loading package bytestring-0.9.2.1 ... linking ... done. <interactive>: FFISo.o: unknown symbol `callMeFromHaskell' Prelude Main> Leaving GHCi. ``` Well, let's try giving GHCi the `c.o` objectfile. ``` $ make ghci1 echo main | ghci FFISo.hs c.o GHCi, version 7.4.1: http://www.haskell.org/ghc/ :? for help Loading package ghc-prim ... linking ... done. Loading package integer-gmp ... linking ... done. Loading package base ... linking ... done. Loading object (static) c.o ... done ghc: c.o: unknown symbol `callMeFromC' linking extra libraries/objects failed make: *** [ghci1] Error 1 final link ... ``` Oh okay... let's try with FFISo.o: ``` $ make ghci2 echo main | ghci FFISo.hs c.o FFISo.o GHCi, version 7.4.1: http://www.haskell.org/ghc/ :? for help Loading package ghc-prim ... linking ... done. Loading package integer-gmp ... linking ... done. Loading package base ... linking ... done. Loading object (static) c.o ... done Loading object (static) FFISo.o ... done ghc: FFISo.o: unknown symbol `bytestringzm0zi9zi2zi1_DataziByteStringziInternal_PS_con_info' linking extra libraries/objects failed make: *** [ghci2] Error 1 final link ... ``` And that's where I'm stuck. I tested it with two different environments with the same result: ``` $ # system 1 $ ghc --version The Glorious Glasgow Haskell Compilation System, version 7.4.1 $ uname -a Linux phenom 3.2.13-1-ARCH #1 SMP PREEMPT Sat Mar 24 09:10:39 CET 2012 x86_64 AMD Phenom(tm) II X6 1055T Processor AuthenticAMD GNU/Linux $ # system 2 $ ghc --version The Glorious Glasgow Haskell Compilation System, version 6.12.1 $ uname -a Linux hermann 2.6.32-22-generic-pae #36-Ubuntu SMP Thu Jun 3 23:14:23 UTC 2010 i686 GNU/Linux ```