-
Notifications
You must be signed in to change notification settings - Fork 19
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
1 changed file
with
42 additions
and
23 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
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: | ||
|
||
```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: | ||
|
||
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. | ||
|
||
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*). | ||
`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: | ||
|
||
`llc -asm-verbose=false -o main.s main.bc` | ||
|
||
The backend output is in linear WASM 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 `ewasm-cleanup` to be deployed as a contract. |