答案 0 :(得分:4)
这不是一个完整的答案,但这是大部分的方法。 也不复杂:
Haskell运行时只是您可以在GHC安装中找到的库。在我的Mac上,它位于$PREFIX/lib/ghc-$VERSION/rts
中,其中$PREFIX
是GHC的安装前缀(例如/
,/usr
,/usr/local
等-编译器可执行文件应是$PREFIX/bin/ghc
)。您需要使用其中一个共享库(对我来说,它们称为.dylib
)。但是,Haskell运行时或已编译的Haskell代码均不包含main
。 GHC生成存根C文件:
#include "Rts.h"
extern StgClosure ZCMain_main_closure;
int main(int argc, char *argv[])
{
RtsConfig __conf = defaultRtsConfig;
__conf.rts_opts_enabled = RtsOptsSafeOnly;
__conf.rts_opts_suggestions = true;
__conf.rts_hs_main = true;
return hs_main(argc,argv,&ZCMain_main_closure,__conf);
}
其中ZCMain_main_closure
表示用Haskell编写的main
操作,hs_main
表示RTS中的符号。您将需要将其编译为使用clang
进行位编码,使用ghc
编译Haskell代码,将llvm-link
编译为一个大.bc
,然后将其提供给GraalVM的{{1} }。将以上内容放在lli
中,然后将示例程序放入c_main.c
:
Main.hs
编译并链接:
main = putStrLn "Hello, World!"
现在,在一个完美的世界中,以下方法将起作用:
$ clang -emit-llvm -I/usr/local/lib/ghc-8.6.5/include -c c_main.c
# Change -I path as needed
$ ghc -fllvm -keep-llvm-files -S Main.hs
$ llvm-link Main.ll c_main.bc -o prog.bc
但是,这不起作用,因为这些库具有相互依赖性。 $ lli --lib /usr/local/lib/ghc-8.6.5/rts/libHSrts-ghc8.6.5.dylib \
--lib /usr/local/lib/ghc-8.6.5/base-4.12.0.0/libHSbase-4.12.0.0-ghc8.6.5.dylib \
prog.bc
# Maybe you need more of the base libraries
# It's kind of hard to test because it doesn't work, anyway
主要用Haskell编写,需要RTS。 RTS挂接到base
中以与Haskell通信(例如,例外)。 GraalVM尝试使用base
一次dlopen
一次,这会尝试并且无法严格解析符号。它需要使用RTLD_NOW
。这应该是GraalVM中容易解决的问题。
答案 1 :(得分:1)
感谢HTNW提供有关如何产生所需位码的指针。我可以提供更多有关GraalVM方面需要的信息。
首先,对于循环依赖性问题,仅RTLD_LAZY无效,因为它仅适用于未解析的函数,不适用于未解析的变量(您可以通过尝试dlopen libHSrts和libHSbase的简单C程序来验证这一点) 。但是,有一个非常简单的解决方法:只产生一个链接到两者的空共享对象(gcc -shared libHSrts- .so libHSbase- .so)。然后可以通过GraalVM对该共享对象进行开放。
不幸的是,它仍然不起作用,GraalVM似乎在Haskell rts内的某个地方遇到了段错误。一个潜在的问题是GC,我们可能在GraalVM中将堆栈弄乱了很多,从而导致GC无法正常工作。
一个有趣的尝试是将所有内容(包括rts和库)编译为位码。这将使调试此问题变得更加容易,并且没有任何本机管理的边界。 GC仍然是个问题,因为在GraalVM上,堆栈看起来可能与本机非常不同。但是也许我们甚至可以修补GC,然后使用普通的Java GC。