2011-12-31 28 views
17

Tôi muốn xây dựng một thư viện động có chứa hàm haskell. Tôi làm việc trên Linux và muốn gọi thư viện động này từ mã C++.Xây dựng thư viện động với haskell và sử dụng nó từ C++

tôi sử dụng ví dụ tại http://wiki.python.org/moin/PythonVsHaskell và có những file sau:

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(); 
} 

Bây giờ tôi biên dịch file này cho một người năng động thư viện:

$ 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 ... 

Điều này tạo ra trong số những thứ khác file Test_stub.h:

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

và 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 

Sau đó, tôi tạo ra một main.cpp tập tin cpp:

#include "Test_stub.h" 

#include <iostream> 

using namespace std; 

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

và muốn biên dịch và liên kết nó. Nhưng khi tôi gọi g ++, nó nói:

$ 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 

Vì vậy, tôi đã thêm các tập tin Test_stub.o vào dòng lệnh (mặc dù tôi nghĩ chức năng hsfun nên đã được quy định tại libTest.so được bổ sung thông qua -lTest . thông số tôi không nghĩ rằng, tôi nên liên kết file Test_stub.o vào thực thi bởi vì tôi muốn sử dụng liên kết động), nhưng điều này cũng không làm việc:

$ 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 

tôi có phải liên kết các Test_stub .o? Nếu đúng thì tại sao? Và tôi nên chuyển đối số nào cho trình liên kết?

+0

Tôi không biết chi tiết; nhưng bạn chắc chắn cần phải liên kết thời gian chạy Haskell quá (đặc biệt là bộ thu gom rác của nó). –

+1

"$ g ++ -I/usr/lib/ghc-7.0.3/include -L. -lTest main.cpp" có lẽ nó hoạt động nếu bạn đặt cờ liên kết ở cuối dòng lệnh? –

+0

@Daniel: Đó là lần thứ hai tôi thấy một người nào đó đề xuất đặt cờ liên kết ở cuối và lần đầu tiên dường như giải quyết vấn đề. Tại sao vậy? Tôi nghĩ vị trí của những lá cờ không quan trọng? – Xeo

Trả lời

9

lẽ dễ dàng hơn vật lộn với g ++ là để cho GHC làm công việc,

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

đã thực hiện công việc cho tôi sau khi tạo lib được chia sẻ theo cách bạn đã làm. Tôi đã thử nghiệm nó với 7.2.2 và 7.0.2, cả hai đều làm việc ở đây.

+2

Giao diện haskell là một mô-đun của một dự án lớn hơn và tôi không muốn biên dịch toàn bộ dự án C++ bằng ghc. – Heinzi

+0

Điều đó có ý nghĩa. Bạn có thể thử chụp cờ liên kết cần thiết bằng cách ghc biên dịch ví dụ với độ dài đủ cao và chuyển hướng stderr tới một tệp.Tuy nhiên, nó sẽ cung cấp cho bạn một danh sách khá dài các mục được liên kết. –

+1

Tôi đã làm cho nó hoạt động bằng cách sử dụng giải pháp của bạn. Khi tôi chuyển tham số -v đến ghc, nó sẽ in các thông số liên kết được sử dụng trên dòng lệnh. – Heinzi

Các vấn đề liên quan