[Rust学習] WebAssemblyを簡単構築

2024年4月6日

Rust プログラミング 学習

eyecatch そもそも、Rustを学習したいと強く思ったのは、WebAssemblyという、インターネットブラウザで高速に動作することができる、プラグインなどを構築できるという事を何かの記事で見たのがきっかけです。 それまで、インターネットブラウザでは、Javascript言語のみがプログラミングして動的ページを作ることができる手段だったのが、別の方法で且つ、Javascriptよりも高速に動作することができるというのは、Web系人間にとっては、非常に魅力的な技術なんですね。 そして、そのWrbAssemblyって何なのか?というと、その時新しいプログラミング言語として紹介されていたRust言語だったというわけですね。 今現在もWebAssemblyについてまだ理解していない部分もあるので、今回は自分の目的でもあるWebAssemblyについて調査をしてみたいと思います。

ChatGPTに聞いてみた

  • WebAssemblyについて詳しく教えて
  • WebAssembly(略称: wasm)は、ウェブブラウザ内で高性能なバイナリコードを実行するためのオープン標準技術です。 以下に、WebAssemblyに関する詳細をわかりやすく説明します。

目的と特徴

WebAssemblyは、ブラウザ上で高速な計算や処理を可能にすることを目的としています。 JavaScriptだけでは表現力やパフォーマンスが不十分な場合に、WebAssemblyが補完的な役割を果たします。 WebAssemblyはバイナリ形式であり、テキスト形式のJavaScriptよりも効率的に実行できます。

使用される場面

WebAssemblyは、ゲームやグラフィックス、音声・動画処理、科学計算など、高度な計算や処理が必要なウェブアプリケーションで活用されます。 特に、大規模なデータ処理やリアルタイムな処理を要求されるアプリケーションで効果を発揮します。

利点

パフォーマンス: WebAssemblyは高速で効率的な実行が可能であり、JavaScriptよりも性能が向上します。 言語の選択肢: WebAssemblyはC/C++、Rustなどの言語でコードを記述し、ブラウザ上で実行できます。 ポータビリティ: バイナリ形式であり、異なるプラットフォームやブラウザでも同じコードが動作します。

動作原理

WebAssemblyは、ブラウザ上でJavaScriptから呼び出されます。 C/C++やRustなどで書かれたコードは、コンパイラによってWebAssemblyバイナリに変換されます。 ブラウザはこのバイナリを解釈し、ネイティブコードと同様の速度で実行します。

開発環境

WebAssemblyを利用するには、EmscriptenやRustのwasm-packなどのツールが利用されます。 EmscriptenはC/C++コードをWebAssemblyに変換するためのツールチェーンであり、 wasm-packはRustをWebAssemblyにコンパイルするためのツールです。

将来展望

WebAssemblyは急速に普及しており、ウェブ開発の重要な要素となっています。 将来的には、WebAssemblyの機能やサポートがさらに拡大し、ウェブアプリケーションの多様な領域で利用されることが期待されています。 以上が、WebAssemblyについての詳細で分かりやすい説明です。

理解できた点

WebAssemblyって、Rust言語のみだと思っていたら、C/C++でも出来てしまうというのが知らんかった情報。 ※Go言語などでもできるらしい・・・ ツールを使ってWebAssemblyアプリケーションに変換するとの事で、 Rust言語のツールwasm-packをインストールしてみました。 $ cargo install wasm-pack Updating crates.io index Downloaded wasm-pack v0.12.1 Downloaded 1 crate (423.6 KB) in 0.18s Installing wasm-pack v0.12.1 Updating crates.io index Downloaded atty v0.2.14 Downloaded aes v0.8.4 Downloaded cfg-if v1.0.0 Downloaded sha1 v0.10.6 Downloaded serde_ignored v0.1.10 Downloaded serde_derive v1.0.197 Downloaded equivalent v1.0.1 Downloaded constant_time_eq v0.1.5 Downloaded tinyvec_macros v0.1.1 Downloaded num-conv v0.1.0 Downloaded home v0.5.9 Downloaded time-core v0.1.2 Downloaded clap_lex v0.7.0 Downloaded colorchoice v1.0.0 Downloaded cipher v0.4.4 Downloaded cargo_metadata v0.15.4 Downloaded which v4.4.2 Downloaded scopeguard v1.2.0 Downloaded same-file v1.0.6 Downloaded rand_core v0.6.4 Downloaded powerfmt v0.2.0 Downloaded percent-encoding v2.3.1 Downloaded pbkdf2 v0.11.0 Downloaded version_check v0.9.4 Downloaded unicode-width v0.1.11 Downloaded strsim v0.11.0 Downloaded indexmap v2.2.6 Downloaded thiserror v1.0.58 Downloaded toml_datetime v0.6.5 Downloaded hashbrown v0.14.3 Downloaded untrusted v0.9.0 Downloaded rustls-webpki v0.102.2 Downloaded zeroize v1.7.0 Downloaded xattr v1.3.1 Downloaded chrono v0.4.37 Downloaded zstd-safe v5.0.2+zstd.1.5.2 Downloaded walkdir v2.5.0 Downloaded utf8parse v0.2.1 Downloaded object v0.32.2 Downloaded spin v0.9.8 Downloaded smallvec v1.13.2 Downloaded sha2 v0.10.8 Downloaded thiserror-impl v1.0.58 Downloaded rustls v0.22.3 Downloaded rustix v0.38.32 Downloaded idna v0.5.0 Downloaded gimli v0.28.1 Downloaded bzip2-sys v0.1.11+1.0.8 Downloaded libc v0.2.153 Downloaded toml v0.8.12 Downloaded tempfile v3.10.1 Downloaded clap_builder v4.5.2 Downloaded unicode-bidi v0.3.15 Downloaded toml v0.7.8 Downloaded tinyvec v1.6.0 Downloaded zstd v0.11.2+zstd.1.5.2 Downloaded unicode-ident v1.0.12 Downloaded uuid v1.8.0 Downloaded tar v0.4.40 Downloaded typenum v1.17.0 Downloaded serde v1.0.197 Downloaded memchr v2.7.2 Downloaded shell-words v1.1.0 Downloaded ryu v1.0.17 Downloaded miniz_oxide v0.7.2 Downloaded flate2 v1.0.28 Downloaded zip v0.6.6 Downloaded cc v1.0.90 Downloaded base64 v0.21.7 Downloaded subtle v2.5.0 Downloaded strsim v0.10.0 Downloaded url v2.5.0 Downloaded siphasher v0.3.11 Downloaded serde_spanned v0.6.5 Downloaded semver v1.0.22 Downloaded rustls-pki-types v1.4.1 Downloaded rustc-demangle v0.1.23 Downloaded toml_edit v0.19.15 Downloaded toml_edit v0.22.9 Downloaded ureq v2.9.6 Downloaded quote v1.0.35 Downloaded proc-macro2 v1.0.79 Downloaded pkg-config v0.3.30 Downloaded password-hash v0.4.2 Downloaded parking_lot_core v0.9.9 Downloaded unicode-normalization v0.1.23 Downloaded ring v0.17.8 Downloaded winnow v0.5.40 Downloaded time v0.3.34 Downloaded serde_json v1.0.115 Downloaded webpki-roots v0.26.1 Downloaded syn v2.0.57 Downloaded parking_lot v0.12.1 Downloaded os_info v3.8.2 Downloaded once_cell v1.19.0 Downloaded num-traits v0.2.18 Downloaded log v0.4.21 Downloaded lock_api v0.4.11 Downloaded hmac v0.12.1 Downloaded env_logger v0.10.2 Downloaded dialoguer v0.10.4 Downloaded clap v4.5.4 Downloaded lazy_static v1.4.0 Downloaded jobserver v0.1.28 Downloaded itoa v1.0.11 Downloaded is_executable v0.1.2 Downloaded inout v0.1.3 Downloaded iana-time-zone v0.1.60 Downloaded human-panic v1.2.3 Downloaded hex v0.4.3 Downloaded heck v0.5.0 Downloaded zstd-sys v2.0.10+zstd.1.5.6 Downloaded glob v0.3.1 Downloaded getrandom v0.2.12 Downloaded generic-array v0.14.7 Downloaded fs2 v0.4.3 Downloaded form_urlencoded v1.2.1 Downloaded filetime v0.2.23 Downloaded fastrand v2.0.2 Downloaded errno v0.3.8 Downloaded either v1.10.0 Downloaded dirs-sys-next v0.1.2 Downloaded dirs-next v2.0.0 Downloaded digest v0.10.7 Downloaded deranged v0.3.11 Downloaded crypto-common v0.1.6 Downloaded crc32fast v1.4.0 Downloaded cpufeatures v0.2.12 Downloaded core-foundation-sys v0.8.6 Downloaded console v0.15.8 Downloaded clap_derive v4.5.4 Downloaded camino v1.1.6 Downloaded bzip2 v0.4.4 Downloaded byteorder v1.5.0 Downloaded bitflags v2.5.0 Downloaded base64ct v1.6.0 Downloaded cargo-platform v0.1.8 Downloaded block-buffer v0.10.4 Downloaded backtrace v0.3.71 Downloaded binary-install v0.2.0 Downloaded anyhow v1.0.81 Downloaded autocfg v1.2.0 Downloaded anstyle-query v1.0.2 Downloaded anstyle-parse v0.2.3 Downloaded anstyle v1.0.6 Downloaded anstream v0.6.13 Downloaded adler v1.0.2 Downloaded addr2line v0.21.0 Downloaded 148 crates (13.5 MB) in 1.53s (largest was `ring` at 4.2 MB) Compiling libc v0.2.153 Compiling proc-macro2 v1.0.79 Compiling unicode-ident v1.0.12 Compiling cfg-if v1.0.0 Compiling serde v1.0.197 Compiling version_check v0.9.4 Compiling typenum v1.17.0 Compiling pkg-config v0.3.30 Compiling subtle v2.5.0 Compiling rustix v0.38.32 Compiling generic-array v0.14.7 Compiling autocfg v1.2.0 Compiling adler v1.0.2 Compiling bitflags v2.5.0 Compiling miniz_oxide v0.7.2 Compiling log v0.4.21 Compiling equivalent v1.0.1 Compiling tinyvec_macros v0.1.1 Compiling hashbrown v0.14.3 Compiling crc32fast v1.4.0 Compiling indexmap v2.2.6 Compiling jobserver v0.1.28 Compiling quote v1.0.35 Compiling errno v0.3.8 Compiling cc v1.0.90 Compiling syn v2.0.57 Compiling getrandom v0.2.12 Compiling cpufeatures v0.2.12 Compiling tinyvec v1.6.0 Compiling utf8parse v0.2.1 Compiling untrusted v0.9.0 Compiling rustls-pki-types v1.4.1 Compiling zstd-safe v5.0.2+zstd.1.5.2 Compiling serde_json v1.0.115 Compiling spin v0.9.8 Compiling anstyle-parse v0.2.3 Compiling zeroize v1.7.0 Compiling anstyle v1.0.6 Compiling base64ct v1.6.0 Compiling crypto-common v0.1.6 Compiling block-buffer v0.10.4 Compiling inout v0.1.3 Compiling percent-encoding v2.3.1 Compiling digest v0.10.7 Compiling unicode-bidi v0.3.15 Compiling unicode-normalization v0.1.23 Compiling ryu v1.0.17 Compiling itoa v1.0.11 Compiling colorchoice v1.0.0 Compiling rustls v0.22.3 Compiling powerfmt v0.2.0 Compiling anstyle-query v1.0.2 Compiling rand_core v0.6.4 Compiling anstream v0.6.13 Compiling deranged v0.3.11 Compiling zstd-sys v2.0.10+zstd.1.5.6 Compiling ring v0.17.8 Compiling bzip2-sys v0.1.11+1.0.8 Compiling idna v0.5.0 Compiling password-hash v0.4.2 Compiling backtrace v0.3.71 Compiling sha2 v0.10.8 Compiling hmac v0.12.1 Compiling form_urlencoded v1.2.1 Compiling cipher v0.4.4 Compiling flate2 v1.0.28 Compiling lock_api v0.4.11 Compiling num-traits v0.2.18 Compiling semver v1.0.22 Compiling thiserror v1.0.58 Compiling gimli v0.28.1 Compiling memchr v2.7.2 Compiling anyhow v1.0.81 Compiling camino v1.1.6 Compiling time-core v0.1.2 Compiling parking_lot_core v0.9.9 Compiling serde_derive v1.0.197 Compiling num-conv v0.1.0 Compiling time v0.3.34 Compiling object v0.32.2 Compiling thiserror-impl v1.0.58 Compiling bzip2 v0.4.4 Compiling addr2line v0.21.0 Compiling aes v0.8.4 Compiling url v2.5.0 Compiling pbkdf2 v0.11.0 Compiling sha1 v0.10.6 Compiling xattr v1.3.1 Compiling webpki-roots v0.26.1 Compiling dirs-sys-next v0.1.2 Compiling filetime v0.2.23 Compiling constant_time_eq v0.1.5 Compiling lazy_static v1.4.0 Compiling fastrand v2.0.2 Compiling heck v0.5.0 Compiling smallvec v1.13.2 Compiling core-foundation-sys v0.8.6 Compiling winnow v0.5.40 Compiling strsim v0.11.0 Compiling byteorder v1.5.0 Compiling unicode-width v0.1.11 Compiling rustc-demangle v0.1.23 Compiling base64 v0.21.7 Compiling clap_lex v0.7.0 Compiling scopeguard v1.2.0 Compiling once_cell v1.19.0 Compiling clap_builder v4.5.2 Compiling console v0.15.8 Compiling iana-time-zone v0.1.60 Compiling clap_derive v4.5.4 Compiling rustls-webpki v0.102.2 Compiling toml_datetime v0.6.5 Compiling serde_spanned v0.6.5 Compiling toml_edit v0.22.9 Compiling toml v0.8.12 Compiling toml_edit v0.19.15 Compiling ureq v2.9.6 Compiling cargo-platform v0.1.8 Compiling os_info v3.8.2 Compiling tempfile v3.10.1 Compiling tar v0.4.40 Compiling dirs-next v2.0.0 Compiling uuid v1.8.0 Compiling fs2 v0.4.3 Compiling shell-words v1.1.0 Compiling siphasher v0.3.11 Compiling home v0.5.9 Compiling is_executable v0.1.2 Compiling either v1.10.0 Compiling same-file v1.0.6 Compiling hex v0.4.3 Compiling which v4.4.2 Compiling walkdir v2.5.0 Compiling dialoguer v0.10.4 Compiling human-panic v1.2.3 Compiling cargo_metadata v0.15.4 Compiling chrono v0.4.37 Compiling toml v0.7.8 Compiling clap v4.5.4 Compiling serde_ignored v0.1.10 Compiling parking_lot v0.12.1 Compiling atty v0.2.14 Compiling env_logger v0.10.2 Compiling glob v0.3.1 Compiling strsim v0.10.0 Compiling zstd v0.11.2+zstd.1.5.2 Compiling zip v0.6.6 Compiling binary-install v0.2.0 Compiling wasm-pack v0.12.1 Finished release [optimized] target(s) in 1m 05s Installing /Users/***/.cargo/bin/wasm-pack Installed package `wasm-pack v0.12.1` (executable `wasm-pack`) メチャクチャたくさんのモジュールがインストールされた!!!

簡単WebAssemblyの構築

Cargoプロジェクトの作成

最終的に*.wasmというファイルをJavascriptで読み込んで動作させることができるモジュールとなるので、それを作るために、cargoフレームワークを使うという感じです。 まずは、以下のコマンドでプロジェクトを作ります。 $ cargo new --lib hello > Created library `hello` package helloは、Cargoプロジェクトの名前なので、任意の名称で作ります。 すると、helloフォルダが以下の構成で構築されます。
/ hello ├ src │ └ lib.rs ├ .gitignore └ Cargo.toml

Cargo.tomlに追記

できあがったCargo.tomlに、以下のコードを追加します。 [lib] crate-type = ["cdylib"] ちなみに、ファイルの全体は次のようになります。 [package] name = "hello" version = "0.1.0" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] [lib] crate-type = ["cdylib"]

プログラムの設置

lib.rsには、cargoサンプルとして以下のような内容が書かれていました。 pub fn add(left: usize, right: usize) -> usize { left + right } #[cfg(test)] mod tests { use super::*; #[test] fn it_works() { let result = add(2, 2); assert_eq!(result, 4); } } これを、独自のソースに書き換えます。 #[no_mangle] pub fn add(a: i32, b: i32) -> i32 { a + b }

Cargoでビルド

wasm32-unknown-unknownが有効化されていない場合は、事前に以下のコマンドを実行する。 $ rustup target add wasm32-unknown-unknown $ cargo build --target=wasm32-unknown-unknown --release > Compiling hello v0.1.0 (/Users/yugeta/web/test/rust/hello) > Finished release [optimized] target(s) in 0.10s

.wasmファイルを取得

ビルドすると、.wasmファイルが以下の階層に構築されます。 hello/target/wasm32-unknown-unknown/release/hello.wasm

index.htmlを作成

javascriptで、hello.wasmファイルを読み込んで実行する処理を書きます。 <!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <title>Hello, WebAssembly!</title> <script> const wasm = '../target/wasm32-unknown-unknown/release/hello.wasm' fetch(wasm) .then(response => response.arrayBuffer()) .then(bytes => WebAssembly.instantiate(bytes, {})) .then(results => { const add = results.instance.exports.add(11, 22); console.log("Hello add : ", add) }) </script> </head> </html> このページをhttpプロトコルで開くと、コンソール画面に"Hello add : 33"と表示されています。 Rustで書いたプログラムをJavascriptで実行できたという証ですね。

いくつかの問題を発見

文字列をreturnするとundefinedになる問題

上記の方法で、RustでString(何かしらの文字列)を返すプログラムを書いてみました。 #[no_mangle] pub fn hello(name: &str) -> String{ // return name.to_string(); let hello = "Hello ".to_string(); let s = hello + name.trim(); return s; } hello関数に、文字列を引数で送ると、"Hello 文字列"と返すように書いてみました。 Rustでコンパイルすると、問題なく動作する関数なのですが、Javascriptから呼び出すと返される文字列が、undefinedになってしまいます。

複数の関数を同梱できない問題

次のように、lib.rsに、複数の関数を記述した場合、 #[no_mangle] pub fn add(a: i32, b: i32) -> i32 { a + b } pub fn min(a: i32, b: i32) -> i32 { a - b } index.htmlで表示されるJavascriptは、先頭の関数は正常に読み込まれますが、2つ目移行の関数は、エラーが返ります。 Hello add : 33 html/:17 Uncaught (in promise) TypeError: results.instance.exports.min is not a function at html/:17:46

次回以降に調べようっと!

今回は上記の問題に関して調べる事はしません。 何故なら・・・めちゃんこ時間がかかりそうな匂いがプンプンするからです。 とりあえず、数値の計算をして結果を返す事は今回のWebAssenblyのコンパイル方法で出来ることがわかったという進捗で満足しておくことにしましょう。 モヤモヤする? もちろん、自分としてもこんなところでゴールにするつもりはないので、もっとRust+WebAssemblyを突っ込んでいって、 より良いWebアプリケーション構築につなげていく予定です。

あとがき

WebAssemblyを簡単に触ってみましたが、Javascriptで関数を読み込んで、より高速な計算が行えるという事が分かりました。 でも・・・Javascriptって結構計算が早いんですよね。 どこかの人のブログ(参考リンクにあります)で、速度比較してましたが、3倍程度のメリットしか無いとの結論で少しがっかりもしました。 ただ、WebAsseemblyのメリットは、関数内のプログラムが、Javascriptだと丸見えスクリプトなんですが、WebAssemblyだと、処理がコンパイルされて精度の悪いデコンパしたところで、処理のモロバレは回避できるのがいいですね。 ちょっとだけ触ってみて、いろいろな問題もわかってきて、今後の目標ができたというモノです。 なんかワクワクしてきましたね。 セキュイアな、Webアプリが構築できる予感がビンビンします。

参考

WebAssembly の概要 Rust から WebAssembly にコンパイル WasmをさわってJSとの速度比較をしてみた WebAssembly 入門 Rust と WebAssembly を使用したシンプルな Web アプリの構築: ステップバイステップ ガイド WasmをさわってJSとの速度比較をしてみた

人気の投稿

このブログを検索

ごあいさつ

このWebサイトは、独自思考で我が道を行くユゲタの少し尖った思考のTechブログです。 毎日興味がどんどん切り替わるので、テーマはマルチになっています。 もしかしたらアイデアに困っている人の助けになるかもしれません。

ブログ アーカイブ