1
0

More than 1 year has passed since last update.

ラストのまほう 第18話『WASM-4のビルドとカートリッジサイズの最適化』

Last updated at Posted at 2022-12-17

ソフトウェアの開発ではビルドやデプロイの手順を頻繁に確認しておくことは大事です。「完成しました、さあデプロイしましょう」となったところで何か重大な問題が発覚してデプロイできない、なんてことになったら大変ですから。

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.tomllto = trueopt-level = "z"の設定をしろみたいにGitHubのIssueかどこかに書いてあったので、確認してみます。またdebug = trueになっていたので、debug = falseに変えてみます。

Cargo.toml
[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!マクロなどが使えなくなるんですね……。つら……。

参考文献

次回予告

次回はいわゆる「グラフィックコンテキスト」を自力で作っていきます。ぜんぶセルフサービスです。

1
0
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
1
0