use std::env;
fn main() {
println!("cargo:rerun-if-env-changed=CARGO_FEATURE_BEVY");
println!("cargo:rerun-if-env-changed=CARGO_FEATURE_DEBUG");
println!("cargo:rerun-if-env-changed=CARGO_FEATURE_PARKING_LOT");
println!("cargo:rerun-if-env-changed=CARGO_FEATURE_TRACY");
println!("cargo:rerun-if-env-changed=CARGO_FEATURE_NIGHTLY");
println!("cargo:rerun-if-env-changed=CARGO_FEATURE_MEMORY_FILTER");
let bevy_enabled = env::var("CARGO_FEATURE_BEVY").is_ok();
let debug_enabled = env::var("CARGO_FEATURE_DEBUG").is_ok();
let parking_lot_enabled = env::var("CARGO_FEATURE_PARKING_LOT").is_ok();
let tracy_enabled = env::var("CARGO_FEATURE_TRACY").is_ok();
let nightly_enabled = env::var("CARGO_FEATURE_NIGHTLY").is_ok();
let memory_filter_enabled = env::var("CARGO_FEATURE_MEMORY_FILTER").is_ok();
let profile = env::var("PROFILE").unwrap_or_else(|_| "unknown".to_string());
let is_release = profile == "release";
if bevy_enabled {
emit_info("Bevy integration enabled");
emit_note("Remember to add SmartAllocPlugin to your Bevy App:");
emit_note(" app.add_plugins(framealloc::bevy::SmartAllocPlugin::default())");
emit_note("");
emit_note("The plugin will:");
emit_note(" • Insert AllocResource as a Bevy resource");
emit_note(" • Reset frame arenas at frame boundaries");
emit_note(" • Work correctly with Bevy's parallel systems");
if let Ok(bevy_version) = env::var("DEP_BEVY_VERSION") {
emit_info(&format!("Detected Bevy version: {}", bevy_version));
}
}
if debug_enabled {
emit_info("Debug features enabled");
emit_note("Debug mode provides:");
emit_note(" • Memory poisoning (freed memory filled with 0xCD)");
emit_note(" • Allocation backtraces (for leak detection)");
emit_note(" • Extended validation checks");
if is_release {
emit_warning("Debug features enabled in release build!");
emit_note("This may impact performance. Consider disabling for production.");
}
} else if !is_release {
emit_note("Tip: Enable 'debug' feature for memory poisoning and allocation tracking:");
emit_note(" framealloc = { version = \"0.1\", features = [\"debug\"] }");
}
if parking_lot_enabled {
emit_info("Using parking_lot for mutexes (faster lock implementation)");
}
if tracy_enabled {
emit_info("Tracy profiler integration enabled");
emit_note("Use ProfilerHooks to connect to Tracy:");
emit_note(" let mut hooks = ProfilerHooks::new();");
emit_note(" hooks.set_callback(|event| { /* send to tracy */ });");
}
if nightly_enabled {
emit_info("Nightly features enabled (std::alloc::Allocator trait)");
emit_note("You can now use framealloc with standard collections:");
emit_note(" let frame_alloc = alloc.frame_allocator();");
emit_note(" let vec: Vec<u32, _> = Vec::new_in(frame_alloc);");
check_nightly_compiler();
}
if memory_filter_enabled {
emit_info("Memory behavior filter enabled (v0.4.0)");
emit_note("The behavior filter detects allocation pattern issues:");
emit_note(" • Frame allocations that survive too long (FA501, FA502)");
emit_note(" • Pool allocations used as scratch (FA510)");
emit_note(" • Excessive promotion churn (FA520)");
emit_note(" • Heap allocations in hot paths (FA530)");
emit_note("");
emit_note("Enable and check at runtime:");
emit_note(" alloc.enable_behavior_filter();");
emit_note(" // ... run your game loop ...");
emit_note(" let report = alloc.behavior_report();");
emit_note(" for issue in &report.issues { eprintln!(\"{}\", issue); }");
}
detect_async_runtime();
if is_release {
emit_info("Building in release mode");
if !parking_lot_enabled {
emit_note("Tip: Consider enabling 'parking_lot' for better mutex performance:");
emit_note(" framealloc = { version = \"0.1\", features = [\"parking_lot\"] }");
}
}
emit_separator();
emit_info("framealloc Quick Reference");
emit_separator();
emit_note("Frame allocation (fastest, reset per frame):");
emit_note(" alloc.begin_frame();");
emit_note(" let data = alloc.frame_box(value);");
emit_note(" alloc.end_frame();");
emit_note("");
emit_note("Pool allocation (small objects, auto-freed):");
emit_note(" let boxed = alloc.pool_box(value);");
emit_note("");
emit_note("Heap allocation (large objects, auto-freed):");
emit_note(" let large = alloc.heap_box(large_value);");
emit_separator();
check_target_features();
}
fn emit_info(msg: &str) {
println!("cargo:warning=[framealloc] ℹ️ {}", msg);
}
fn emit_note(msg: &str) {
if msg.is_empty() {
println!("cargo:warning=[framealloc]");
} else {
println!("cargo:warning=[framealloc] {}", msg);
}
}
fn emit_warning(msg: &str) {
println!("cargo:warning=[framealloc] ⚠️ {}", msg);
}
#[allow(dead_code)]
fn emit_error(msg: &str) {
println!("cargo:warning=[framealloc] ❌ {}", msg);
}
fn emit_separator() {
println!("cargo:warning=[framealloc] ────────────────────────────────────────");
}
fn check_nightly_compiler() {
if let Ok(rustc) = env::var("RUSTC") {
if let Ok(output) = std::process::Command::new(&rustc)
.arg("--version")
.output()
{
let version = String::from_utf8_lossy(&output.stdout);
if !version.contains("nightly") {
emit_warning("'nightly' feature enabled but compiler doesn't appear to be nightly!");
emit_note("The std::alloc::Allocator trait requires nightly Rust.");
emit_note("Install nightly: rustup install nightly");
emit_note("Use nightly: rustup override set nightly");
}
}
}
}
fn check_target_features() {
let target = env::var("TARGET").unwrap_or_default();
if target.contains("x86_64") {
if env::var("CARGO_CFG_TARGET_FEATURE").map(|f| f.contains("avx2")).unwrap_or(false) {
emit_info("AVX2 available - memory operations may be vectorized");
}
}
if target.contains("wasm") {
emit_warning("WebAssembly target detected");
emit_note("framealloc works on WASM but with some limitations:");
emit_note(" • No true threading (use single-threaded mode)");
emit_note(" • Memory budget may be constrained");
}
if target.contains("windows") {
emit_info("Building for Windows");
} else if target.contains("linux") {
emit_info("Building for Linux");
} else if target.contains("darwin") || target.contains("macos") {
emit_info("Building for macOS");
}
}
fn detect_async_runtime() {
let has_tokio = env::var("DEP_TOKIO_VERSION").is_ok()
|| std::path::Path::new("Cargo.lock").exists()
&& std::fs::read_to_string("Cargo.lock")
.map(|s| s.contains("name = \"tokio\""))
.unwrap_or(false);
let has_async_std = std::path::Path::new("Cargo.lock").exists()
&& std::fs::read_to_string("Cargo.lock")
.map(|s| s.contains("name = \"async-std\""))
.unwrap_or(false);
if has_tokio || has_async_std {
emit_separator();
emit_warning("Async runtime detected in project");
emit_note("Frame allocations are NOT safe across await points!");
emit_note("");
emit_note("⚠️ UNSAFE pattern:");
emit_note(" async fn bad(alloc: &SmartAlloc) {");
emit_note(" let data = alloc.frame_box(value); // Allocated here");
emit_note(" some_async_call().await; // Frame may reset!");
emit_note(" use_data(&data); // 💥 Use after free");
emit_note(" }");
emit_note("");
emit_note("✅ SAFE alternatives:");
emit_note(" • Use pool_box() or heap_box() for data crossing await");
emit_note(" • Use scratch_pool() for task-local scratch memory");
emit_note(" • Complete frame work before awaiting");
emit_separator();
}
}