use std::env;
use std::process::Command;
fn main() {
println!("cargo:rerun-if-changed=build.rs");
validate_platform_compatibility();
}
fn validate_platform_compatibility() {
let target_os = env::var("CARGO_CFG_TARGET_OS").unwrap_or_default();
let target_arch = env::var("CARGO_CFG_TARGET_ARCH").unwrap_or_default();
let target_env = env::var("CARGO_CFG_TARGET_ENV").unwrap_or_default();
let is_debug = env::var("DEBUG").unwrap_or_default() == "true";
match (target_os.as_str(), target_env.as_str(), target_arch.as_str()) {
("linux", "gnu", _) => {
if !can_use_mimalloc_on_linux() {
print_compilation_error_and_exit();
} else {
println!("cargo:warning=Auto-allocator: Linux GNU platform detected");
if is_debug {
println!("cargo:warning= → Will use system allocator (debug build)");
} else {
println!("cargo:warning= → Will use mimalloc (release build)");
}
}
}
("linux", "musl", _) => {
if !can_use_mimalloc_on_linux() {
print_compilation_error_and_exit();
} else {
println!("cargo:warning=Auto-allocator: Linux musl platform detected");
if is_debug {
println!("cargo:warning= → Will use system allocator (debug build)");
} else {
println!("cargo:warning= → Will use mimalloc (release build)");
}
}
}
_ => {
print_platform_info(target_os.as_str(), target_env.as_str(), target_arch.as_str(), is_debug);
}
}
}
fn can_use_mimalloc_on_linux() -> bool {
if !has_stdatomic_header() {
return false;
}
if let Some(gcc_version) = get_gcc_version() {
if gcc_version < 49 { return false;
}
}
true
}
fn has_stdatomic_header() -> bool {
let test_program = r#"
#include <stdatomic.h>
int main() {
atomic_int x = ATOMIC_VAR_INIT(0);
return atomic_load(&x);
}
"#;
match std::process::Command::new("cc")
.arg("-c")
.arg("-o")
.arg("/dev/null")
.arg("-x")
.arg("c")
.arg("-")
.stdin(std::process::Stdio::piped())
.stdout(std::process::Stdio::null())
.stderr(std::process::Stdio::null())
.spawn()
{
Ok(mut child) => {
if let Some(mut stdin) = child.stdin.take() {
use std::io::Write;
let _ = stdin.write_all(test_program.as_bytes());
}
child.wait().map(|status| status.success()).unwrap_or(false)
}
Err(_) => false, }
}
fn print_compilation_error_and_exit() {
eprintln!();
eprintln!("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
eprintln!("❌ AUTO-ALLOCATOR COMPILATION ERROR");
eprintln!("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
eprintln!();
eprintln!("🚫 Cannot compile on this system: mimalloc requires modern GCC with stdatomic.h");
eprintln!();
if let Some(gcc_version) = get_gcc_version() {
eprintln!("📊 System Information:");
eprintln!(" • Detected GCC version: {}.x", gcc_version / 10);
eprintln!(" • Required GCC version: 4.9+");
eprintln!(" • stdatomic.h available: {}", if has_stdatomic_header() { "✅ Yes" } else { "❌ No" });
} else {
eprintln!("📊 System Information:");
eprintln!(" • GCC compiler: Not detected or not available");
eprintln!(" • stdatomic.h available: {}", if has_stdatomic_header() { "✅ Yes" } else { "❌ No" });
}
eprintln!();
eprintln!("ℹ️ Note: You may see additional 'libmimalloc-sys' compilation errors below.");
eprintln!(" This is expected - the same stdatomic.h issue affects mimalloc compilation.");
eprintln!();
eprintln!("💡 Solutions to fix this issue:");
eprintln!();
eprintln!(" 🔧 Option 1 - Upgrade GCC (Recommended):");
eprintln!(" CentOS 7: sudo yum install -y centos-release-scl devtoolset-11-gcc");
eprintln!(" Then: source /opt/rh/devtoolset-11/enable");
eprintln!(" Ubuntu: sudo apt-get install gcc-9");
eprintln!();
eprintln!(" 🔄 Option 2 - Upgrade OS:");
eprintln!(" CentOS 7 → CentOS 8+ / RHEL 8+ / Rocky Linux 8+");
eprintln!(" Ubuntu 16.04 → Ubuntu 18.04+");
eprintln!();
eprintln!(" ⚡ Option 3 - Use system allocator:");
eprintln!(" Remove auto-allocator and use Rust's default system allocator");
eprintln!(" (No performance benefits, but maximum compatibility)");
eprintln!();
eprintln!("🎯 Why this matters:");
eprintln!(" auto-allocator provides 1.6x faster allocation performance, but requires");
eprintln!(" modern compiler support. Legacy systems cannot benefit from this optimization.");
eprintln!();
eprintln!("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
std::process::exit(1);
}
fn print_platform_info(target_os: &str, target_env: &str, target_arch: &str, is_debug: bool) {
if target_os == "none" {
println!("cargo:warning=Auto-allocator: Embedded platform detected ({})", target_arch);
println!("cargo:warning= → Will use embedded-alloc for resource optimization");
return;
}
match (target_os, target_env, target_arch) {
(_, _, "wasm32") => {
println!("cargo:warning=Auto-allocator: WASM platform detected");
println!("cargo:warning= → Will use system allocator for browser compatibility");
}
("android", _, _) => {
println!("cargo:warning=Auto-allocator: Android platform detected");
println!("cargo:warning= → Will use system allocator (Scudo) per Android security policy");
}
("ios", _, _) => {
println!("cargo:warning=Auto-allocator: iOS platform detected");
println!("cargo:warning= → Will use system allocator (libmalloc) per Apple recommendations");
}
("freebsd", _, _) | ("netbsd", _, _) => {
println!("cargo:warning=Auto-allocator: BSD platform detected ({})", target_os);
println!("cargo:warning= → Will use system allocator (native jemalloc)");
}
("openbsd", _, _) => {
println!("cargo:warning=Auto-allocator: OpenBSD platform detected");
println!("cargo:warning= → Will use system allocator (security-hardened)");
}
("solaris", _, _) | ("illumos", _, _) => {
println!("cargo:warning=Auto-allocator: Solaris platform detected ({})", target_os);
println!("cargo:warning= → Will use system allocator (libumem)");
}
("windows", "msvc", _) => {
println!("cargo:warning=Auto-allocator: Windows MSVC platform detected");
if is_debug {
println!("cargo:warning= → Will use system allocator (debug build)");
} else {
println!("cargo:warning= → Will use mimalloc (release build)");
}
}
("windows", "gnu", _) => {
println!("cargo:warning=Auto-allocator: Windows GNU platform detected");
if is_debug {
println!("cargo:warning= → Will use system allocator (debug build)");
} else {
println!("cargo:warning= → Will use mimalloc (release build)");
}
}
("macos", _, _) => {
println!("cargo:warning=Auto-allocator: macOS platform detected");
if is_debug {
println!("cargo:warning= → Will use system allocator (debug build)");
} else {
println!("cargo:warning= → Will use mimalloc (release build)");
}
}
_ => {
println!("cargo:warning=Auto-allocator: Unknown platform detected");
println!("cargo:warning= → Platform: {} env: {} arch: {}", target_os, target_env, target_arch);
println!("cargo:warning= → Will use system allocator (mimalloc not available on this platform)");
}
}
}
fn get_gcc_version() -> Option<u32> {
if let Ok(cc) = env::var("CC") {
if !cc.contains("gcc") {
return None;
}
}
let gcc_cmd = env::var("CC").unwrap_or_else(|_| "gcc".to_string());
let output = Command::new(&gcc_cmd).arg("--version").output().ok()?;
let version_str = String::from_utf8(output.stdout).ok()?;
for line in version_str.lines() {
if line.to_lowercase().contains("gcc") {
for part in line.split_whitespace() {
if let Some(version) = parse_version_number(part) {
return Some(version);
}
}
}
}
None
}
fn parse_version_number(s: &str) -> Option<u32> {
let parts: Vec<&str> = s.split('.').collect();
if parts.len() >= 2 {
if let (Ok(major), Ok(minor)) = (parts[0].parse::<u32>(), parts[1].parse::<u32>()) {
return Some(major * 10 + minor);
}
}
parts.first()?.parse::<u32>().ok().map(|v| v * 10)
}