LoginSignup
5
7

More than 5 years have passed since last update.

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

Last updated at Posted at 2017-03-28

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

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

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

Setup

Rustとcmakeをインストール。

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

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

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

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にコードが配置されます。

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

.
├── 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

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

src/main.rs
fn main() {
    println!("Hello world");
}
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サーバを起動します。

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

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

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

所感

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

References

5
7
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
7