如何在GraalVM上运行Haskell?

时间:2019-06-20 07:54:15

标签: haskell graalvm

我试图让Haskell在GraalVM上运行,但无法包含运行时环境。在Rust中,只需为Rust标准库指定正确的路径即可,如here所述。

Haskell是否有同样简单的解决方案? 甚至有可能吗?

2 个答案:

答案 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。