use std::env;
use std::ffi::OsString;
use std::fs;
use std::path::PathBuf;
use std::process::Command;
const BINARY_MAGIC: &[u8; 8] = b"OXIWISDM";
const BINARY_FORMAT_VERSION: u16 = 1;
const ALGO_TAG_COOLEY_TUKEY: u8 = 0;
fn main() {
println!("cargo:rustc-check-cfg=cfg(oxifft_portable_simd)");
println!("cargo:rerun-if-env-changed=RUSTC_BOOTSTRAP");
let portable_simd_requested = env::var_os("CARGO_FEATURE_PORTABLE_SIMD").is_some();
if portable_simd_requested && feature_attrs_allowed() {
println!("cargo:rustc-cfg=oxifft_portable_simd");
}
let mpi_enabled = env::var("CARGO_FEATURE_MPI").is_ok();
let sve_enabled = env::var("CARGO_FEATURE_SVE").is_ok();
if mpi_enabled {
println!(
"cargo:warning=\
oxifft: the `mpi` feature links against the system MPI library (C/Fortran), \
which violates the Pure Rust policy for default builds. \
This feature is provided for distributed computing and is explicitly \
feature-gated. No pure-Rust MPI implementation currently exists. \
See https://github.com/cool-japan/oxifft/blob/master/README.md#mpi for details."
);
}
let _ = sve_enabled;
println!("cargo:rerun-if-env-changed=OXIFFT_TUNE");
println!("cargo:rerun-if-env-changed=OXIFFT_SKIP_TUNE");
let out_dir = PathBuf::from(env::var("OUT_DIR").expect("OUT_DIR must be set by Cargo"));
let baseline_path = out_dir.join("wisdom_baseline.bin");
let tune_requested = env::var("OXIFFT_TUNE").is_ok_and(|v| v == "1");
let tune_skipped = env::var("OXIFFT_SKIP_TUNE").is_ok_and(|v| v == "1");
let host = env::var("HOST").unwrap_or_default();
let target = env::var("TARGET").unwrap_or_default();
let cross_compiling = !host.is_empty() && !target.is_empty() && host != target;
let baseline = if tune_requested && !tune_skipped && !cross_compiling {
println!(
"cargo:warning=\
oxifft: OXIFFT_TUNE=1 — embedding a build-time wisdom baseline. For per-machine \
measured tuning, run `oxifft_tune` and import the result at runtime."
);
build_baseline_blob()
} else {
if tune_requested && cross_compiling {
println!(
"cargo:warning=\
oxifft: OXIFFT_TUNE=1 ignored for cross-compilation (host {host} != target {target}); \
writing empty wisdom baseline."
);
}
Vec::new()
};
fs::write(&baseline_path, &baseline).expect("failed to write wisdom_baseline.bin in OUT_DIR");
}
fn feature_attrs_allowed() -> bool {
if env::var_os("RUSTC_BOOTSTRAP").is_some() {
return true;
}
let rustc = env::var_os("RUSTC").unwrap_or_else(|| OsString::from("rustc"));
let Ok(output) = Command::new(rustc).arg("-vV").output() else {
return false;
};
if !output.status.success() {
return false;
}
let text = String::from_utf8_lossy(&output.stdout);
text.lines()
.find_map(|line| line.strip_prefix("release:"))
.map(str::trim)
.is_some_and(|release| release.contains("nightly") || release.contains("dev"))
}
fn build_baseline_blob() -> Vec<u8> {
let sizes: Vec<u64> = (1..=16).map(|k| 1u64 << k).collect();
let entry_count_u16 = u16::try_from(sizes.len()).unwrap_or(u16::MAX);
let entry_count = entry_count_u16 as usize;
let mut buf = Vec::with_capacity(16 + entry_count * 30);
buf.extend_from_slice(BINARY_MAGIC);
buf.extend_from_slice(&BINARY_FORMAT_VERSION.to_le_bytes());
buf.extend_from_slice(&entry_count_u16.to_le_bytes());
buf.extend_from_slice(&0u32.to_le_bytes());
for &size in sizes.iter().take(entry_count) {
buf.extend_from_slice(&size.to_le_bytes()); buf.push(ALGO_TAG_COOLEY_TUKEY); buf.push(0u8); buf.extend_from_slice(&[0u8; 12]); buf.extend_from_slice(&0u64.to_le_bytes()); }
buf
}