Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add docs for using LLVM toolchain with Webassembly #46

Open
wants to merge 10 commits into
base: master
Choose a base branch
from
Open
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 42 additions & 23 deletions clang.md
Original file line number Diff line number Diff line change
@@ -1,54 +1,73 @@
# Compiling C/C++ to WebAssembly

## Rolling your own compiler
Many high level languages already support compilation to WebAssembly
through the experimental LLVM backend. Unfortunately, it is a tedious
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

experimental LLVM backend

Could you please add a link to further documentation on this? Why is it "experimental"?

and poorly documented process. This document aims to alleviate some
of this tedium with a step-by-step tutorial to compile some basic C
code to WAST format using LLVM, as well as provide instructions for building
the toolchain.

Clang has a WebAssembly target, though it is not easy to use currently. First, a custom build must be made.
## Dependencies

- LLVM + Clang: Must be built with the experimental WebAssebmly backend enabled
- Binaryen: Needed to convert the `.s` output of LLVM's backend to WAST

## Install LLVM and Clang with the WebAssembly backend

### From the repo

First, clone the needed repositories:

To build `clang`:
```sh
git clone http://llvm.org/git/llvm.git
cd llvm/tools
git clone http://llvm.org/git/clang.git
cd ../projects
git clone http://llvm.org/git/compiler-rt.git

Then initialize CMake:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure why these two steps needs to be separate (initialise + build).

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

helps to annotate


```sh
mkdir ../build
cd ../build
cmake -DLLVM_EXPERIMENTAL_TARGETS_TO_BUILD=WebAssembly -DLLVM_TARGETS_TO_BUILD= ..
```

Lastly, call `make` as usual:

```sh
cmake --build .
cd ../..
```

This will take anything from 1 to 5 hours.
At the end of the (long) build the binaries will be in `bin`. Feel free to add that to your `PATH` for ease of use.

## Install Binaryen

This one is much easier. Simply:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you link to the binaryen master install docs here? In case these steps change or something.


To build `binaryen`:
```sh
git clone https://github.com/WebAssembly/binaryen.git
cd binaryen
mkdir build
cd build
cmake ..
cmake --build .
cd ../..
```

## Using this compiler
CMake will also generate an `install` target if you want to actually install Binaryen on your system.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How would you run this? cmake install? Could you please make that explicit here?


Now everything is set to finally compile *Hello World*!
## Compile C/C++ to WebAssembly

The compilation process has four steps:
- compiling (`clang`)
- linking to LLVM IR (`llc`)
- compiling to WebAssembly S-expressions (`s2wasm`)
- compiling to WebAssembly binary (`wasm-as`)
First we must compile C to LLVM bitcode through the Clang frontend:

Note: the last step can also be accomplished with [wabt](https://github.com/webassembly/wabt) (previously called *sexpr-wasm-prototype*).
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we can keep this note.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

actually the list of steps is gone and we need binaryen anyway for s2wasm

`clang -emit-llvm --target=wasm32-unknown-unknown-elf -c -o source.bc source.c`

Cheat sheet:
```sh
clang -emit-llvm --target=wasm32-unknown-unknown-elf -nostdlib -S hello.c
llc -o hello.s hello.ll
s2wasm -o hello.wast hello.s
wasm-as -o hello.wasm hello.wast
```
Next we can generate linear WASM output from the bitcode:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is a "linear WASM output" ?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The linear assembly format that WASM specifies

also i stopped maintaining this a while ago.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The linear assembly format that WASM specifies

I'm also not sure what this means. Could you link to another doc that explains this?


`llc -asm-verbose=false -o main.s main.bc`

The backend output is in linear assembly format, so we must convert this to WAST with binaryen's `s2wasm` tool:

`s2wasm -o main.wast main.s`

There you go, you have your very first WebAssembly binary.
The code will now be in WAST format but must be cleaned up with [wasm-chisel](https://github.com/wasmx/wasm-chisel) to be deployed as a contract.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

must be cleaned up with wasm-chisel

Could you please make it explicit how to do this? Is it just a command you need to run? Do you need to clone the repo and compile and run? Etc.