Home - WebGHC/wasm-cross GitHub Wiki

Status

GHC cross compiler can compile most of the packages including ones with C code (like bytestring). For example jsaddle works fine, and it has a lot of dependecies including lens, aeson, attoparsec, etc.

The runtime kernel can run in single threaded mode, concurrency stuff like forkIO, MVars, threadDelay, etc work fine, though there is no parallelism.

There is support to do very minimal IO (it can print on the browser console, and communicate with jsaddle js code). The IO support is currently in experimental stage, and has been hand crafted to do a proof of concept implementation.

The size of wasm executable (containing RTS, libc and all the libraries statically linked) is above 15mb for simple hello world, and 27mb for jsaddle.

Since we know the jsaddle works and can do arbitrary JS code execution, in theory we should be able to run any ghcjs-dom based applications like reflex-dom.

Next tasks

Reduce the code size

This is currently the most critical issue we will have to fix. This has been captured in the below issues.

https://github.com/WebGHC/ghc/issues/13

https://github.com/WebGHC/jsaddle-wasm/issues/1

Currently I (@dfordivam) am trying a number of experiments here to better understand the problem and possible solutions. If you know llvm, or ghc code generation, then please get in touch.

Implement kernel execution environment for runtime

There is a need to create a proper "kernel" support for running the runtime in JavaScript, and interact with DOM.

  • Implement basic APIs for memory management, other system calls. In current implementation some of these APIs dont do what they are intended to do, so that need to be fixed.

  • Need to provide a unix like File system support, using the browsefs package.

  • The wasm executable and kernel code runs in a separate WebWorker thread (currently they run together in one thread, though that might change in next version). Whereas the jsaddle JavaScript code has to run in the main thread, as it need to manipulate the DOM.

    So there is a need to do this communication between the different threads. We are thinking to implement this as a special character device in browserfs (like /dev/jsaddle) with support of doing system calls to do read, write and get status.

Currently @ElvishJerricco is implementing this in TypeScript (https://github.com/WebGHC/webabi/tree/typescript-kernel-reorg).

This work is independent of the code size issue and there is a lot to be done. So contributions are very much appreciated here.

Create jsaddle-wasm

Jsaddle interface for WebGHC. https://github.com/WebGHC/jsaddle-wasm

This is relatively easy to implement once the above kernel execution environment is created. This will allow the ghcjs-dom to work using the jsaddle-dom package.

Executation on NodeJS

This will be required to run the test-suites, and perhaps other applications. We have managed to run the current version of webabi on nodejs, though there is some more work required to run the ghc test-suite.

Try it out

   # Make sure you add the binary key to fetch pre-compiled ghc and toolchain
   # hydra.webghc.org-1:knW30Yb8EXYxmUZKEl0Vc6t2BDjAUQ5kfC1BKJ9qEG8=

   $ git clone https://github.com/WebGHC/wasm-cross.git
   $ cd wasm-cross
   $ nix-build release.nix -o haskell-example-web -A wasm.haskell-example-web
   $ cd haskell-example-web
   $ hserv -p8080

Go to 127.0.0.1:8080 in firefox or chrome, and open console to view the print outputs. You will have to enable SharedArrayBuffer from the browser config settings. Or you can edit the wasm.js file and comment out the two lines containing SharedArrayBuffer.

Hack

Get in touch with us (@dfordivam, @ElvishJerricco) on IRC freenode #reflex-frp or #ghc

GHC

GHC currently uses unregistered compilation, by generating C code and compiling using clang. The llvm native code generation cannot be used currently because wasm doesn't have tail-call support.

The runtime system (RTS) has been compiled to wasm with some minor modifications.

To build GHC cross compiler, first do this config

    $ git config --global url."[email protected]:WebGHC/packages-".insteadOf     [email protected]:WebGHC/packages/
    $ git config --global url."ssh://github.com/WebGHC/packages-".insteadOf     ssh://github.com/WebGHC/packages/
    $ git config --global url."https://github.com/WebGHC/packages-".insteadOf     https://github.com/WebGHC/packages/
    $ git config --global url."http://github.com/WebGHC/packages-".insteadOf     http://github.com/WebGHC/packages/
    $ git config --global url."git://github.com/WebGHC/packages-".insteadOf     git://github.com/WebGHC/packages/

Then fetch the sources and build

    $ git clone --recursive https://github.com/WebGHC/ghc.git

    # Obtain a nix-shell
    $ cd /path/to/wasm-cross
    $ nix-shell -A nixpkgsWasm.haskell.packages.ghcHEAD.ghc
    
    # Do build
    $ cd /path/to/ghc

    # Edit mk/build.mk if required 
    $ configurePhase
    $ make -j4

    # Run your local ghc cross compiler
    $ /path/to/ghc/inplace/bin/ghc-stage1 main.hs
    # use the generated *main* file

Webabi / kernel execution / System calls

The supporting kernel code (wasm.js) is work in progress, and can do minimal operations like write to STDOUT.

    # Get source
    $ git clone https://github.com/WebGHC/webabi
    $ cd webabi

    # obtain a shell with ghc
    $ cd wasm-cross
    $ nix-shell -A nixpkgsWasm.haskell.packages.ghcHEAD.hello

    # Copy some dependecies 
    $ cp /path/to/haskell-example-web/node_modules .
    $ cp /path/to/haskell-example-web/index.html .

After this you can compile haskell code using the ghc in this shell, and modify the files wasm.js, kernel.js, etc.

    # Compile haskell
    $ wasm32-unknown-unknown-wasm-ghc main.hs -o hello
    $ hserv