use std::fs;
use std::path::PathBuf;
fn main() {
let pointer_width = std::env::var("CARGO_CFG_TARGET_POINTER_WIDTH")
.expect("CARGO_CFG_TARGET_POINTER_WIDTH must be set by cargo");
if pointer_width != "64" {
panic!(
"arpack-sys is supported only on 64-bit-pointer-width targets \
(got target_pointer_width = {pointer_width})"
);
}
println!("cargo:rerun-if-env-changed=DOCS_RS");
if std::env::var_os("DOCS_RS").is_some() {
return;
}
let lib = pkg_config::Config::new()
.atleast_version("3.8.0")
.probe("arpack")
.expect("pkg-config could not locate ARPACK-NG (>= 3.8.0). Install it (e.g. `brew install arpack`) and ensure its .pc file is on PKG_CONFIG_PATH.");
verify_default_integer_abi(&lib.include_paths);
}
fn verify_default_integer_abi(include_paths: &[PathBuf]) {
let mut header = None;
for dir in include_paths {
let candidate = dir.join("arpackdef.h");
if candidate.exists() {
header = Some(candidate);
break;
}
}
let Some(header) = header else {
panic!(
"could not find arpackdef.h in pkg-config include paths ({:?}); cannot verify ARPACK integer ABI",
include_paths
);
};
println!("cargo:rerun-if-changed={}", header.display());
let content = fs::read_to_string(&header)
.unwrap_or_else(|e| panic!("failed to read {}: {e}", header.display()));
let raw_value: Option<String> = content
.lines()
.map(str::trim)
.filter_map(|l| l.strip_prefix('#').map(str::trim_start))
.filter_map(|l| l.strip_prefix("define"))
.find_map(|rest| {
let mut tokens = rest.split_whitespace();
match tokens.next() {
Some("INTERFACE64") => tokens.next().map(str::to_owned),
_ => None,
}
});
let value = raw_value.as_deref().map(strip_macro_decoration);
match value {
Some("0") => {}
Some("1") => panic!(
"ARPACK-NG at {} was built with INTERFACE64=1 (64-bit a_int). \
The committed arpack-sys bindings target the default 32-bit ABI, \
so using a 64-bit-ABI build would silently corrupt memory. \
Rebuild ARPACK-NG with INTERFACE64=0 (the upstream default) \
or open an issue if 64-bit-ABI support is needed.",
header.display()
),
Some(other) => panic!(
"unrecognized INTERFACE64 value '{other}' in {}; expected 0 or 1",
header.display()
),
None => panic!(
"could not locate `#define INTERFACE64` in {}; the installed ARPACK-NG \
header may be too old or non-standard",
header.display()
),
}
}
fn strip_macro_decoration(raw: &str) -> &str {
let mut s = raw.trim();
if let Some(pos) = s.find("//") {
s = s[..pos].trim();
}
if let Some(pos) = s.find("/*") {
s = s[..pos].trim();
}
while let (Some(stripped_start), true) = (s.strip_prefix('('), s.ends_with(')')) {
s = stripped_start
.strip_suffix(')')
.unwrap_or(stripped_start)
.trim();
}
s
}