Every launcher that calls the build stamp gets the 8 MB main stack (#2940)
The Windows main-thread reserve was set only in `crates/benilla/build.rs`. So `benilla-worldview`, and every launcher built on benilla by the recipe in `extended_launcher.rs`, linked with the linker's default: 1 MB on MSVC, 2 MB on mingw. That is less than the login screen needs. `benilla_buildstamp::emit()`, which every launcher's build script already calls, now asks for 8 MB through `rustc-link-arg`: `/STACK` on MSVC, `--stack` on mingw. Unlike `rustc-link-arg-bins`, cargo accepts it from a package with no binary, so a library that calls `emit()` still builds. The recipe and CONTRIBUTING's "Building on top" say so. Test, mingw cross-build: `SizeOfStackReserve` is 0x800000 for `benilla.exe` (unchanged) and `benilla-worldview.exe` (was 0x200000). A library-only crate calling `emit()` checks clean on MSVC and builds on mingw. Fixes #2934 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -10,8 +10,9 @@
|
||||
//! `AddOns/` folder in [`benilla_app::config_dir`], where an addon the crate ships is written.
|
||||
//!
|
||||
//! A crate of its own copies the `benilla` launcher (`crates/benilla`): a build script that stamps
|
||||
//! its commit, a `main` like this one that reads the stamp back as `crates/benilla/src/main.rs`
|
||||
//! does, and a manifest that takes benilla as the workspace does:
|
||||
//! its commit and gives its binary the 8 MB main-thread stack the app needs on Windows, a `main`
|
||||
//! like this one that reads the stamp back as `crates/benilla/src/main.rs` does, and a manifest
|
||||
//! that takes benilla as the workspace does:
|
||||
//!
|
||||
//! ```toml
|
||||
//! [features]
|
||||
@@ -45,7 +46,7 @@
|
||||
//! ```
|
||||
//!
|
||||
//! ```text
|
||||
//! // build.rs
|
||||
//! // build.rs: the stamp, and on Windows the main-thread stack of every binary in the package
|
||||
//! fn main() {
|
||||
//! benilla_buildstamp::emit();
|
||||
//! }
|
||||
|
||||
@@ -1,14 +1,20 @@
|
||||
//! The build stamp: the `build.rs` body the `benilla` and `benilla-worldview` launcher shims
|
||||
//! share. It stays a build-dependency of the shims, never of `benilla-app`: cargo rebuilds the
|
||||
//! package that owns a `rerun-if-changed` path whenever that path's mtime moves, and these paths
|
||||
//! move on every commit, rebase and checkout.
|
||||
//! share, and every launcher a crate on top builds the same way. It stays a build-dependency of
|
||||
//! the shims, never of `benilla-app`: cargo rebuilds the package that owns a `rerun-if-changed`
|
||||
//! path whenever that path's mtime moves, and these paths move on every commit, rebase and
|
||||
//! checkout.
|
||||
|
||||
use std::path::Path;
|
||||
use std::process::Command;
|
||||
|
||||
/// Stamp the commit this binary was built from into the calling package as six `rustc-env`
|
||||
/// vars, which its `main.rs` reads back with `env!` into a `BuildId`, beside its own
|
||||
/// `CARGO_PKG_VERSION`:
|
||||
/// The main thread's stack on Windows, in bytes: what Linux and macOS give it.
|
||||
const MAIN_THREAD_STACK: u32 = 8 << 20;
|
||||
|
||||
/// Stamp the commit this binary was built from into the calling package, and give its executables
|
||||
/// the main-thread stack the app needs on Windows.
|
||||
///
|
||||
/// The stamp is six `rustc-env` vars, which its `main.rs` reads back with `env!` into a
|
||||
/// `BuildId`, beside its own `CARGO_PKG_VERSION`:
|
||||
///
|
||||
/// - `BENILLA_GIT_SHA`: the full sha.
|
||||
/// - `BENILLA_GIT_SHORT`: git's own abbreviation of it.
|
||||
@@ -94,6 +100,34 @@ pub fn emit() {
|
||||
String::new()
|
||||
};
|
||||
println!("cargo::rustc-env=BENILLA_PROJECT_DIR={project}");
|
||||
|
||||
main_thread_stack();
|
||||
}
|
||||
|
||||
/// The app runs on the main thread, where the windowing event loop must live, and needs more than
|
||||
/// the 1 MB the MSVC linker reserves for it by default (2 MB on mingw): the login screen overflows
|
||||
/// it. So the package's Windows executables reserve [`MAIN_THREAD_STACK`] through
|
||||
/// `rustc-link-arg`, which cargo passes to every target it links and, unlike
|
||||
/// `rustc-link-arg-bins`, takes from a package that has no binary.
|
||||
fn main_thread_stack() {
|
||||
let os = std::env::var("CARGO_CFG_TARGET_OS").unwrap_or_default();
|
||||
let env = std::env::var("CARGO_CFG_TARGET_ENV").unwrap_or_default();
|
||||
if let Some(arg) = stack_link_arg(&os, &env) {
|
||||
println!("cargo::rustc-link-arg={arg}");
|
||||
}
|
||||
}
|
||||
|
||||
/// The linker's spelling of the main-thread reserve for a target: `/STACK` on MSVC, `--stack`
|
||||
/// through the compiler driver on mingw; none off Windows, where the system gives 8 MB already.
|
||||
fn stack_link_arg(target_os: &str, target_env: &str) -> Option<String> {
|
||||
if target_os != "windows" {
|
||||
return None;
|
||||
}
|
||||
match target_env {
|
||||
"msvc" => Some(format!("/STACK:{MAIN_THREAD_STACK}")),
|
||||
"gnu" => Some(format!("-Wl,--stack,{MAIN_THREAD_STACK}")),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// The workspace root of the package at `manifest_dir`: the nearest folder up from it holding
|
||||
@@ -135,6 +169,23 @@ mod tests {
|
||||
std::fs::remove_dir_all(&bare).ok();
|
||||
}
|
||||
|
||||
/// A Windows binary reserves 8 MB for its main thread in the linker's own spelling; no other
|
||||
/// target is asked to.
|
||||
#[test]
|
||||
fn a_windows_binary_reserves_the_main_threads_8_mb() {
|
||||
assert_eq!(
|
||||
stack_link_arg("windows", "msvc").as_deref(),
|
||||
Some("/STACK:8388608")
|
||||
);
|
||||
assert_eq!(
|
||||
stack_link_arg("windows", "gnu").as_deref(),
|
||||
Some("-Wl,--stack,8388608")
|
||||
);
|
||||
for (os, env) in [("macos", ""), ("linux", "gnu"), ("windows", "")] {
|
||||
assert_eq!(stack_link_arg(os, env), None, "{os} {env}");
|
||||
}
|
||||
}
|
||||
|
||||
/// benilla's own launchers stamp the checkout, the folder a dev build always used.
|
||||
#[test]
|
||||
fn a_launcher_in_this_checkout_stamps_the_checkout() {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
//! Stamps the commit this binary was built from.
|
||||
//! Stamps the commit this binary was built from, and gives the main thread the stack the app needs
|
||||
//! on Windows.
|
||||
|
||||
fn main() {
|
||||
benilla_buildstamp::emit();
|
||||
|
||||
+2
-17
@@ -1,21 +1,6 @@
|
||||
//! Stamps the commit this binary was built from, and gives the main thread the stack the app needs.
|
||||
//! Stamps the commit this binary was built from, and gives the main thread the stack the app needs
|
||||
//! on Windows.
|
||||
|
||||
fn main() {
|
||||
benilla_buildstamp::emit();
|
||||
main_thread_stack();
|
||||
}
|
||||
|
||||
/// The app runs on the main thread, where the windowing event loop must live, and needs more than
|
||||
/// the 1 MB the MSVC linker reserves for it by default (2 MB on mingw): the login screen overflows
|
||||
/// it. Linux and macOS give the main thread 8 MB, so Windows reserves the same.
|
||||
fn main_thread_stack() {
|
||||
const STACK: u32 = 8 << 20;
|
||||
if std::env::var("CARGO_CFG_TARGET_OS").as_deref() != Ok("windows") {
|
||||
return;
|
||||
}
|
||||
match std::env::var("CARGO_CFG_TARGET_ENV").as_deref() {
|
||||
Ok("msvc") => println!("cargo:rustc-link-arg-bins=/STACK:{STACK}"),
|
||||
Ok("gnu") => println!("cargo:rustc-link-arg-bins=-Wl,--stack,{STACK}"),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,10 +40,11 @@ taken.
|
||||
A feature 1.12.1 does not have lives in a crate of its own that adds its Bevy plugins through
|
||||
`benilla_app::run_with`, as `crates/benilla-app/examples/extended_launcher.rs` shows, or in a
|
||||
fork. A client started through `run_with` says `extended` in its build line, so its reports read
|
||||
apart from stock benilla's. The crate keeps its own settings, never rows in benilla's CVar table,
|
||||
which every addon reads, and its files go under `benilla_app::config_dir()`, its own
|
||||
`benilla-config/`: an addon it ships is written into that folder's `AddOns/` and loads as any
|
||||
addon does.
|
||||
apart from stock benilla's. Its build script calls `benilla_buildstamp::emit()`, which stamps the
|
||||
commit that line names and gives its binary the 8 MB main-thread stack the app needs on Windows.
|
||||
The crate keeps its own settings, never rows in benilla's CVar table, which every addon reads,
|
||||
and its files go under `benilla_app::config_dir()`, its own `benilla-config/`: an addon it ships
|
||||
is written into that folder's `AddOns/` and loads as any addon does.
|
||||
|
||||
Past `run_with` and that folder, benilla opens a piece of itself to such a crate only when its own
|
||||
1.12.1 work creates that piece, never for the crate alone, and promises no stable API: a crate
|
||||
|
||||
Reference in New Issue
Block a user