use std::env;
use std::process::Command;
fn main() {
println!("cargo:rerun-if-changed=build.rs");
println!("cargo:rerun-if-changed=Cargo.toml");
detect_and_configure_simd();
configure_target_specific_features();
configure_optimization_flags();
#[cfg(feature = "ffi")]
generate_ffi_bindings();
}
fn detect_and_configure_simd() {
let target_arch = env::var("CARGO_CFG_TARGET_ARCH").unwrap_or_default();
match target_arch.as_str() {
"x86_64" => detect_x86_features(),
"aarch64" => detect_arm_features(),
_ => {
println!("cargo:warning=SIMD optimizations not available for target architecture: {}", target_arch);
configure_scalar_fallback();
}
}
}
fn detect_x86_features() {
println!("cargo:rustc-cfg=target_arch_x86_64");
if cfg!(feature = "simd") {
println!("cargo:rustc-cfg=zipora_simd");
detect_x86_feature("sse2", true); detect_x86_feature("sse3", true);
detect_x86_feature("ssse3", true);
detect_x86_feature("sse4.1", true);
detect_x86_feature("sse4.2", true);
detect_x86_feature("popcnt", true);
detect_x86_feature("avx", true);
detect_x86_feature("avx2", true);
detect_x86_feature("bmi1", true);
detect_x86_feature("bmi2", true);
detect_x86_feature("lzcnt", true);
if cfg!(feature = "avx512") {
detect_x86_feature("avx512f", false);
detect_x86_feature("avx512vl", false);
detect_x86_feature("avx512bw", false);
detect_x86_feature("avx512dq", false);
detect_x86_feature("avx512cd", false);
detect_x86_feature("avx512vpopcntdq", false);
detect_x86_feature("avx512vbmi", false);
detect_x86_feature("avx512ifma", false);
}
}
if is_feature_available("bmi2") && is_feature_available("avx2") {
println!("cargo:rustc-cfg=zipora_optimization_tier_4");
} else if is_feature_available("bmi2") {
println!("cargo:rustc-cfg=zipora_optimization_tier_3");
} else if is_feature_available("popcnt") {
println!("cargo:rustc-cfg=zipora_optimization_tier_2");
} else {
println!("cargo:rustc-cfg=zipora_optimization_tier_1");
}
}
fn detect_arm_features() {
println!("cargo:rustc-cfg=target_arch_aarch64");
if cfg!(feature = "simd") {
println!("cargo:rustc-cfg=zipora_simd");
detect_arm_feature("neon", true);
detect_arm_feature("crc", false);
detect_arm_feature("crypto", false);
detect_arm_feature("sve", false);
detect_arm_feature("sve2", false);
if is_feature_available("sve2") {
println!("cargo:rustc-cfg=zipora_optimization_tier_3");
} else if is_feature_available("sve") || is_feature_available("crypto") {
println!("cargo:rustc-cfg=zipora_optimization_tier_2");
} else {
println!("cargo:rustc-cfg=zipora_optimization_tier_1");
}
}
}
fn detect_x86_feature(feature: &str, commonly_available: bool) {
if commonly_available || try_compile_with_feature(feature) {
let cfg_name = format!("zipora_has_{}", feature.replace(".", "_").replace("-", "_"));
println!("cargo:rustc-cfg={}", cfg_name);
if feature != "popcnt" { println!("cargo:rustc-env=RUSTFLAGS=-C target-feature=+{}", feature);
}
}
}
fn detect_arm_feature(feature: &str, commonly_available: bool) {
if commonly_available || try_compile_with_arm_feature(feature) {
let cfg_name = format!("zipora_has_{}", feature);
println!("cargo:rustc-cfg={}", cfg_name);
}
}
fn try_compile_with_feature(feature: &str) -> bool {
let test_code = format!(r#"
#[cfg(target_arch = "x86_64")]
fn test_feature() {{
#[cfg(target_feature = "{}")]
{{
// Feature is available at compile time
}}
}}
fn main() {{
test_feature();
}}
"#, feature);
compile_test_program(&test_code, &[&format!("target-feature=+{}", feature)])
}
fn try_compile_with_arm_feature(feature: &str) -> bool {
let test_code = format!(r#"
#[cfg(target_arch = "aarch64")]
fn test_feature() {{
#[cfg(target_feature = "{}")]
{{
// Feature is available at compile time
}}
}}
fn main() {{
test_feature();
}}
"#, feature);
compile_test_program(&test_code, &[&format!("target-feature=+{}", feature)])
}
fn compile_test_program(code: &str, flags: &[&str]) -> bool {
use std::fs;
use std::path::Path;
let out_dir = env::var("OUT_DIR").unwrap_or_else(|_| ".".to_string());
let test_file = Path::new(&out_dir).join("feature_test.rs");
if fs::write(&test_file, code).is_err() {
return false;
}
let mut cmd = Command::new("rustc");
cmd.arg(&test_file);
cmd.arg("-o").arg(Path::new(&out_dir).join("feature_test"));
for flag in flags {
cmd.arg("-C").arg(flag);
}
cmd.output().map(|output| output.status.success()).unwrap_or(false)
}
fn is_feature_available(feature: &str) -> bool {
let _cfg_name = format!("zipora_has_{}", feature.replace(".", "_").replace("-", "_"));
match feature {
"sse2" | "sse3" | "ssse3" | "sse4.1" | "sse4.2" | "popcnt" => true,
"avx" | "avx2" | "bmi1" | "bmi2" | "lzcnt" => {
true
}
"neon" => {
env::var("CARGO_CFG_TARGET_ARCH").unwrap_or_default() == "aarch64"
}
_ => false,
}
}
fn configure_scalar_fallback() {
println!("cargo:rustc-cfg=zipora_scalar_only");
println!("cargo:rustc-cfg=zipora_optimization_tier_0");
}
fn configure_target_specific_features() {
let target_arch = env::var("CARGO_CFG_TARGET_ARCH").unwrap_or_default();
let target_os = env::var("CARGO_CFG_TARGET_OS").unwrap_or_default();
match (target_arch.as_str(), target_os.as_str()) {
("x86_64", "linux") => {
println!("cargo:rustc-cfg=zipora_linux_x86_64");
println!("cargo:rustc-link-lib=pthread");
}
("x86_64", "windows") => {
println!("cargo:rustc-cfg=zipora_windows_x86_64");
}
("x86_64", "macos") => {
println!("cargo:rustc-cfg=zipora_macos_x86_64");
}
("aarch64", "linux") => {
println!("cargo:rustc-cfg=zipora_linux_aarch64");
println!("cargo:rustc-link-lib=pthread");
}
("aarch64", "macos") => {
println!("cargo:rustc-cfg=zipora_macos_aarch64");
}
_ => {
println!("cargo:warning=Unoptimized target: {}-{}", target_arch, target_os);
}
}
match target_arch.as_str() {
"x86_64" => println!("cargo:rustc-cfg=zipora_cache_line_64"),
"aarch64" => println!("cargo:rustc-cfg=zipora_cache_line_64"),
_ => println!("cargo:rustc-cfg=zipora_cache_line_64"), }
}
fn configure_optimization_flags() {
let profile = env::var("PROFILE").unwrap_or_default();
match profile.as_str() {
"release" => {
println!("cargo:rustc-cfg=zipora_release_mode");
if cfg!(feature = "simd") {
println!("cargo:rustc-env=RUSTFLAGS=-C target-cpu=native");
}
}
"bench" => {
println!("cargo:rustc-cfg=zipora_bench_mode");
if cfg!(feature = "simd") {
println!("cargo:rustc-env=RUSTFLAGS=-C target-cpu=native");
}
}
_ => {
println!("cargo:rustc-cfg=zipora_debug_mode");
}
}
}
#[cfg(feature = "ffi")]
#[allow(dead_code)]
fn generate_ffi_bindings() {
use std::env;
use std::path::PathBuf;
let crate_dir = env::var("CARGO_MANIFEST_DIR").unwrap();
let config = cbindgen::Config {
language: cbindgen::Language::C,
cpp_compat: true,
include_guard: Some("ZIPORA_H".to_string()),
autogen_warning: Some("/* Warning, this file is autogenerated by cbindgen. Don't modify this manually. */".to_string()),
include_version: true,
namespace: Some("zipora".to_string()),
line_length: 100,
tab_width: 4,
documentation: true,
documentation_style: cbindgen::DocumentationStyle::Doxy,
..Default::default()
};
cbindgen::Builder::new()
.with_crate(crate_dir)
.with_config(config)
.generate()
.expect("Unable to generate bindings")
.write_to_file("include/zipora.h");
println!("cargo:rustc-cfg=zipora_ffi_enabled");
}
#[cfg(not(feature = "ffi"))]
fn generate_ffi_bindings() {
}