2011-12-31 11 views
17

私は、haskell関数を含む動的ライブラリを構築したいと思います。私はLinux上で動作し、この動的ライブラリをC++コードから呼びたいと思っています。動的ライブラリをhaskellでビルドし、C++から使用する

私はhttp://wiki.python.org/moin/PythonVsHaskellで例を使用して、次のファイルを持っている:

Test.hs:

{-# LANGUAGE ForeignFunctionInterface #-} 
module Test where 

import Foreign.C.Types 

hsfun :: CInt -> IO CInt 
hsfun x = do 
    putStrLn "Hello World" 
    return (42 + x) 

foreign export ccall 
    hsfun :: CInt -> IO CInt 

をmodule_init.c:

#define CAT(a,b) XCAT(a,b) 
#define XCAT(a,b) a ## b 
#define STR(a) XSTR(a) 
#define XSTR(a) #a 

#include <HsFFI.h> 

extern void CAT (__stginit_, MODULE) (void); 

static void library_init (void) __attribute__ ((constructor)); 
static void 
library_init (void) 
{ 
    /* This seems to be a no-op, but it makes the GHCRTS envvar work. */ 
    static char *argv[] = { STR (MODULE) ".so", 0 }, **argv_ = argv; 
    static int argc = 1; 

    hs_init (&argc, &argv_); 
    hs_add_root (CAT (__stginit_, MODULE)); 
} 

static void library_exit (void) __attribute__ ((destructor)); 
static void 
library_exit (void) 
{ 
    hs_exit(); 
} 

今、私はこれがダイナミックにファイルをコンパイル図書館:

$ ghc -dynamic -shared -fPIC -optc '-DMODULE=Test' Test.hs module_init.c -o libTest.so 
[1 of 1] Compiling Test    (Test.hs, Test.o) 
Linking libTest.so ... 

これは、他のもののファイルTest_stub.hの間で作成されます。その後、私はcppのファイルmain.cppを作成

#define IN_STG_CODE 0 
#include "Rts.h" 
#include "Stg.h" 
#ifdef __cplusplus 
extern "C" { 
#endif 

extern StgClosure Test_zdfhsfunzua165_closure; 
HsInt32 hsfun(HsInt32 a1) 
{ 
Capability *cap; 
HaskellObj ret; 
HsInt32 cret; 
cap = rts_lock(); 
cap=rts_evalIO(cap,rts_apply(cap,(HaskellObj)runIO_closure,rts_apply(cap,&Test_zdfhsfunzua165_closure,rts_mkInt32(cap,a1))) ,&ret); 
rts_checkSchedStatus("hsfun",cap); 
cret=rts_getInt32(ret); 
rts_unlock(cap); 
return cret; 
} 
static void stginit_export_Test_zdfhsfunzua165() __attribute__((constructor)); 
static void stginit_export_Test_zdfhsfunzua165() 
{getStablePtr((StgPtr) &Test_zdfhsfunzua165_closure);} 
#ifdef __cplusplus 
} 
#endif 

#include "HsFFI.h" 
#ifdef __cplusplus 
extern "C" { 
#endif 
extern HsInt32 hsfun(HsInt32 a1); 
#ifdef __cplusplus 
} 
#endif 

とTest_stub.c

#include "Test_stub.h" 

#include <iostream> 

using namespace std; 

int main() 
{ 
    cout << hsfun(5); 
} 

をし、それをコンパイルしてリンクしたい。しかし、私はg ++の呼び出したとき、それは言う:

$ g++ -I/usr/lib/ghc-7.0.3/include -L. -lTest main.cpp 
/tmp/ccFP2AuB.o: In function `main': 
main.cpp:(.text+0xa): undefined reference to `hsfun' 
collect2: ld gab 1 als Ende-Status zurück 

だから私は、コマンドラインにTest_stub.oファイルを追加しました(私はhsfun機能がすでにlibTest.soで定義されるべきだと思うが、追加された-lTest経由。パラメータは、私は私が)動的リンクを使用したいのでTest_stub.oは、実行可能ファイルにファイルをリンクする必要があり、ないと思いますが、これも動作しません:

$ g++ -I/usr/lib/ghc-7.0.3/include -L. -lTest main.cpp Test_stub.o 
Test_stub.o: In function `hsfun': 
Test_stub.c:(.text+0x9): undefined reference to `rts_lock' 
Test_stub.c:(.text+0x16): undefined reference to `rts_mkInt32' 
Test_stub.c:(.text+0x1d): undefined reference to `Test_zdfhsfunzua165_closure' 
Test_stub.c:(.text+0x28): undefined reference to `rts_apply' 
Test_stub.c:(.text+0x2f): undefined reference to `base_GHCziTopHandler_runIO_closure' 
Test_stub.c:(.text+0x3a): undefined reference to `rts_apply' 
Test_stub.c:(.text+0x4a): undefined reference to `rts_evalIO' 
Test_stub.c:(.text+0x5c): undefined reference to `rts_checkSchedStatus' 
Test_stub.c:(.text+0x66): undefined reference to `rts_getInt32' 
Test_stub.c:(.text+0x70): undefined reference to `rts_unlock' 
Test_stub.o: In function `stginit_export_Test_zdfhsfunzua165': 
Test_stub.c:(.text.startup+0x3): undefined reference to `Test_zdfhsfunzua165_closure' 
Test_stub.c:(.text.startup+0x8): undefined reference to `getStablePtr' 
collect2: ld gab 1 als Ende-Status zurück 

私はTest_stubをリンクする必要がありますか.o?はいの場合、なぜですか?そして、私はリンカにどの引数を渡すべきですか?おそらく

+0

詳細はわかりません。 Haskellランタイム(特にそのガベージコレクタ)もリンクする必要があります。 –

+1

"$ g ++ -I/usr/lib/ghc-7.0.3/include -L。-lTest main.cpp"リンカフラグをコマンドラインの最後に置いた場合はおそらく動作しますか? –

+0

@Daniel:誰かがリンカフラッグを最後に付けることを提案しているのを見るのは2回目です。初めて問題を解決するように思えました。それはなぜですか?私はフラグの位置は問題ではないと思った? – Xeo

答えて

9

グラムの++と格闘よりも簡単にはGHCは仕事、

GHC main.cppに-o hithere -Lを行いせています。 -lTest -lstdC++

共有ライブラリを作成した後に私の仕事をしてくれました。私は7.2.2と7.0.2でテストしましたが、どちらもここで働いていました。

+2

haskellインターフェイスは大きなプロジェクトのモジュールの1つで、ghcを使ってC++プロジェクト全体をコンパイルしたくありません。 – Heinzi

+0

それは理にかなっています。 ghcに十分な冗長性を持たせて例をコンパイルし、stderrをファイルにリダイレクトさせることで、必要なリンカフラグを取得することができます。しかし、それはリンクされているアイテムのかなり長いリストを提供します。 –

+1

私はあなたのソリューションを使用してそれを稼働させました。パラメータ-vをghcに渡すと、使用されたリンカパラメータがコマンドラインに出力されます。 – Heinzi