【问题标题】:How to run Haskell on GraalVM?如何在 GraalVM 上运行 Haskell?
【发布时间】:2019-06-20 07:54:15
【问题描述】:

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

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

【问题讨论】:

  • "GraalVM 提供了一个全面的生态系统,支持大量语言(Java 和其他基于 JVM 的语言、JavaScript、Ruby、Python、R 和 C/C++ 以及其他基于 LLVM 的语言) " github.com/llvm-hs 可能是一个起点。
  • @chepner 这似乎不相关。如果您想实际与 LLVM 交互,请使用 llvm-hs。 OP 希望将 Haskell 编译为 LLVM 并使用 GraalVM 的备用 lli 运行它。
  • @HTNW 谢谢。可以肯定的是,某个地方确实有一个项目可以将 Haskell 编译为 LLVM;只是把上面的链接误认为是那个项目。我会尽力找到我想要的那个。
  • 叹息。我可能一直在考虑stephendiehl.com/llvm,它不是 Haskell-to-LLVM 编译器。
  • @chepner Erm... GHC 是 Haskell->LLVM 编译器?

标签: haskell graalvm


【解决方案1】:

这不是一个完整的答案,但大部分都是这样。这不是复杂:

Haskell 运行时只是一个可以在 GHC 安装中找到的库。在我的 Mac 上,它位于 $PREFIX/lib/ghc-$VERSION/rts 中,其中 $PREFIX 是 GHC 的安装前缀(例如 //usr/usr/local 等——编译器可执行文件应该是 $PREFIX/bin/ghc)。您需要使用其中一个共享库(对我来说,它们被称为.dylibs)。但是,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将它编译成bitcode,用ghcllvm-link将Haskell代码编译成一个大的.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 尝试使用RTLD_NOW 一次一个地处理dlopen 它们,它尝试并未能严格解析符号。它需要使用RTLD_LAZY。这在 GraalVM 中应该是一个很容易解决的问题。

【讨论】:

    【解决方案2】:

    感谢 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。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-08-04
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多