おはこんばんにちは!
タグで 3 OS ビルド では、
card_capture など ターミナルゲーム向けに cargo build --release の生バイナリ を Artifact に載せる話を書きました。
TBH Skill Simulator は egui / eframe の GUI アプリ です。
配布物も「実行ファイル 1 個」ではなく、.deb / .app / .exe(アイコン・メタデータ付き) にしたくなりました。
そこで cargo-bundle を足し、 GitHub Actions の workflow も bundle 出力向け に載せ替えています。
ゲームルールや egui UI の話は TBH Skill Simulator に任せ、 ここでは GUI 配布インフラだけ を書きます。
- 例としてのリポジトリ: yoshitaka-k/tbh_skill_simulator
- ワークフロー:
.github/workflows/build.yml

▲ v* タグ push 後。linux(deb)/ macos(app)/ windows(exe)の 3 job が並んでいる状態。
なぜ CLI のタグビルドと分けたか
| 観点 | CLI 版(card_capture 等) | GUI 版(TBH Skill Simulator) |
|---|---|---|
| アプリ種別 | CLI / TUI | GUI(eframe) |
| ビルド | cargo build --release |
cargo bundle --release |
| Linux 成果物 | 生バイナリ | .deb パッケージ |
| macOS 成果物 | 生バイナリ | .app バンドル |
| Windows 成果物 | .exe 1 ファイル |
アイコン埋め込み exe |
| Cargo.toml | [profile.release] |
[package.metadata.bundle] 等 |
CLI 版の「タグ → 3 OS マトリクス → Artifact」という骨格は同じです。 成果物の形と Cargo 設定が別物 なので、シリーズを分けました。
| シリーズ | 中身 |
|---|---|
| タグで 3 OS ビルド | CLI/TUI の生バイナリ配布 |
| cargo-bundle | GUI の cargo-bundle 配布 |
追加・変更したファイル
tbh_skill_simulator/ Cargo.toml … [package.metadata.bundle] / winresource build.rs … Windows ICO 埋め込み(既存 codegen に追加) bundle.sh … ローカル bundle 用 .github/workflows/build.yml … cargo bundle + Artifact
card_capture の CI から流用したのは タグトリガー・3 OS マトリクス・MinGW クロスビルド です。
cargo build を cargo bundle に差し替え、Artifact の path を release/bundle/** に変えたのが主な差分です。
[package.metadata.bundle] — cargo-bundle の設定
[package.metadata.bundle] identifier = "jp.ktgwya.tbh-skill-simulator" name = "TBH Skill Simulator" icon = ["assets/icon.png"] category = "Game" short_description = "Skill build simulator for TBH" linux_use_terminal = false deb_depends = [ "libgtk-3-0", "libxcb-render0", "libxcb-shape0", "libxcb-xfixes0", "libxkbcommon0", "libvulkan1", "libssl3", ]
| キー | 意味 |
|---|---|
identifier |
macOS / Linux のアプリ ID |
icon |
バンドル用アイコン(PNG) |
linux_use_terminal |
false — GUI アプリとして .desktop を生成 |
deb_depends |
.deb インストール時に要求する システムライブラリ |
eframe / wgpu 系は Linux で GTK や XCB、Vulkan 等に依存します。
CLI ゲームには不要だった deb_depends の列挙 が GUI 版の追加コストです。
Windows 向け exe の表示名は別セクションです。
[package.metadata.winresource] ProductName = "TBH Skill Simulator" FileDescription = "Skill build simulator for TBH" OriginalFilename = "TBH Skill Simulator.exe"
winresource クレート(build-dependencies)と組み合わせて、
エクスプローラ上のプロパティに載る文字列を指定しています。
build.rs — PNG から ICO を生成して exe に埋め込む
cargo-bundle の icon は macOS / Linux 向けです。
Windows の exe アイコン は build.rs で別途埋め込みます。
fn embed_windows_resources(manifest_dir: &Path, out_dir: &Path) { if env::var("CARGO_CFG_TARGET_OS").ok().as_deref() != Some("windows") { return; } let png_path = manifest_dir.join("assets/icon.png"); let ico_path = out_dir.join("app.ico"); write_ico_from_png(&png_path, &ico_path); winresource::WindowsResource::new() .set_icon(ico_path.to_str().expect("invalid ico path")) .compile() .expect("failed to compile Windows resources"); }
PNG 1 枚から複数サイズの ICO を作ります。
for size in [256, 128, 64, 48, 32, 16] { let rgba = image .resize_exact(size, size, image::imageops::FilterType::Lanczos3) .to_rgba8(); // ... }
| タイミング | 対象 OS | やること |
|---|---|---|
build.rs |
Windows のみ | exe リソースに ICO 埋め込み |
cargo bundle -f osx |
macOS | .app に PNG アイコン |
cargo bundle -f deb |
Linux | .deb にデスクトップエントリ + アイコン |
TBH 2 本目 の JSON codegen と 同じ build.rs に同居しています。
CARGO_CFG_TARGET_OS で Windows ビルド時だけ ICO 生成が走るので、Linux/macOS の CI には影響しません。
GitHub Actions — CLI 版からの差分
トリガーとマトリクスは タグで 3 OS ビルド と同型です。
on: push: tags: - 'v*' workflow_dispatch:
cargo-bundle のインストール
- name: Install cargo-bundle run: cargo install cargo-bundle --locked
CLI 版では不要だったステップです。CI ごとに cargo install するので、初回ビルドはやや長く なります。
OS ごとに bundle 形式を切り替え
- name: Build and bundle run: | case "${{ matrix.job.target }}" in x86_64-pc-windows-gnu) cargo bundle --release --target x86_64-pc-windows-gnu -f exe # cargo-bundle 0.11.0 が .exe を二重付けするため修正 for f in target/x86_64-pc-windows-gnu/release/bundle/exe/*.exe.exe; do mv "$f" "${f%.exe}" done ;; x86_64-unknown-linux-gnu) cargo bundle --release --target x86_64-unknown-linux-gnu -f deb ;; x86_64-apple-darwin) cargo bundle --release --target x86_64-apple-darwin -f osx ;; esac
| target | -f |
出力例 |
|---|---|---|
x86_64-pc-windows-gnu |
exe |
bundle/exe/TBH Skill Simulator.exe |
x86_64-unknown-linux-gnu |
deb |
bundle/deb/tbh-skill-simulator_0.1.3_amd64.deb |
x86_64-apple-darwin |
osx |
bundle/osx/TBH Skill Simulator.app |
CLI 版の cargo build + 生バイナリ path 指定から、release/bundle/**/* 丸ごと に変わります。
- name: Upload Artifact uses: actions/upload-artifact@v4 with: name: ${{ github.event.repository.name }}-${{ github.ref_name }}-${{ matrix.job.artifact-name }} path: | target/${{ matrix.job.target }}/release/bundle/**/* if-no-files-found: error
GUI 版は bundle が空だと配布不能なので、if-no-files-found: error にしています。
CLI 版の ignore は「Linux job に .exe path がなくても落ちない」ための保険でしたが、
bundle 方式では 各 OS とも bundle ディレクトリが必須 です。
.exe.exe 二重付けの workaround
cargo-bundle 0.11.0 では、Windows クロスビルド時に Something.exe.exe になることがあります。
for f in target/x86_64-pc-windows-gnu/release/bundle/exe/*.exe.exe; do
mv "$f" "${f%.exe}"
done
CI 内でリネームしてから Artifact に載せています。
upstream の修正を待つ間の 実務的な回避 です。
ローカル確認 — bundle.sh
CI 以外で bundle を試す用のシェルスクリプトです。
# Windows(MinGW が必要) cargo bundle --release --target x86_64-pc-windows-gnu -f exe # Linux cargo bundle --release -f deb sudo dpkg -i target/release/bundle/deb/tbh-skill-simulator_*.deb
Linux では dpkg -i まで一気に試せます。
macOS 向け -f osx は CI(macos-latest runner)側で確認する想定です。

▲ Ubuntu 等で .deb インストール後、アプリランチャーに TBH Skill Simulator が載っている状態。
CLI 版との対応表(コピペ用)
| 項目 | CLI 版 | GUI 版 |
|---|---|---|
| ビルドコマンド | cargo build --release --target … |
cargo bundle --release --target … -f … |
| 追加 install | なし | cargo install cargo-bundle |
| Cargo.toml | [profile.release] |
[package.metadata.bundle] + winresource |
| build.rs | なし(または codegen のみ) | + Windows ICO 埋め込み |
| Artifact path | target/.../release/バイナリ |
target/.../release/bundle/**/* |
| Linux 依存 | 動的リンクなし想定 | deb_depends 必須 |
タグ運用(git tag v0.1.3 && git push origin v0.1.3)と Artifact 命名規則は CLI 版と同じです。
Releases 自動作成も、現状は 手動添付 のままです。
設計で意識したこと
1. CLI 版の workflow をベースに差し替え
3 OS マトリクスと MinGW クロスビルドは実績のある構成をそのまま使い、 ビルドコマンドと Artifact path だけ GUI 向け に変えました。
2. アイコンは「実行ファイル」と「バンドル」で二系統
- 実行中のウィンドウアイコン →
main.rsのinclude_bytes!+with_icon - 配布物のアイコン →
metadata.bundle+ Windows はbuild.rsの ICO
同じ assets/icon.png を源に、用途ごとに変換しています。
3. Linux は deb、macOS は app
「バイナリを tarball で渡す」より、各 OS の慣習に近い形 を選びました。 個人ツールでも、初めて GUI を配るなら cargo-bundle の方が楽でした。
4. GUI 記事とインフラ記事を分離
TBH Skill Simulator 読者が
突然 deb_depends に遭遇しないよう、bundle / CI はこちらに集約しています。
動かしてみる
git clone https://github.com/yoshitaka-k/tbh_skill_simulator.git cd tbh_skill_simulator # ローカル(Linux 例) cargo install cargo-bundle --locked cargo bundle --release -f deb ls target/release/bundle/deb/ # CI と同じタグ運用 git tag v0.1.3 git push origin v0.1.3 # → Actions から deb / app / exe を Artifact ダウンロード
確認ポイント:
- 3 job すべて
bundle/以下にファイルができるか - Windows Artifact の exe が
.exe.exeになっていないか - Linux deb を
dpkg -iしたあと GUI が起動するか - exe のプロパティにアイコンと ProductName が載るか
まとめ
TBH Skill Simulator の GUI 配布は次のとおりです。
cargo-bundle— OS ごとに deb / osx / exe 形式で出力[package.metadata.bundle]— アイコン・deb 依存・GUI フラグbuild.rs+ winresource — Windows exe へ ICO 埋め込み- GitHub Actions — CLI 版と同型マトリクス + bundle path
.exe.exeリネーム — cargo-bundle 0.11.0 の暫定対処
CLI/TUI 向けタグビルドの延長として、GUI アプリ用の bundle レイヤ を足した形です。
関連記事
- タグで 3 OS ビルド(CLI 版)
- TBH Skill Simulator 3 本目: eframe 起動と永続化
- TBH Skill Simulator 2 本目: build.rs codegen