haskell - 无法使用 "foreign"指针使 C2HS 工作

标签 haskell ffi c2hs

一般信息

我目前正在试验 Haskell 的 C->Haskell (C2HS) 接口(interface)生成器。乍一看,这真是太棒了,我在短短几个小时内就连接了一个相当复杂的 C++ 库(使用小型 extern C -wrapper)。 (而且我以前从未做过任何 FFI。)

只有一个问题:如何释放 C/C++ 库中分配的内存?我找到了{#pointer ... foreign #}C2HS documentation这看起来就像我所追求的。由于我的 C-wrapper 将 C++ 库转换为具有引用透明性和功能接口(interface)的库,因此 Haskell 存储管理器应该能够为我完成艰苦的工作:-)。不幸的是,我无法让这个工作。为了更好地解释我的问题,我设置了一个小的 demo project on GitHub它具有与 C/C++ 库+包装器相同的属性,但没有开销。如您所见,该库与 pure unsafe 一起使用是完全安全的。 FFI。

演示项目

在 GitHub 上,我创建了一个 small demo project组织如下:

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) .

  • Experiment/C2HSBinding/Foreign/lib_to_interface.h
  • Experiment/C2HSBinding/Foreign/lib_to_interface.c

  • 低级 Haskell 绑定(bind)

    低级 Haskell 绑定(bind)是使用 C2HS 设置的,您可以在
  • Experiment/C2HSBinding/Foreign/HsLTI.chs

  • 高级 Haskell API

    为了好玩,我还设置了一个 high-level Haskell API使用低级 API 绑定(bind)和 simple driver program使用高级 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
    

    演示的当前状态

    您应该能够克隆、编译和运行 project只需键入 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 file trying to use these foreign pointers但它不起作用:-(。我非常努力地尝试了它,但我没有任何成功。

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

    最佳答案

    问题已解决:我找到了 this file doing something similar在互联网上并能够解决它:-)。

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

    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
    

    这是final managed ( ForeignPtr ) verion of the .chs file .

    关于haskell - 无法使用 "foreign"指针使 C2HS 工作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12070800/

    相关文章:

    haskell - 你如何构图_Just with the at lens

    parsing - Haskell 中的 AST 和解析

    haskell - 在 GADT 数据构造函数中通过类型族指定依赖类型

    c++ - 从多个 C/C++ 线程调用 Haskell

    python - 有没有一种简单的方法可以使用 Common Lisp 中的 Python 库?

    haskell - Websockets 上 GHCJS 代码最有效的有线格式

    haskell - 使用 FFI 的可执行文件是否需要 GHC 选项?

    c - Haskell FFi 与 c2hs : Better out-marshalling of structs

    c - C 枚举的大型 c2hs 推断大小

    haskell - 使用 c2hs 和 cabal 构建