ソフトウェアの開発ではビルドやデプロイの手順を頻繁に確認しておくことは大事です。「完成しました、さあデプロイしましょう」となったところで何か重大な問題が発覚してデプロイできない、なんてことになったら大変ですから。
WASM-4ゲームのビルド
これは開発初期の話なんですが、あるときゲームをビルドしてカートリッジを作成しようとしたときのこと。コマンドはRustの通常のビルドと同じで、次のとおりです。
$ cargo build --release
これで、target/wasm32-unknown-unknown/release/cart.wasm
にカートリッジのファイルが作成されます。あとはw4 bundle
コマンドでそのカートリッジのファイルを指定すればOKです。
$ w4 bundle target/wasm32-unknown-unknown/release/cart.wasm --title "mygame" --html mygame.html
Cart size of 975938 bytes is above the limit of 65536 bytes.
ぎょわッ!?(動揺) 975,938バイト(≒950キロバイト)って……。 以前の記事で述べたとおり、WASM-4のカートリッジは 最大64キロバイト と決められいて、これを大幅に超過してしまっています。なお、ゲームボーイのROMは最大1メガバイトで、初代ポケモンは512キロバイトのROMだったことを考えると、WASM-4の制約はかなり厳しい感じです。さすがにもうちょっと欲しい……。
Rustのオプションでカートリッジのサイズを最適化する
とはいえ、まだ大してゲーム開発も進んでいないのにこのサイズはあんまりですし、余計なコードがたくさん入っているだけでもっとサイズは削減できるはずです。
とりあえずCargo.toml
でlto = true
、opt-level = "z"
の設定をしろみたいにGitHubのIssueかどこかに書いてあったので、確認してみます。またdebug = true
になっていたので、debug = false
に変えてみます。
[profile.release]
debug = false
lto = true
opt-level = "z"
panic = 'abort'
$ w4 bundle target/wasm32-unknown-unknown/release/cart.wasm --title "mygame" --html mygame.html
Cart size of 392363 bytes is above the limit of 65536 bytes.
ん゛ッ……! まだ392363バイトもあります。本当はRustのコンパイラの最適化だけで何とかなって欲しいです。WASM-4はZigやNimなどの言語でも書くことができますが、他の言語ならもっとバイナリのサイズは小さいんでしょうか。
wasm-snapとwasm-optをキメる
GitHubのIssueを漁ったら、Rustのカートリッジのサイズがでかすぎる というまさしく私が直面しているのと同じ問題で Issueが立っていたので読んでみました。どうも、wasm-snip
というツールを使うとかなりファイルサイズを削減できるそうです。インストールして使ってみます。
$ cargo install wasm-snip
$ cargo build --release
$ wasm-snip --snip-rust-fmt-code --snip-rust-panicking-code target/wasm32-unknown-unknown/release/cart.wasm > cart.min.wasm
Cart size of 97493 bytes is above the limit of 65536 bytes.
ぐぬぬ……かなりサイズは減りましたが、これでもダメみたいです。他にもwasm-opt
というツールがあるそうなので、これも使います。
$ npm i wasm-opt -g
$ wasm-opt -Oz --zero-filled-memory --strip-producers --dce cart.min.wasm -o cart.min.min.wasm
$ w4 bundle cart.min.min.wasm --title "mygame" --html mygame.html
Bundled mygame.html
これでようやく 53キロバイトにまでサイズを削減し、ゲームをバンドルすることができました!
これで、mygame.html
というファイルが作成されています。独立した完全ペライチ1枚のHTMLになっていて、カートリッジのファイル自体もHTMLに埋め込まれていました。これをどこかにアップロードすればデプロイ完了です。
しかしformat!
がお亡くなりになる
これで解決と思いきや、ローカルの開発サーバーでは問題ないものの、ビルドしてデプロイしたらブルースクリーンになってしまうことに気付きました。どうやら format!
マクロやi32::to_string
のような関数で軒並みエラーになっているようです。いろいろ調べまわってようやく思い当たったのですが、wasm-snip
に --snip-rust-fmt-code
というオプションを渡しているじゃないですか。このオプション、文字通りRust標準のstd::fmt
の関数をかたっぱしから潰してサイズを削減するため、format!
マクロなどが使えなくなるんですね……。つら……。
参考文献
- https://wasm4.org/docs/guides/distribution
- https://github.com/aduros/wasm4/issues/480
- https://github.com/aduros/wasm4/issues/238
次回予告
次回はいわゆる「グラフィックコンテキスト」を自力で作っていきます。ぜんぶセルフサービスです。