This is not a complete answer, but it's most of the way there. It is not too complicated:
The Haskell runtime is just a library that you can find in your GHC installation. On my Mac it's in $PREFIX/lib/ghc-$VERSION/rts
, where $PREFIX
is the installation prefix of GHC (e.g. /
, /usr
, /usr/local
, etc.—the compiler executable should be $PREFIX/bin/ghc
). You need to use one of the shared libraries (for me, they're called .dylib
s). However, neither the Haskell runtime nor the compiled Haskell code contains main
. GHC generates a stub C file:
#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);
}
where ZCMain_main_closure
refers to the main
action written in Haskell and hs_main
refers to a symbol from the RTS. You will need to compile this to bitcode with clang
, compile the Haskell code with ghc
, llvm-link
them into one big .bc
, then give it to GraalVM's lli
. With the above in c_main.c
, place an example program into Main.hs
:
main = putStrLn "Hello, World!"
Compile and link:
$ 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
Now, in a perfect world, the following would work:
$ 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
However, this doesn't work because the libraries have mutual dependencies. base
, written mostly in Haskell, needs the RTS. The RTS hooks into base
to communicate with Haskell (e.g. with exceptions). GraalVM tries to dlopen
them one at a time with RTLD_NOW
, which tries and fails to strictly resolve the symbols. It would need to use RTLD_LAZY
. This should be an easily fixable issue in GraalVM.