環境構築
今回はRustでwasm-bindgen
を使ってWebAssembly部分を作っていきます。
そちらを準備していきましょう。
Rustの開発環境のセットアップの流れとしては、
- Rustをインストールするために、まずはrustupというツールを使用します。これにより、Rustのコンパイラやツールチェーンを簡単に管理できます。
- rustupを使ってRustをインストールします。これにより、必要なツールが自動的にダウンロードされ、設定されます。
- インストール後、PATH環境変数の確認
- インストールが成功したかどうかを確認するために、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
ディレクトリ内に、target
とpkg
ディレクトリが作られていると思います。
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ファイルを扱う際、型チェックができるように提供されます。
- WebAssemblyのバイナリファイル(
-
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を見てみたい人はどうぞ。