FFI: c/c++ struct on stack as an argument or return value

Yuras Shumovich shumovichy at gmail.com
Fri Mar 14 18:00:09 UTC 2014

On Fri, 2014-03-14 at 09:08 -0400, Edward Kmett wrote:
> I spent some time hacking around on this from a library perspective when I
> had to interoperate with a bunch of Objective C on a 64-bit mac as many of
> the core library functions you need to FFI out to pass around pairs of Int32s
> as a struct small enough by the x64 ABI to get shoehorned into one
> register, and as I was programmatically cloning Objective C APIs via
> template haskell I couldn't use the usual clunky C shims.

Was it related to language-c-inline package?

> So if nothing else, you can at least take this as a vote of confidence that
> your idea isn't crazy. =)
> I'd also be happy to answer questions if you get stuck or need help.

Thank you, Edward

Since there is at least one person how is interested in, I'll start
asking questions. Please let me know when I become too noisy :)

For now I'm focused on desugaring phase. Right now

type Fn = CInt -> CInt -> IO ()
foreign import ccall "wrapper" f :: Fn -> IO (FunPtr Fn)

is desugared into

f :: Fn -> IO (FunPtr Fn)
f hsFunc = do
  sPtr <- newStablePtr hsFunc
  createAdjustor sPtr staticWrapper ...

Here staticWrapper -- address of C function. It will dereference the
sPtr, cast to StgClosure* and call with appropriate arguments. All the
arguments are primitive C types (int, char, pointer, etc), so it is easy
to convert them to corresponding haskell types via rts_mkInt, rts_mkChar

But I want to allow argument to be C structs.

data CStruct {
  i :: CInt,
  j :: CInt
type Fn = CStruct -> IO ()
foreign import ccall "wrapper" f :: Fn -> IO (FunPtr Fn)

Looks like it is impossible to instantiate CStruct from C function. Is
it true? Is it easy to add such functionality?

The only solution I see is to flatten CStruct before creating StablePtr:

f :: Fn -> IO (FunPtr Fn)
f hsFunc = do
  sPtr <- newStablePtr $ \i j -> hsFunc (CStruct i j)
  createAdjustor sPtr staticWrapper ...

Does it make sense? It will add performance overhead because of
additional indirection. Better ideas are welcome.


> -Edward
> On Fri, Mar 14, 2014 at 7:50 AM, Yuras Shumovich <shumovichy at gmail.com>wrote:
> >
> > Hi,
> >
> > Right now ghc's FFI doesn't support c/c++ structures.
> >
> > Whenever we have foreign function that accepts or returns struct by
> > value, we have to create wrapper that accepts or returns pointer to
> > struct. It is inconvenient, but actually not a big deal.
> >
> > But there is no easy workaround when you want to export haskell function
> > to use it with c/c++ API that requires structures to be passed by value
> > (Usually it is a callback in c/c++ API. You can't change it's signature,
> > and if it doesn't provide some kind of "void* userdata", then you are
> > stuck.)
> >
> > I'm interested in fixing that. I'm going to start with 'foreign import
> > "wrapper" ...' stuff.
> >
> > Calling conventions for passing c/c++ structures by value are pretty
> > tricky and platform/compiler specific. So initially I'll use libffi for
> > that (it will work when USE_LIBFFI_FOR_ADJUSTORS is defined, see
> > rts/Adjustor.c). It will allow me to explore design space without
> > bothering about low level implementation details. Later it could be
> > implemented for native (non-libffi) adjustors.
> >
> > Is anybody interested it that? I appreciate any comments/ideas.
> >
> > Right now I don't have clear design. It would be nice to support plain
> > haskell data types that are 1) not recursive, 2) has one constructor and
> > 3) contains only c/c++ types. But it doesn't work with c/c++ unions. Any
> > ideas are welcome.
> >
> > An example how to use libffi with structures:
> > http://www.atmark-techno.com/~yashi/libffi.html#Structures
> >
> > Thanks,
> > Yuras
> >
> >
> > _______________________________________________
> > ghc-devs mailing list
> > ghc-devs at haskell.org
> > http://www.haskell.org/mailman/listinfo/ghc-devs
> >

More information about the ghc-devs mailing list