RustでコンパイルしたWebAssemblyでHelloWorldするまで

若干周回遅れ感ありますが、
Firefox,Chromeのstableにwasmがきたということで、
休日を使ってトライしてみました。

パッケージ管理やCI/CDを考えればcargo build一択だと思いますが、
一応rustcとcargoそれぞれでビルドする方法を確認しました。

なお、動作環境はmacOSです。

## Setup

Rustとcmakeをインストール。

```sh
curl https://sh.rustup.rs -sSf | sh
rustup install stable
rustup default stable
rustup target add wasm32-unknown-emscripten
rustc --version
```
```sh
brew install cmake
cmake --version
```

Emscriptenをインストール。
3,40分かかるので注意。

```sh
cd /usr/local/share
git clone https://github.com/juj/emsdk.git
emsdk/emsdk install sdk-incoming-64bit binaryen-master-64bit
emsdk/emsdk activate sdk-incoming-64bit binaryen-master-64bit
sudo ln -s $(pwd)/emsdk/emscripten/incoming/emcc /usr/local/bin/emcc
emcc -v
```

## Build by cargo

```sh
cargo new --bin hello
cd hello/
cargo build --target=wasm32-unknown-emscripten
cd target/wasm32-unknown-emscripten/debug
python -m SimpleHTTPServer 8000
```

HTTPサーバーはなんでもお好きなものを。
`cargo new` で新規プロジェクトの作成。
`cargo build --target` ではtarget以下にアーキテクチャごとのディレクトリが作られ、
その中にhtml,js,wasmなどが生成されます。

今回は`wasm32-unknown-emscripten`をaddしてるので同名のディレクトリが作られます。
ビルド時に`--release` オプションを付けると`target/wasm32-unknown-emscripten/debug`でなく
`target/wasm32-unknown-emscripten/release`にコードが配置されます。

ビルド後のファイル/ディレクトリ構成は以下。

```sh
.
├── Cargo.lock
├── Cargo.toml
├── src
│   └── main.rs
└── target
    ├── debug
    │   │   
    │  (略)   
    │   │   
    └── wasm32-unknown-emscripten
        └── debug
            ├── build
            ├── deps
            │   ├── hello-e0a7964fe7e29b5e.asm.js
            │   ├── hello-e0a7964fe7e29b5e.js
            │   ├── hello-e0a7964fe7e29b5e.wasm
            │   ├── liblibc-5dc7b85e748840b4.rlib
            │   └── librand-c9d9fbdab2355ee4.rlib
            ├── examples
            ├── hello.d
            ├── hello.js
            ├── hello.wasm
            ├── incremental
            ├── index.html
            └── native
```

## Build by rustc

事前にファイルをいくつか用意しておきます。

```rust:src/main.rs
fn main() {
    println!("Hello world");
}
```

```html:dist/index.html
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title></title>
</head>
<body>
<script>
var Module = {}
fetch('./main.wasm')
  .then((response) => response.arrayBuffer())
  .then((buffer) => {
    Module.wasmBinary = buffer
    var script = document.createElement('script')
    script.src = "main.js"
    document.body.appendChild(script)
  })
</script>
</body>
</html>
```

インラインにfetch.thenを書いていますがこれはほぼイディオムで、
`.wasm`はscriptタグではなくfetch経由でないと動作しないようです。

直接的なHTMLファイルOpenではなくSimpleHTTPServerなどでサーバを立てるのは、
このfetch(ネットワーク経由での`.wasm`のロード)が必要なためです。

話を戻して、rustcで`src/main.rs`をBuild、その後Webサーバを起動します。

```sh
rustc --target=wasm32-unknown-emscripten src/main.rs -o dist/main.js
cd dist/
python -m SimpleHTTPServer 8000
```

ビルド後のファイル/ディレクトリ構成はこんな感じ。

```sh
.
├── dist
│   ├── index.html
│   ├── main.0.o
│   ├── main.asm.js
│   ├── main.js
│   ├── main.metadata.o
│   └── main.wasm
└── src
    └── main.rs
```

## 所感

ちょっとした動作テストや小さなモジュール程度ならrustcを使うのもアリかなと思いました。
少し前にトライしたときはどっかしらのセットアップに躓いてしまい頓挫していたのですが、
今回リベンジしたところemsdkを入れるのに時間がかかった以外はスムーズに作業を進められて幸せでした。


## References

* [Rust から WASM32 を出力するための準備 \- Qiita](http://qiita.com/chikoski/items/6c9f24dc4a825c437e78)
* [Compiling Rust to WebAssembly Guide – Hacker Noon](https://hackernoon.com/compiling-rust-to-webassembly-guide-411066a69fde)