use std::env;
use std::path::PathBuf;
const CXX_DIR: &str = "src/IsoSpec++";
fn main() {
let root = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap());
let cxx_dir = root.join(CXX_DIR);
println!("cargo:rerun-if-changed=rust/src/ffi.rs");
println!("cargo:rerun-if-changed=rust/shim");
println!("cargo:rerun-if-changed={CXX_DIR}");
println!("cargo:rerun-if-env-changed=DOCS_RS");
println!("cargo:rerun-if-changed=VERSION");
let version = std::fs::read_to_string(root.join("VERSION")).expect("reading VERSION");
println!("cargo:rustc-env=ISOSPEC_LIBRARY_VERSION={}", version.trim());
if env::var_os("DOCS_RS").is_some() {
return;
}
let base = configure(cxx_build::bridge("rust/src/ffi.rs"), &cxx_dir);
let is_msvc = base.get_compiler().is_like_msvc();
let is_x86 = matches!(
env::var("CARGO_CFG_TARGET_ARCH").as_deref(),
Ok("x86_64") | Ok("x86")
);
let levels: [(&str, &[&str]); 4] = [
("baseline", &[]),
("avx", &["-mavx"]),
("v3", &["-mavx2", "-mfma"]),
(
"v4",
&["-mavx512f", "-mavx512bw", "-mavx512dq", "-mavx512vl"],
),
];
let mut kernel_objects = Vec::new();
for (level, flags) in levels {
let mut build = configure(cc::Build::new(), &cxx_dir);
let wanted = !is_msvc && is_x86 && !flags.is_empty();
if wanted
&& flags
.iter()
.all(|f| build.is_flag_supported(f).unwrap_or(false))
{
for f in flags {
build.flag(f);
}
}
kernel_objects.extend(
build
.file(cxx_dir.join(format!("isa_kernels_{level}.cpp")))
.compile_intermediates(),
);
}
let mut base = base;
base.file(cxx_dir.join("unity-build.cpp"))
.file("rust/shim/shim.cc")
.objects(kernel_objects)
.compile("isospec_cxx");
}
fn configure(mut build: cc::Build, cxx_dir: &std::path::Path) -> cc::Build {
build
.cpp(true)
.std("c++20")
.include(cxx_dir)
.include("rust/shim")
.define("ISOSPEC_ISA_DISPATCH", "1")
.warnings(false);
if env::var_os("CARGO_CFG_DEBUG_ASSERTIONS").is_none() {
build.define("NDEBUG", None);
}
if build.get_compiler().is_like_msvc() {
build.flag("/utf-8").flag("/bigobj").flag("/Zc:__cplusplus");
}
build
}