2011-12-31 18 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:

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

和Test_stub.c:

#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 

然後,我創建一個CPP文件main.cpp中:

#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功能應該已經在通過-lTest添加libTest.so定義。參數我不覺得,我應該鏈接的文件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運行時(特別是它的垃圾收集器)。 – 2011-12-31 19:27:38

+1

「$ g ++ -I/usr/lib/ghc-7.0.3/include -L。-lTest main.cpp」如果你把鏈接器標誌放在命令行的最後,它可能會起作用嗎? – 2011-12-31 19:58:24

+0

@Daniel:這是我第二次看到有人建議在最後加上鍊接器標誌,並且第一次似乎也解決了這個問題。爲什麼?我認爲旗幟的位置並不重要? – Xeo 2011-12-31 20:28:22

回答

9

可能比使用g ++是讓GHC摔跤容易做的工作,

GHC的main.cpp -o hithere -L。 -lTest -lstdC++

按照你的方式創建共享庫後爲我完成了這項工作。我用7.2.2和7.0.2測試了它們,都在這裏工作。

+2

haskell接口是一個較大項目的一個模塊,我不想用ghc編譯整個C++項目。 – Heinzi 2011-12-31 21:17:57

+0

這很有道理。你可以嘗試捕獲必要的鏈接器標誌,讓ghc以足夠高的冗長度編譯示例並將stderr重定向到一個文件。不過,它會給你一個相當長的待鏈接項目列表。 – 2011-12-31 21:30:21

+1

我知道它使用你的解決方案。當我將參數-v傳遞給ghc時,它將在命令行中輸出使用的鏈接器參數。 – Heinzi 2011-12-31 21:33:24

相關問題