从C ++代码调用Haskell

我目前正在用C ++编写一个应用程序,发现它的一些function会更好的写在Haskell中。 我看过从C代码调用Haskell的说明,但是可以用C ++做同样的事情吗?

编辑:澄清,我正在寻找的是一种方法来编译Haskell代码到外部库,g ++可以链接从C ++的对象代码。

更新:我已经为其他人感兴趣的(下面我不会忘记)举出一个工作的例子。

编辑:你也应该看到Tomer的答案在下面。 我在这里的回答描述了正在发生的事情的理论,但是我可能有一些执行的细节不完整,而他的回答是一个完整的实例。

正如sclv所示,编译应该没有问题。 这很可能是连接C ++代码,在这里你将有一点难以获得所有需要的运行时库链接。问题是,Haskell程序需要链接到Haskell运行时库和C + +程序需要与C ++运行时库链接。 在Wiki页面中,您可以参考

 $ ghc -optc -O test.c Ao A_stub.o -o test 

编译C程序,实际上做了两步:将C程序编译成一个目标文件,然后将它链接在一起。 写出来,这将是类似的(可能不太正确,因为我不会说GHC):

 $ ghc -c -optc-O test.c -o test.o $ ghc test.o Ao A_stub.o -o test 

在编译C程序时,GHC就像GCC(和IIUC,function上 GCC)一样行事。 但是,在链接时,它与直接调用GCC的情况不同,因为它也奇迹般地包含了Haskell运行时库。 G ++对于C ++程序的工作原理是相同的 – 当它用作链接器时,它包含C ++运行时库。

所以,正如我所提到的,您需要以与这两个运行时库链接的方式进行编译。 如果以详细模式运行G ++来编译和链接程序,如下所示:

 $ g++ test.cpp -o test -v 

它会创build一个关于它在做什么的输出的长长的清单; 在最后将是一个输出行,它在链接(与collect2子程序)指示它链接到哪些库。 你可以把它和编译一个简单C程序的输出进行比较,看看C ++有什么不同。 在我的系统上,它添加了-lstdc++

因此,你应该能够编译和链接混合的Haskell / C ++程序,如下所示:

 $ ghc -c -XForeignFunctionInterface -O A.hs # compile Haskell object file. $ g++ -c -O test.cpp # compile C++ object file. $ ghc Ao A_stub.o test.o -lstdc++ -o test # link 

在那里,因为你已经指定了-lstdc++ ,它将包含C ++运行时库(假设-l是正确的GHC语法;你需要检查),因为你已经链接到ghc ,它将包括Haskell运行时图书馆。 这应该导致一个工作程序。

或者,你应该可以做一些类似于GHC的-v输出调查的东西,并找出Haskell运行时库(或库)链接到Haskell支持,然后添加该库时链接你的程序与C + +就像你已经为纯C ++程序做的那样。 (有关详细信息,请参阅Tomer的答案,因为这是他所做的。)

对于任何感兴趣的人来说,这是我终于开始工作的testing案例:


M.hs

 module Foo where foreign export ccall foo :: Int -> Int foo :: Int -> Int foo = floor . sqrt . fromIntegral 

TEST.CPP

 #include <iostream> #include "M_stub.h" int main(int argc, char *argv[]) { std::cout << "hello\n"; hs_init(&argc, &argv); std::cout << foo(500) << "\n"; hs_exit(); return 0; } 

我做了我的Windows机器上的编译和链接。 要运行的命令(按此顺序)是:

 >ghc -XForeignFunctionInterface -c M.hs >g++ -c test.cpp -I"c:\Program Files\Haskell Platform\2010.2.0.0\lib\include" >g++ -o test.exe -DDONT_WANT_WIN32_DLL_SUPPORT Mo M_stub.o test.o -L"C:\Program Files\Haskell Platform\2010.2.0.0\lib\haskell98-1.0.1.1" -L"C:\Program Files\Haskell Platform\2010.2.0.0\lib\random-1.0.0.2" -L"C:\Program Files\Haskell Platform\2010.2.0.0\lib\time-1.1.4" -L"C:\Program Files\Haskell Platform\2010.2.0.0\lib\process-1.0.1.3" -L"C:\Program Files\Haskell Platform\2010.2.0.0\lib\directory-1.0.1.1" -L"C:\Program Files\Haskell Platform\2010.2.0.0\lib\old-time-1.0.0.5" -L"C:\Program Files\Haskell Platform\2010.2.0.0\lib\old-locale-1.0.0.2" -L"C:\Program Files\Haskell Platform\2010.2.0.0\lib\filepath-1.1.0.4" -L"C:\Program Files\Haskell Platform\2010.2.0.0\lib\Win32-2.2.0.2" -L"C:\Program Files\Haskell Platform\2010.2.0.0\lib\bytestring-0.9.1.7" -L"C:\Program Files\Haskell Platform\2010.2.0.0\lib\array-0.3.0.1" -L"C:\Program Files\Haskell Platform\2010.2.0.0\lib\base-4.2.0.2" -L"C:\Program Files\Haskell Platform\2010.2.0.0\lib\integer-gmp-0.2.0.1" -L"C:\Program Files\Haskell Platform\2010.2.0.0\lib\ghc-prim-0.2.0.0" -L"C:\Program Files\Haskell Platform\2010.2.0.0\lib" -L"C:\Program Files\Haskell Platform\2010.2.0.0\lib/gcc-lib" -lHSrtsmain -lHShaskell98-1.0.1.1 -lHSrandom-1.0.0.2 -lHStime-1.1.4 -lHSprocess-1.0.1.3 -lHSdirectory-1.0.1.1 -lHSold-time-1.0.0.5 -lHSold-locale-1.0.0.2 -lHSfilepath-1.1.0.4 -lHSWin32-2.2.0.2 -luser32 -lgdi32 -lwinmm -ladvapi32 -lshell32 -lshfolder -lHSbytestring-0.9.1.7 -lHSarray-0.3.0.1 -lHSbase-4.2.0.2 -lwsock32 -luser32 -lshell32 -lHSinteger-gmp-0.2.0.1 -lHSghc-prim-0.2.0.0 -lHSrts -lm -lwsock32 -u _ghczmprim_GHCziTypes_Izh_static_info -u _ghczmprim_GHCziTypes_Czh_static_info -u _ghczmprim_GHCziTypes_Fzh_static_info -u _ghczmprim_GHCziTypes_Dzh_static_info -u _base_GHCziPtr_Ptr_static_info -u _base_GHCziWord_Wzh_static_info -u _base_GHCziInt_I8zh_static_info -u _base_GHCziInt_I16zh_static_info -u _base_GHCziInt_I32zh_static_info -u _base_GHCziInt_I64zh_static_info -u _base_GHCziWord_W8zh_static_info -u _base_GHCziWord_W16zh_static_info -u _base_GHCziWord_W32zh_static_info -u _base_GHCziWord_W64zh_static_info -u _base_GHCziStable_StablePtr_static_info -u _ghczmprim_GHCziTypes_Izh_con_info -u _ghczmprim_GHCziTypes_Czh_con_info -u _ghczmprim_GHCziTypes_Fzh_con_info -u _ghczmprim_GHCziTypes_Dzh_con_info -u _base_GHCziPtr_Ptr_con_info -u _base_GHCziPtr_FunPtr_con_info -u _base_GHCziStable_StablePtr_con_info -u _ghczmprim_GHCziBool_False_closure -u _ghczmprim_GHCziBool_True_closure -u _base_GHCziPack_unpackCString_closure -u _base_GHCziIOziException_stackOverflow_closure -u _base_GHCziIOziException_heapOverflow_closure -u _base_ControlziExceptionziBase_nonTermination_closure -u _base_GHCziIOziException_blockedIndefinitelyOnMVar_closure -u _base_GHCziIOziException_blockedIndefinitelyOnSTM_closure -u _base_ControlziExceptionziBase_nestedAtomically_closure -u _base_GHCziWeak_runFinalizzerBatch_closure -u _base_GHCziTopHandler_runIO_closure -u _base_GHCziTopHandler_runNonIO_closure -u _base_GHCziConc_ensureIOManagerIsRunning_closure -u _base_GHCziConc_runSparks_closure -u _base_GHCziConc_runHandlers_closure -lHSffi 

最后一个g ++命令的长参数列表来自运行

 >ghc M.hs -v 

然后复制命令“*** Linker:”(需要删除一些第一个参数)。


结果:

 >test hello 22 

这是关于这个主题的教程:

https://github.com/jarrett/cpphs

它涵盖了从C ++调用Haskell并从Haskell调用C。

既然你可以从C调用Haskell,那么没有理由不能从C ++调用它。 另一方面,从Haskell调用C ++要困难得多,通常需要一个C封装器。

编辑以展开。 说明是错误的不完整。 他们是一个维基页面。 直接查看GHC手册: http : //www.haskell.org/ghc/docs/6.12.2/html/users_guide/ffi-ghc.html

这里描述了如何导出函数,以及如何使用你自己的main函数。 注意它说“其他语言,说C”。 它说这是因为你可以从任何语言(和编译器),可以调用你导出的香草C函数,并且HsFFI.h提供。 这是语言不可知的,编译器是不可知的。 它所需要的只是能够使用C ++编译器(如g ++)提供的标准调用约定来调用C函数。