8

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

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

4

2 回答 2

7

这不是一个完整的答案,但它是大部分的方式。它并不太复杂:

Haskell 运行时只是一个可以在 GHC 安装中找到的库。在我的 Mac 上,它位于 中, GHC 的安装前缀在$PREFIX/lib/ghc-$VERSION/rts哪里(例如、、等——编译器可执行文件应该是)。您需要使用其中一个共享库(对我来说,它们被称为s)。但是,Haskell 运行时和编译的 Haskell 代码都不包含. GHC 生成一个存根 C 文件:$PREFIX//usr/usr/local$PREFIX/bin/ghc.dylibmain

#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指的是main用 Haskell 编写的动作,hs_main指的是 RTS 中的符号。您需要将其编译为 bitcode clang,使用 编译 Haskell 代码ghcllvm-link将它们合并成一个大.bc文件,然后将其提供给 GraalVM 的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

但是,这不起作用,因为库具有相互依赖关系。base,主要用 Haskell 编写,需要 RTS。RTS 挂钩base以与 Haskell 进行通信(例如有异常)。GraalVM 一次尝试dlopen一个RTLD_NOW,它尝试并未能严格解析符号。它需要使用RTLD_LAZY. 这应该是 GraalVM 中一个容易解决的问题。

于 2019-06-20T15:54:04.760 回答
4

感谢 HTNW 提供有关如何生成所需位码的指示。我可以提供更多关于 GraalVM 方面需要什么的信息。

首先,对于循环依赖的问题,单独的 RTLD_LAZY 不起作用,因为它仅适用于未解析的函数,而不适用于未解析的变量(您可以通过尝试 dlopen libHSrts 和 libHSbase 的简单 C 程序验证这一点)。但是有一个非常简单的解决方法:只需生成一个链接到两者的空共享对象(gcc -shared libHSrts-.so libHSbase-.so)。然后这个共享对象可以被 GraalVM dlopen-ed。

不幸的是,它仍然不起作用,GraalVM 似乎在 Haskell rts 的某个地方遇到了段错误。一个潜在的问题是 GC,我们可能在 GraalVM 中弄乱了堆栈,导致 GC 无法正常工作。

一个有趣的尝试是将所有内容(包括 rts 和库)编译为位码。这将使调试这个问题更容易,没有任何本地管理的边界。GC 仍然是一个问题,因为在 GraalVM 上,堆栈可能看起来与原生的非常不同。但也许我们甚至可以修补 GC,只使用普通的 Java GC。

于 2019-07-25T11:42:42.873 回答