Ubuntu(WSL)上からWindows(msvc)のBevyアプリケーションのビルド&実行
WSL上のUbuntu24.04からWindows向けbevyアプリケーションをビルドし、実行するまでのなんやかや
ここでは Unofficial Bevy Cheat Book の下記にある手順をベースに、いくつかの改善や問題への対策を記録しておく。 https://bevy-cheatbook.github.io/setup/cross/linux-windows.html
x86_64-pc-windows-msvc を使うパターンの話。
x86_64-pc-windows-gnu を使う場合はいろいろ異なる。
出くわす問題:
- ビルド環境作り
- 開発環境の引っ越し時苦労しないよう、リポジトリ内に手順や設定を詰め込んでおく
- target/debug下のwindowsのbevyアプリとassetsパス
- ビルド成果物のexeは target/下に配置されるが、
assets/はexeと同じ位置にコピーされるわけではない。 bevy はデフォルトでは同ディレクトリのassets/にアクセスするため、exe実行に際してなんらかの対処が必要になる。
- ビルド成果物のexeは target/下に配置されるが、
ビルド環境作り
リンカが必要(だったはず)。
lld使う場合: lldインストール( apt install lld )して .cargo/config.toml に下記書いておけば cargo build --target x86_64-pc-windows-msvc としたとき適用される。
[target.x86_64-pc-windows-msvc]
linker = "lld-link"
リンク対象となるWindows SDK のインストールを行う必要がある。 その際 Microsoftのライセンスを受け入れる必要あり。
インストールは xwin を使うと楽なので、これを使うことにする。しかし xwin のインストール、 xwin による SDKインストール後SDKのパスをリンカに渡せるようにする、などの必要がある。
ここでは build.rs を用いて半自動化する。以下は Geminiくんに作ってもらった build.rs。
XWIN_CACHE_DIRが設定されていない場合、インストール手順を表示して終了する。- 手順通りやればSDKがインストールされる。インストール先はユーザ指定(例:
/home/<user>/.xwin)可能とし、ユーザがXWIN_CACHE_DIRにパスを格納する前提としている。
- 手順通りやればSDKがインストールされる。インストール先はユーザ指定(例:
XWIN_CACHE_DIRをもとに リンカに必要なパス設定を行う。- 一応パスが不正ならWarning表示(
panic!の方がよいかも?)
- 一応パスが不正ならWarning表示(
// build.rs
fn main() {
let target = std::env::var("TARGET").unwrap_or_default();
// Windows MSVC ターゲットのみ対象
if target.contains("msvc") {
// 1. 環境変数のチェック
let xwin_cache_env = "XWIN_CACHE_DIR";
let xwin_path = match std::env::var(xwin_cache_env) {
Ok(path) => path,
Err(_) => {
// 環境変数が設定されていない場合、エラーメッセージを表示して終了
panic!(
"\n\n[Error] xwin のパスが設定されていません。\n\
以下の手順でセットアップを行ってください:\n\n\
1. xwin をインストール (未実行の場合):\n\
cargo install xwin\n\n\
2. MSVC SDK をダウンロード・展開:\n\
xwin --accept-license splat --output /path/to/xwin-data\n\n\
3. 環境変数をセット:\n\
export {}=/path/to/xwin-data\n\n\
注意: /path/to/xwin-data は絶対パスを指定してください。\n",
xwin_cache_env
);
}
};
// 2. ターゲットアーキテクチャの判定
let arch = if target.contains("x86_64") {
"x86_64"
} else if target.contains("aarch64") {
"aarch64"
} else {
"x86"
};
// 3. リンカパスの指定
// xwin splat 後のディレクトリ構造 (sdk/lib/um, sdk/lib/ucrt, crt/lib)
let lib_dirs = [
format!("{}/sdk/lib/um/{}", xwin_path, arch),
format!("{}/sdk/lib/ucrt/{}", xwin_path, arch),
format!("{}/crt/lib/{}", xwin_path, arch),
];
for dir in &lib_dirs {
// ディレクトリの存在チェック(オプション)
if !std::path::Path::new(dir).exists() {
println!("cargo:warning=Directory not found: {}", dir);
}
println!("cargo:rustc-link-search=native={}", dir);
}
// 変更を検知するための再ビルドトリガー
println!("cargo:rerun-if-env-changed={}", xwin_cache_env);
}
}
以上の準備後、 cargo build --target x86_64-pc-windows-msvc にてビルド可能になる。
target/debug下のwindowsのbevyアプリとassetsパス
ビルド成果物のexeは target/下に配置されるが、 assets/ はexeと同じ位置にコピーされるわけではない。
bevy はデフォルトでは同ディレクトリの assets/ にアクセスするため、exe実行に際してなんらかの対処が必要になる。
実行時に exe を assets/ と同じディレクトリへコピーすることでも実行可能だが、
exeのサイズはそれなりに(MSVCなら150Mbytesくらい、GNUなら1GBytes超えたはず)大きくなるため避けたい。
AssetPlugin はアセットのディレクトリパスを指定可能 ( file_path ) であるため、
実行時にパスを書き換えられるようにする方法がある。
下記は環境変数 ASSETS_DIR が設定されている場合、
そのパスを file_path に設定するコード例。
fn main() {
let asset_root_path = std::env::var("ASSETS_DIR").unwrap_or("assets".into());
App::new()
.add_plugins((
DefaultPlugins.set(AssetPlugin {
file_path: asset_root_path,
..Default::default()
}),
))
// ...
.run();
}
これでexeの移動を行わず、代わりに assets パスを指定することでに実行可能になる。
例えばcargo workspace 下のプロジェクトappのルートディレクトリにてdevelopmentビルド→実行するコマンド例。
$ cargo build --target x86_64-pc-windows-msvc
$ ASSETS_DIR="$(pwd)/assets" WSLENV=ASSETS_DIR/p ../target/x86_64-pc-windows-msvc/debug/app.exe
blake3
下記のようなエラーが起こった場合、 blakc3 の feature に pure を指定することで回避できる。
warning: blake3@1.8.3: GNU compiler is not supported for this target
warning: blake3@1.8.3: GNU compiler is not supported for this target
warning: blake3@1.8.3: The C compiler "cc" does not support /arch:AVX512.
warning: blake3@1.8.3: GNU compiler is not supported for this target
error: failed to run custom build command for `blake3 v1.8.3`
Caused by:
process didn't exit successfully: `/home/mori/repos/bevy/learn-shader/target/debug/build/blake3-e4e57048ce5a5c89/build-script-build` (exit status: 1)
--- stdout
cargo:rustc-check-cfg=cfg(blake3_sse2_ffi, values(none()))
cargo:rustc-check-cfg=cfg(blake3_sse2_rust, values(none()))
cargo:rustc-check-cfg=cfg(blake3_sse41_ffi, values(none()))
cargo:rustc-check-cfg=cfg(blake3_sse41_rust, values(none()))
cargo:rustc-check-cfg=cfg(blake3_avx2_ffi, values(none()))
cargo:rustc-check-cfg=cfg(blake3_avx2_rust, values(none()))
cargo:rustc-check-cfg=cfg(blake3_avx512_ffi, values(none()))
cargo:rustc-check-cfg=cfg(blake3_neon, values(none()))
cargo:rustc-check-cfg=cfg(blake3_wasm32_simd, values(none()))
cargo:rerun-if-env-changed=CARGO_FEATURE_PURE
cargo:rerun-if-env-changed=CARGO_FEATURE_NO_NEON
OUT_DIR = Some(/home/mori/repos/bevy/learn-shader/target/x86_64-pc-windows-msvc/debug/build/blake3-b69351efbd66771c/out)
TARGET = Some(x86_64-pc-windows-msvc)
CARGO_ENCODED_RUSTFLAGS = Some()
VCINSTALLDIR = None
HOST = Some(x86_64-unknown-linux-gnu)
CC_x86_64-pc-windows-msvc = None
CC_x86_64_pc_windows_msvc = None
TARGET_CC = None
CC = None
CROSS_COMPILE = None
RUSTC_LINKER = Some(lld-link)
cargo:rerun-if-env-changed=CC_ENABLE_DEBUG_OUTPUT
RUSTC_WRAPPER = None
cargo:warning=GNU compiler is not supported for this target
OUT_DIR = Some(/home/mori/repos/bevy/learn-shader/target/x86_64-pc-windows-msvc/debug/build/blake3-b69351efbd66771c/out)
cargo:rerun-if-env-changed=CC_ENABLE_DEBUG_OUTPUT
CRATE_CC_NO_DEFAULTS = None
TARGET = Some(x86_64-pc-windows-msvc)
CARGO_CFG_TARGET_FEATURE = Some(cmpxchg16b,fxsr,sse,sse2,sse3)
HOST = Some(x86_64-unknown-linux-gnu)
CFLAGS = None
TARGET_CFLAGS = None
CFLAGS_x86_64_pc_windows_msvc = None
CFLAGS_x86_64-pc-windows-msvc = None
OPT_LEVEL = Some(0)
cargo:warning=GNU compiler is not supported for this target
CRATE_CC_NO_DEFAULTS = None
DEBUG = Some(true)
CARGO_CFG_TARGET_FEATURE = Some(cmpxchg16b,fxsr,sse,sse2,sse3)
CFLAGS = None
TARGET_CFLAGS = None
CFLAGS_x86_64_pc_windows_msvc = None
CFLAGS_x86_64-pc-windows-msvc = None
cargo:warning=The C compiler "cc" does not support /arch:AVX512.
cargo:rerun-if-env-changed=BLAKE3_CI
cargo:rerun-if-env-changed=CARGO_FEATURE_PREFER_INTRINSICS
cargo:rerun-if-env-changed=CARGO_FEATURE_PURE
cargo:rustc-cfg=blake3_sse2_ffi
cargo:rustc-cfg=blake3_sse41_ffi
cargo:rustc-cfg=blake3_avx2_ffi
OUT_DIR = Some(/home/mori/repos/bevy/learn-shader/target/x86_64-pc-windows-msvc/debug/build/blake3-b69351efbd66771c/out)
OPT_LEVEL = Some(0)
TARGET = Some(x86_64-pc-windows-msvc)
CARGO_ENCODED_RUSTFLAGS = Some()
VCINSTALLDIR = None
HOST = Some(x86_64-unknown-linux-gnu)
CC_x86_64-pc-windows-msvc = None
CC_x86_64_pc_windows_msvc = None
TARGET_CC = None
CC = None
CROSS_COMPILE = None
RUSTC_LINKER = Some(lld-link)
cargo:rerun-if-env-changed=CC_ENABLE_DEBUG_OUTPUT
RUSTC_WRAPPER = None
cargo:warning=GNU compiler is not supported for this target
CRATE_CC_NO_DEFAULTS = None
DEBUG = Some(true)
CARGO_CFG_TARGET_FEATURE = Some(cmpxchg16b,fxsr,sse,sse2,sse3)
CFLAGS = None
TARGET_CFLAGS = None
CFLAGS_x86_64_pc_windows_msvc = None
CFLAGS_x86_64-pc-windows-msvc = None
--- stderr
error occurred in cc-rs: failed to find tool "ml64.exe": No such file or directory (os error 2)
Cargo.toml に下記のように記載する。
[dependencies.blake3]
version = "1.8"
features = ["pure"]
CARGO_FEATURE_PURE=1 を cargo build --target x86_64-pc-windows-msvc 時に指定することでも回避可能らしい。