使用Inline-C将结构从C编组到Haskell

时间:2019-01-26 02:09:04

标签: c haskell ffi inline-c

我正试图通过内联C将以下结构类型编组为C和Haskell:

//defined in wayland-server-core.h
struct wl_listener {
  struct wl_list link;
  wl_notify_func_t notify;
};

//such that:

typedef void (*wl_notify_func_t)(struct wl_listener *listener, void *data);

根据inline-C的文档:

  

inline-c还可以处理用户定义的结构和枚举,只要它们是Storable的实例,并且您可以使用上下文将它们定义为inline-c。

在这里,我尝试精确地做到这一点:

-- In some module:
data C'WlListener -- Our (opaque) struct type in Haskell

initializeMyCtx = C.context $ C.baseCtx <> C.funCtx <> mempty {
  C.ctxTypesTable = Data.Map.fromList [
  -- ...
  ,  (C.Struct "wl_listener", [t|C'WlListener|])
  -- ...
  ]
}

-- In a different module:
initializeMyCtx
C.include "<wayland-server.h>"
C.include "<wayland-server-core.h>"

-- | We make C'WlListener an instance of Storable so we can conveniently
-- | pass it from C to Haskell and back via inline-C.
instance Storable C'WlListener where
  sizeOf _    = fromIntegral $ [C.pure| int { sizeof(struct wl_listener) }|]
  alignment _ = fromIntegral $ [C.pure| int { alignof(struct wl_listener) }|]
  peek        = error "peek not implemented for C'WlListener"
  poke _ _    = error "poke not implemented for C'WlListener"

现在,当我尝试在Haskell中使用此功能

-- In a third module:
someIOFunc :: IO ()
someIOFunc = do
  -- Initialize an empty struct (which intializes its members to 0 by default) to pass around from Haskell
  myListener <- [C.exp| struct wl_listener { struct wl_listener listener }|]
  -- ...

我收到以下错误:

    • Unacceptable result type in foreign declaration:
        ‘C'WlListener’ cannot be marshalled in a foreign call
    • When checking declaration:
        foreign import ccall safe "inline_c_McWayFace_2" inline_c_ffi_6989586621679102285
          :: IO C'WlListener
   |
71 |   myListener <- [C.exp| struct wl_listener { struct wl_listener listener }|]
   |                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

0 个答案:

没有答案