一般情報
私は現在、C->Haskell (C2HS) Interface Generator for Haskell を試しています。一見しただけで、それは素晴らしかったです。かなり複雑な C++ ライブラリを (小さなextern C
-wrapper を使用して) わずか 2 時間でインターフェイスしました。(そして、私は以前にFFIをしたことがありません。)
1 つだけ問題がありました。C/C++ ライブラリに割り当てられたメモリを解放するにはどうすればよいでしょうか。私{#pointer ... foreign #}
はC2HSのドキュメントで見つけましたが、それは私が求めているものとまったく同じように見えます. 私の C-wrapper は C++ ライブラリを機能的なインターフェースを備えた参照透過性を備えたライブラリに変換するので、Haskell Storage Manager は私のために大変な作業を行うことができるはずです :-)。残念ながら、私はこれを機能させることができませんでした。私の問題をよりよく説明するために、C/C++ ライブラリ + ラッパーと同じプロパティを持つがオーバーヘッドのない小さなデモ プロジェクトを GitHubにセットアップしました。ご覧のとおり、このライブラリはpure unsafe
FFI で使用しても完全に安全です。
デモプロジェクト
GitHub で、次のような構成の小さなデモ プロジェクトを作成しました。
C ライブラリ
C ライブラリは非常に単純で役に立ちません: 整数を渡すことができ[0..n]
、ライブラリから整数 (現在のところ) を返すことができます。覚えておいてください: ライブラリは役に立たず、ただのデモです。インターフェイスも非常に単純です。この関数LTIData lti_new_data(int n)
は (整数を渡した後)、C ライブラリの割り当てられたデータを含むある種の不透明なオブジェクトを返します。ライブラリには 2 つのアクセサ関数int lti_element_count(LTIData data)
ともint lti_get_element(LTIData data, int n)
あり、前者は要素の数を返し、後者は要素を返しますn
。ああ、最後になりましたが、ライブラリのユーザーは、ライブラリを使用した後、 を使用して不透明を解放する必要がありLTIData
ますvoid lti_free_data(LTIData data)
。
低レベルの Haskell バインディング
低レベルの Haskell Binding は、C2HS を使用してセットアップされます。
高レベル Haskell API
また、お楽しみとして、低レベル API バインディングを使用する一種の高レベル Haskell APIと、高レベル 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
デモの現状
次のように入力するだけで、プロジェクトを複製、コンパイル、実行できるはずです。git clone https://github.com/weissi/c2hs-experiments.git && cd c2hs-experiments && cabal configure && cabal build && dist/build/TestHsLTI/TestHsLTI
では、問題は何ですか?
問題は、プロジェクトがC2HS を使用Foreign.Ptr
する「管理された」バージョンのみを使用し、それを機能させることができないことです。デモ プロジェクトでは、これらの外部ポインタを使用しようとするファイルも追加しましたが、機能しません :-(。一生懸命試しましたが、成功しませんでした。Foreign.ForeignPtr
{#pointer ... foreign #}
.chs
また、私が理解できないことが 1 つあります。それは、C2HS を使用して GHC にライブラリのデータを解放する方法を伝える方法です。デモ プロジェクトのライブラリにはvoid lti_free_data(LTIData data)
、メモリを解放するために呼び出される関数が用意されています。しかし、GHCはそれを推測することはできません!?! GHC が通常の a を使用する場合free()
、すべてのメモリが解放されるわけではありません :-(.