Logo
x logo

箱庭飛行場Ex

環境構築

今回はRustでwasm-bindgenを使ってWebAssembly部分を作っていきます。 そちらを準備していきましょう。

Rustの開発環境のセットアップの流れとしては、

  1. Rustをインストールするために、まずはrustupというツールを使用します。これにより、Rustのコンパイラやツールチェーンを簡単に管理できます。
  2. rustupを使ってRustをインストールします。これにより、必要なツールが自動的にダウンロードされ、設定されます。
  3. インストール後、PATH環境変数の確認
  4. インストールが成功したかどうかを確認するために、rustc --versionコマンドを実行します。これでRustのバージョンが表示されれば、インストールは完了です。 となります。

rustupのページを開くと、Mac/Linux/Windowsそれぞれのインストール方法が表示されます。
<MACの場合>

<Windowsの場合>

Mac/Linuxでは、

1)ターミナルを開き
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh

この時、いろいろ聞かれますが、まずはデフォルトでインストールしておいて大丈夫です。

2)環境変数の設定
source $HOME/.cargo/env
3)インストール後確認
rustc --version

Windowsでは、

1)まず、rustup-init.exeをダウンロードします。

サイトから、rustup-init.exeをダウンロードしてください。 (おそらくほとんどの方は、(64-BIT)と書かれた方で大丈夫です)

2) インストール

rustup-init.exeを起動して、インストーラが表示されたら、インストール先を選択します。通常はデフォルトの設定で問題ありません。

3) Visual Studio C++ Build Toolsのインストール

Rustを使用するためには、Visual Studio C++ Build Toolsが必要です。これがインストールされていない場合は、指示に従ってインストールします。 サイトの方にリンクがありますが、こちらからダウンロード&インストールしてください。

4) インストール後確認

コマンドプロンプトを開き、

rustc --version

で表示されるか確認してください。インストーラーで環境変数も設定されていると思いますが、 もし表示されないときは、

  • 1)Windowsキー + R を押して実行を開く
  • 2)sysdm.cplと入力してシステムのプロパティを開く
  • 3)詳細設定タブ →環境変数をクリック
  • 4)ユーザー環境変数PATH%USERPROFILE%\.cargo\bin含まれていることを確認してください。    入っていなかったら自分で入れて、念の為再起動しておいてください。

詳しくはこちらのrustupのサイトに書かれています。さまざまなドキュメントも用意されていますので、こちらもみておいてください。

RustでHello,world!

せっかくインストールしたので、実際にビルドできるか確認しておきましょう。 開発するディレクトリで、

cargo new hello-world

と入力してください。hello_worldディレクトリが作られ、必要最低限のソースや設定ファイルが出来上がっています。

[hello-world]
├── Cargo.toml
└── src
    └── main.rs

ここで、main.rsを開いてみてください。すでに、Hello, world!を表示するソースが書かれていますね。

fn main() {
    println!("Hello, world!");
}

では、hello_worldディレクトリに戻って、ここで、

cargo run

どうですか?画面にHello, world!と表示されたら成功です。 何かエラーが出てきたら、そのエラーをAIに貼り付けたらほぼ解決法を示してくれます。

これで、Rustの開発環境は出来上がりました。

WebAssembly開発のための準備

さて、次は、WebAssemblyの開発のためのセットアップです。 RustでWebAssemblyを作るための準備です。

1.WebAssembly用のコンパイルをするために、
rustup target add wasm32-unknown-unknown

を入れておいてください。Rustで作られたプログラムをWebAssembly用にコンパイルするために必要です。

次に、wasm-packをインストールします。これはRustで生成されたWebAssemblyをビルドおよびパッケージ化するツールです。

cargo install wasm-pack

以上です。

これで、WebAssemblyの開発もできるようになります。

2.WebAssemblyでHello,world!を試してみる
rustソースの準備

まず、新しいプロジェクトを作成します。

cargo new --lib hello-wasm
cd hello-wasm
[hello-wasm]
├── Cargo.toml
└── src
    └── lib.rs

この中にあるCargo.tomlを編集します。

[package]
name = "hello-wasm"
version = "0.1.0"
edition = "2021"

[dependencies]

最初は、このようになっていますが、ここの[dependencies]に必要なクレート(=ライブラリ)を追加します。そして、作成するクレートタイプを動的ライブラリに指定します。

[dependencies]
wasm-bindgen = "0.2"
[lib]
crate-type = ["cdylib"]

次にソースを編集しましょう。 src/lib.rsを編集します。中にすでに色々書かれていると思いますが、全て削除して以下のようにしてください。

use wasm_bindgen::prelude::*;

#[wasm_bindgen]
extern "C" {
    fn alert(s: &str);
}

#[wasm_bindgen]
pub fn greet(name: &str) {
    alert(&format!("Hello, {}!", name));
}

実際の動作を表現するプログラムコード以外に呪文のようなものが書かれていますね。
順番に説明していきます。
#[wasm_bindgen]はRustとJavaScript間の相互運用を可能にするマクロになります。
Rust->Javascriptを呼び出す場合、Javascript->Rustを呼び出す場合に使います。
この関数はそれぞれの橋渡しをするための関数ですよ。と知らせるための表記です。

そして、extern "C"の部分は、

#[wasm_bindgen]
extern "C" {
...
}

この中にある関数が、Rustから見ると外部で定義されていることを表します。 今回の場合、その上に#[wasm_bindgen]が書かれていますから、 extern "C"{...}の中に書かれている関数は、Javascript側で定義された関数ですよ。 ということを表すことになります。

fn alert(s: &str)       //Rust->Javascript 
pub fn greet(name: &str) //Javascript->Rust

alert関数はJavascript側で定義されていて、Rustから呼び出せる。
greet関数は、Rust側で定義されていて、Javascriptから呼び出せる。
という構造です。

さて、これで準備は整いました。
wasm-packを使用してプロジェクトをWebAssemblyにコンパイルします。
hello-wasmディレクトリに戻り、ここで、

wasm-pack build --target web

とすると、Rustコードを.wasmバイナリにコンパイルし、JavaScriptバインディングが生成されます。

[hello-wasm]
├── Cargo.lock
├── Cargo.toml
├── pkg
│   ├── hello_wasm.d.ts
│   ├── hello_wasm.js
│   ├── hello_wasm_bg.wasm
│   ├── hello_wasm_bg.wasm.d.ts
│   └── package.json
├── src
│   └── lib.rs
└── target
    ├── CACHEDIR.TAG
    ├── release
    └── wasm32-unknown-unknown

ディレクトリ内に、targetpkgディレクトリが作られていると思います。
targetは、Rustでコンパイルされたものが出力されるディレクトリです。
pkgは、wasm-packが生成されたRustのバイナリからWebAssembly用のバイナリにコンパイルし、Javascriptバインディングを作り出したものが出力されるディレクトリです。

どうですか?これでWebAssemblyが出来上がりました。

それぞれのファイルの役割は、このようになります。

  • hello_wasm.d.ts

    • TypeScriptの型定義ファイルです。このファイルにより、JavaScriptやTypeScriptコードで、WASMパッケージの関数や変数の型が提供されます。
    • hello_wasm.js ファイルにエクスポートされている init 関数や greet 関数の型情報が定義されています。
    • TypeScriptのプロジェクトでこのパッケージを利用する場合、このファイルがあることで、型の自動補完やエラー検出が可能です。
  • hello_wasm.js

    • WASMパッケージのJavaScriptラッパーです。WebAssemblyのロードと初期化を行うためのモジュールが書かれています。
    • init 関数(実際には__wbg_init関数)がエクスポートされており、この関数を呼ぶことで hello_wasm_bg.wasm ファイルが読み込まれて実行されるようになります。
    • また、Rustで定義した greet 関数もこのファイルからエクスポートされ、JavaScriptから直接呼び出せるようになります。
  • hello_wasm_bg.wasm

    • WebAssembly(WASM)バイナリファイルです。Rustのコードがコンパイルされ、WebAssembly形式に変換されたものが格納されています。
    • このファイルがブラウザに読み込まれることで、WASMモジュールとして実行可能になります。
    • .js ファイルの init 関数内で、この .wasm ファイルがロードされて使用されます。
  • hello_wasm_bg.wasm.d.ts

    • WebAssemblyのバイナリファイル(hello_wasm_bg.wasm)に関連するTypeScriptの型定義ファイルです。
    • 主に、WASMバイナリのインターフェースと互換性のある型情報が記述されています。
    • JavaScriptとTypeScriptコードでWASMファイルを扱う際、型チェックができるように提供されます。
  • package.json

    • このWASMパッケージの設定や依存関係を定義するJSONファイルです。
    • このファイルにより、npmなどのパッケージ管理ツールを使って、このパッケージをインストール・管理できるようになります。
    • パッケージの名前やバージョン、依存関係、エントリーポイント(main)などが記載されています。
HTML+Javascript側を書いてみましょう

hello-wasmディレクトリの直下に、HTMLファイル(例:index.html)を作成し、そこの中でJavascriptからWebAssemblyモジュールをロードし、WebAssemblyの中のgreet()関数を呼んでみましょう。

<!doctype html>
<html lang="ja-JP">
  <head>
    <meta charset="utf-8" />
    <title>Hello Wasm</title>
  </head>
  <body>
    <script type="module">
      import init, { greet } from "./pkg/hello_wasm.js";
      init().then(() => {
        greet("WebAssembly");
      });
    </script>
  </body>
</html>

ここで、VSCodeを使っている方は、Live Server拡張をインストールしておくと便利です。
index.htmlを右クリックして、Open with Live Serverを選択すると、軽量なWebサーバーが開始して、index.htmlがブラウザで見ることができます。

簡単なWebサーバーにindex.htmlと、pkgディレクトリをそのままおいてみて見ることもできますし、
pythonが入っている方は

python3 -m http.server

とすると、ブラウザで、http://localhost:8000を開くと見れます。

さて、どうなりましたか?
Alertが開き、「Hello, WebAssembly!」と表示されましたか?

これで、WebAssembly準備完了です。
次回は、実際に、Packet Pilot本誌でお話しした通り、Packet Pilotシミュレーターを今回ご紹介したWebAssemblyとHTMLで作っていきたいと思います。

さて、ここからは、我が編集部の調査班に、どうやってこのWebAssembly動いているのかまとめてもらいました。
またまた、細かいですよ〜。じっくりWebAssemblyを見てみたい人はどうぞ。