Haskell Language
外部関数インタフェース
サーチ…
構文
- foreign import ccall unsafe "foo" hFoo :: Int32 - > IO Int32 { - いくつかのオブジェクトファイルで
foo
という名前の関数をインポートし、Haskellコードで呼び出すことができるシンボルhFoo
を定義します。 - }
備考
cabalはCおよびC ++ライブラリをHaskellパッケージに含めることをサポートしていますが、いくつかのバグがあります。まず、 ao
で使用されるbo
で定義されたデータ(関数ではない)があり、 C-sources: ac, bc
をリストすると、cabalはデータを見つけることができません。これは#12152に記載されています。カバールを使用する場合の回避策は、 C-sources
リストをC-sources: bc, ac
C-sources
に並べ替えることC-sources: bc, ac
。スタックを使用すると、 C-sources
アルファベット順にリンクするので、スタックの使用順序に関係なく、スタックを使用すると機能しないことがあります。
別の問題は、ヘッダー(.h)ファイルのC ++コードを#ifdef __cplusplus
ガードで囲む必要があることです。これは、GHCがヘッダファイルのC ++コードを理解していないためです。ヘッダーファイルにC ++コードを書き込むことはできますが、ガードに囲む必要があります。
ccall
は呼び出し規約を指します。現在、 ccall
とstdcall
(Pascal convention)がサポートされています。 unsafe
キーワードはオプションです。これは、単純な機能のためのオーバーヘッドが減少しますが、外国の機能ブロックが無期限に、または実行するための十分な権限がある場合は、デッドロックを引き起こす可能性が1を 。
ハスケルからCを呼び出す
パフォーマンス上の理由から、または成熟したCライブラリの存在により、HaskellプログラムからCコードを呼び出すことができます。ここでは、データをCライブラリに渡して答えを返す簡単な例を示します。
foo.c:
#include <inttypes.h>
int32_t foo(int32_t a) {
return a+1;
}
Foo.hs:
import Data.Int
main :: IO ()
main = print =<< hFoo 41
foreign import ccall unsafe "foo" hFoo :: Int32 -> IO Int32
unsafe
キーワードは、「safe」よりも効率的な呼び出しを生成しますが、CコードがHaskellシステムへのコールバックを決して必要としません。 foo
は完全にC言語であり、決してHaskellを呼び出さないので、 unsafe
を使うことができます。
私たちはC言語でコンパイルしリンクするようカバールに指示する必要もあります。
foo.cabal:
name: foo
version: 0.0.0.1
build-type: Simple
extra-source-files: *.c
cabal-version: >= 1.10
executable foo
default-language: Haskell2010
main-is: Foo.hs
C-sources: foo.c
build-depends: base
次に、実行することができます:
> cabal configure
> cabal build foo
> ./dist/build/foo/foo
42
HaskellをCコードへのコールバックとして渡します。
C関数が他の関数へのポインタを引数として受け入れることは非常に一般的です。最も一般的な例は、GUIツールキットライブラリでボタンがクリックされたときに実行されるアクションを設定することです。 Haskell関数をCコールバックとして渡すことは可能です。
このC関数を呼び出すには:
void event_callback_add (Object *obj, Object_Event_Cb func, const void *data)
最初にそれをHaskellのコードにインポートします:
foreign import ccall "header.h event_callback_add"
callbackAdd :: Ptr () -> FunPtr Callback -> Ptr () -> IO ()
次に、CヘッダーでObject_Event_Cb
がどのように定義されているかを見て、HaskellのCallback
定義します。
type Callback = Ptr () -> Ptr () -> IO ()
最後に、 Callback
型のHaskell関数をポインタFunPtr Callback
Callback
にラップする特別な関数を作成します。
foreign import ccall "wrapper"
mkCallback :: Callback -> IO (FunPtr Callback)
コールバックをCコードで登録することができます:
cbPtr <- mkCallback $ \objPtr dataPtr -> do
-- callback code
return ()
callbackAdd cpPtr
コールバックの登録を解除すると、割り当てられたFunPtr
を解放することが重要です。
freeHaskellFunPtr cbPtr