问题描述
我想建立一个包含haskell函数的动态库。我在linux上工作,想从C ++代码调用这个动态库。
我使用,并具有以下文件:
Test.hs:
{ - #LANGUAGE ForeignFunctionInterface# - }
模块测试其中
import Foreign.C.Types
hsfun :: CInt - > IO CInt
hsfun x = do
putStrLnHello World
return(42 + x)
外部导出ccall
hsfun :: CInt - ; IO CInt
module_init.c:
#define CAT(a,b)XCAT(a,b)
#define XCAT(a,b)a ## b
#define STR (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)
{
/ *这似乎是一个无操作,但它使GHCRTS envvar工作。 * /
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]编译测试(Test.hs,Test.o)
链接libTest.so ...
这会创建文件Test_stub.h:
#includeHsFFI.h
#ifdef __cplusplus
externC{
#endif
extern HsInt32 hsfun(HsInt32 a1);
#ifdef __cplusplus
}
#endif
和Test_stub。 c:
#define IN_STG_CODE 0
#includeRts.h
#include h
#ifdef __cplusplus
externC{
#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:
#includeTest_stub.h
#include< iostream>
using namespace std;
int main()
{
cout< hsfun(5);
}
并希望编译和链接。但是当我调用g ++,它说:
$ g ++ -I / usr / lib / ghc-7.0.3 / L. -lTest main.cpp
/tmp/ccFP2AuB.o:在函数`main'中:
main.cpp :(。text + 0xa):undefined对`hsfun'的引用
collect2:ld gab 1 als Ende-Statuszurü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:在函数`hsfun'中:
Test_stub.c :(。text + 0x9):未定义对`rts_lock'的引用
Test_stub.c (。text + 0x16):未定义引用`rts_mkInt32'
Test_stub.c :(。+ 0x1d):未定义的引用`Test_zdfhsfunzua165_closure'
Test_stub.c :(。未定义的引用`rts_apply'
Test_stub.c :(。text + 0x2f):未定义引用`base_GHCziTopHandler_runIO_closure'
Test_stub.c :( .text + 0x3a):未定义`rts_apply'引用
Test_stub.c :(。text + 0x4a):未定义的引用`rts_evalIO'
Test_stub.c :(。text + 0x5c):未定义的引用`rts_checkSchedStatus'
Test_stub.c :(。
test_stub.c :(。text + 0x70):未定义的引用`rts_unlock'
Test_stub.o:在函数`stginit_export_Test_zdfhsfunzua165'中:
Test_stub.c :( .text.startup + 0x3):未定义的引用`Test_zdfhsfunzua165_closure'
Test_stub.c :( .text.startup + 0x8):未定义引用`getStablePtr'
collect2:ld gab 1 als Ende-Statuszurück
我必须链接Test_stub.o吗?如果是,为什么?
解决方案可能比g ++更容易让ghc做工作, p>
在创建共享库之后为我完成了这项工作。我已经测试了它与7.2.2和7.0.2,都在这里工作。
I want to build a dynamic library containing haskell functions. I work on linux and want to call this dynamic library from C++ code.
I used the example at http://wiki.python.org/moin/PythonVsHaskell and have the following files:
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 (); }
Now I compile this files to a dynamic library:
$ 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 ...
This creates among other things the file Test_stub.h:
#include "HsFFI.h" #ifdef __cplusplus extern "C" { #endif extern HsInt32 hsfun(HsInt32 a1); #ifdef __cplusplus } #endif
and 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
Then I create a cpp file main.cpp:
#include "Test_stub.h" #include <iostream> using namespace std; int main() { cout << hsfun(5); }
and want to compile and link it. But when I call g++, it says:
$ 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
So I added the Test_stub.o file to the command line (although I think the hsfun function should already be defined in libTest.so which is added via the -lTest parameter. I don't think, I should link the Test_stub.o file into the executable because I want to use dynamic linking), but this also doesn't work:
$ 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
Do I have to link the Test_stub.o? If yes, why? And which arguments should I pass to the linker?
解决方案Probably easier than wrestling with g++ is letting ghc do the work,
did the job for me after creating the shared lib the way you did. I have tested it with 7.2.2 and 7.0.2, both worked here.
这篇关于使用haskell构建动态库并从C ++中使用它的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!