Haskell C FFI: accessing static data structures
John L. suggested the CApiFFI
extension, which does exactly what I want: allows you to import values rather than locations. Now:
{-# LANGUAGE CApiFFI #-}newtype {-# CTYPE "foo.h" "struct foo_struct" #-} Foo = Foo { getFoo :: (Ptr Foo) }foreign import capi "foo.h value FOO_GEORGE" fooGeorgePtr :: Ptr afooGeorge = Foo fooGeorgePtr
Another advantage is that this works regardless of whether FOO_GEORGE
is a C variable or a preprocessor macro. The C API I’m working with uses both, and different implementations of the same API that I link to do so differently, so being independent of that is great.
However, there’s a stumbling block: CApiFFI
doesn’t work with ghci! The problem is known, and it isn’t slated to be fixed until GHC 8.0.1 (when I first wrote this, it was due for 7.10, and then was pushed forward). I have a very hacky workaround. CApiFFI
works by generating a C library on the fly, compiling and linking the Haskell program against it. It removes the library when done; the ghci problem seems to be that the .so file is gone by the time ghci needs to link against it. I just grab the .c file during compilation before it gets deleted, then compile it myself and tell ghci to load it. Since I don’t change that portion of the program very often, it works out for me well enough.
My method for catching the temporary .c file is to start ghci in Emacs compilation-mode
, with (setq compilation-auto-jump-to-first-error t)
. Emacs sees the error and loads the .c file into a buffer before GHC gets around to deleting it — by the time I see it the file is gone, but I’ve got the contents in a buffer.
Update: ghci -fobject-code Foo
works, but can only see the names exported from the module.