Haskellコードを動的ライブラリにしてCから使用する その1
それほど難しくはないのですが、その分細かい手順を忘れやすいので。
まずは、動的ライブラリ(DLL)の作成まで。 必要な手順は、
となります。 (他にもやり方はあるかもしれません)
今回の環境。
- OS: Windows 8.1
- CPU: Core 2 Quad Q9550 2.83GHz
- Haskellコンパイラ: ghc 7.4.1
Haskell側の記述です。公開したい関数を次のように指定します。Cの方の型を扱うため特別なimportも必要です。
-- ExprEval.hs import Foreign.C.Types import Foreign.C.String foreign export ccall cexprI :: CWString -> IO CInt foreign export ccall cexprF :: CWString -> IO CFloat foreign export ccall cexprCheck :: CWString -> IO CInt
次はこれらを呼び出すC側の記述です。 DLLのインタフェイスとして実際に呼び出す関数はこちらです。 ラッパーとして作成して扱いやすくします。
// cexpr.c #include <HsFFI.h> #ifdef __GLASGOW_HASKELL__ #include "expr_stub.h" extern void __stginit_ExprEval(void); #endif int exprCheck(const wchar_t *str) { return cexprCheck((HsPtr)str); } float exprF(const wchar_t *str) { return cexprF((HsPtr)str); } int exprI(const wchar_t *str) { return cexprI((HsPtr)str); } HsBool hslibInit(int argc, char *argv[]) { hs_init(&argc, &argv); return HS_BOOL_TRUE; } void hslibEnd() { hs_exit(); }
あとはこれらをまとめてghcでコンパイルです。DLLと静的ライブラリが作成されます。 静的ライブラリの拡張子が.aとなるかもしれません。
ghc -shared cexpr.c ExprEval.hs -o ExprEval.dll ren ExprEval.dll.a ExprEval.dll.a
それから、作成したDLLはHaskellのランタイムを含んでいます。1Mバイトほどサイズが大きくなります。 ghcのオプションに-dynamicをつけると含まなくなり、小さく作れます。
DLLを呼び出す側にもう少しお作法がありますので、次回にまた。