10
votes

Good (your local time of day), everyone.

I went through Real World Haskell's chapter on the Foreign Function Interface, and did some follow-up reading here. I'm now experimenting with binding to C functions, and I'd like some clarification on some things.

The following is fairly clear:

foreign import ccall unsafe "math.h sin" c_sin :: CDouble -> CDouble

I can load this and code that uses it in ghci, and everything is fine. It even loads in the embedded ghci in emacs's Haskell mode. I find this great for testing. math is a system library so this is straight-forward.

Now an example from Real World Haskell:

foreign import ccall unsafe "pcre.h pcre_compile" c_pcre_compile :: ...

I've left out the rest of the function signature on purpose. Now, I can't load this in Haskell mode. All the examples I've seen say this must be done:

ghci -lpcre

Which I do, and get instant confirmation that things are loading properly:

GHCi, version 7.6.2: 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 (dynamic) /usr/lib/gcc/x86_64-unknown-linux-gnu/4.7.2/../../../../lib/libpcre.so ... done
final link ... done

I can then load my binding code and test away, but...

_Question 1_ Can I load non-system libraries from within ghci, like pcre? This would allow me to test within emacs.

Moving on. Things get more complicated when I try to write bindings to my own C code.

foreign import ccall unsafe "myprint.h myprint" c_myprint :: CString -> IO ()

Admittedly a rather pointless function. It takes a ByteString from Haskell and prints it with C. Here is a simple test file:

{-# LANGUAGE ForeignFunctionInterface #-}
-- printTest.hs

import Foreign
import Foreign.C.Types
import Foreign.C.String

import qualified Data.ByteString.Char8 as B

---

foreign import ccall unsafe "myprint.h myprint" c_myprint :: CString -> IO ()

---

main = B.useAsCString (B.pack "Tempura is great!") c_myprint

I have been able to compile this by doing:

ghc --make myprint.c printTest.hs

And get an executable, but I haven't been able to load it in ghci at all. This severely lags the testing process.

_Question 2_ What do I have to do to load Haskell code in ghci that binds to my C code? None of the major sources of FFI information had anything to say about this. No amount of fiddling with ghci -L could get it to work.

Please and thanks for any help you can offer.

1
Q2, you must compile myprint.c as a library if you want it to load in ghci. This is c compiler/ os dependent.Jonke
Along these lines (gcc -c -fPIC foo.c -o foo.o and then gcc -shared -Wl,-soname,libfoo.so.1 -o libfoo.so.1.0.1 foo.o) or something like thatJonke

1 Answers

11
votes

ghci will load any library so long as it's valid for your architecture and can be located on some path. On windows, pathnames with spaces used to cause problems, I don't know if they still do.

To load your own code in ghci, you need to first compile it, then tell ghci to load the output of that:

mybox$ gcc -c myprint.c
mybox$ ghci Myprint.hs myprint.o

*Main> main
Loading package array-0.4.0.1 ... linking ... done.
Loading package deepseq-1.3.0.1 ... linking ... done.
Loading package bytestring-0.10.0.2 ... linking ... done.
Tempura is great!
*Main>

You could also compile the C files into a library and load that into ghci, but for just one file using an object file is quite convenient. If you want to create a library, a command like @Jonke suggested should work. On my system (OSX),

mybox$ gcc -shared -fPIC myprint.c -o libmyprint.dylib
mybox$ ghci -L. -lmyprint Foo.hs

On my system it also works to just use the library filepath as an argument, but I don't know if that's portable.