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 .dylibs). 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.