不能让C2HS与"外国"指针一起工作

Joh*_*iss 5 haskell ffi c2hs

一般信息

我目前正在试验Haskell的C-> Haskell(C2HS)接口生成器.在第一次,这真是太棒了,我extern C在几个小时内连接了一个相当复杂的C++库(使用一个小型的包装器).(之前我从未做过任何FFI.)

只有一个问题:如何释放在C/C++库中分配的内存?我{#pointer ... foreign #}C2HS文档中找到了,它看起来与我追求的完全一样.由于我的C-wrapper将C++库转换为具有参考透明度和功能接口的库,Haskell Storage Manager应该能够为我做好工作:-).不幸的是,我无法让这个工作.为了更好地解释我的问题,我在GitHub上设置了一个小的演示项目,它具有与C/C++库+包装器相同的属性,但没有开销.如您所见,该库与pure unsafeFFI 一起使用是完全安全的.

演示项目

在GitHub上,我创建了一个小型演示项目,其组织如下:

C库

C库非常简单和无用:你可以传递一个整数,你可以[0..n]从库中获取尽可能多的整数(当前).记住:图书馆没用,只是一个演示.界面也很简单:函数LTIData lti_new_data(int n)将(在传递一个整数之后)返回一些包含C库分配数据的不透明对象.图书馆还拥有两个存取函数int lti_element_count(LTIData data)int lti_get_element(LTIData data, int n),前者将返回元素的数量,而后者将返回元素n.嗯,最后但并非最不重要的,该库的用户应该使用它后释放不透明的LTIData使用void lti_free_data(LTIData data).

低级Haskell绑定

使用C2HS设置低级Haskell绑定,您可以在其中找到它

高级Haskell API

为了好玩,我还使用低级API绑定和使用高级API的简单驱动程序设置了一种高级Haskell API.使用驱动程序和例如valgrind,可以很容易地看到泄漏的内存(对于库执行分配的每个参数;可以轻松观察如下):p_1, p_2, ..., p_n\sum_{i = 1..n} 1 + p_i

$ valgrind dist/build/TestHsLTI/TestHsLTI 100             2>&1 | grep -e allocs -e frees
==22647==   total heap usage: 184 allocs, 74 frees, 148,119 bytes allocated

$ valgrind dist/build/TestHsLTI/TestHsLTI 100 100         2>&1 | grep -e allocs -e frees
==22651==   total heap usage: 292 allocs, 80 frees, 181,799 bytes allocated

$ valgrind dist/build/TestHsLTI/TestHsLTI 100 100 100     2>&1 | grep -e allocs -e frees
==22655==   total heap usage: 400 allocs, 86 frees, 215,479 bytes allocated

$ valgrind dist/build/TestHsLTI/TestHsLTI 100 100 100 100 2>&1 | grep -e allocs -e frees
==22659==   total heap usage: 508 allocs, 92 frees, 249,159 bytes allocated
Run Code Online (Sandbox Code Playgroud)

目前的演示状态

您只需键入即可克隆,编译和运行项目git clone https://github.com/weissi/c2hs-experiments.git && cd c2hs-experiments && cabal configure && cabal build && dist/build/TestHsLTI/TestHsLTI

那又是什么问题呢?

问题是项目只使用Foreign.Ptr而不是Foreign.ForeignPtr使用C2HS的"托管"版本{#pointer ... foreign #},我无法使用它.在演示项目中,我还添加了一个.chs文件,试图使用这些外部指针,但它不起作用:-(.我努力尝试但我没有任何成功.

还有一件事我也不明白:如何告诉GHC使用C2HS如何释放图书馆的数据.演示项目的库提供了一个void lti_free_data(LTIData data)应该被调用来释放内存的函数.但是GHC猜不出来了!?!如果GHC使用常规a free(),则不会释放所有内存:-(.

Joh*_*iss 3

问题已解决:我发现这个文件在互联网上做了类似的事情并且能够解决它:-)。

它所需要的只是一些样板编组代码:

foreign import ccall "lib_to_interface.h &lti_free_data"
  ltiFreeDataPtr :: FunPtr (Ptr (LTIDataHs) -> IO ())


newObjectHandle :: Ptr LTIDataHs -> IO LTIDataHs
newObjectHandle p = do
  fp <- newForeignPtr ltiFreeDataPtr p
  return $ LTIDataHs fp
Run Code Online (Sandbox Code Playgroud)

这是该文件的最终托管 ( ForeignPtr) 版本.chs