use std::env;
use std::path::PathBuf;
#[derive(Debug)]
struct ParseSignedConstants;
impl bindgen::callbacks::ParseCallbacks for ParseSignedConstants {
fn int_macro(&self, name: &str, _value: i64) -> Option<bindgen::callbacks::IntKind> {
let prefix: String = name.chars().take_while(|c| *c != '_').collect();
match prefix.as_ref() {
"CV" | "IDA" | "KIN" | "SUN" => Some(bindgen::callbacks::IntKind::Int),
_ => None,
}
}
}
fn get_env_var(var_name: &str) -> Option<String> {
env::vars().find_map(|t| {
let (key, value) = t;
if key == var_name {
Some(value)
} else {
None
}
})
}
fn main() {
macro_rules! feature {
($s:tt) => {
if cfg!(feature = $s) {
"ON"
} else {
"OFF"
}
};
}
let static_libraries = feature!("static_libraries");
let shared_libraries = match static_libraries {
"ON" => "OFF",
"OFF" => "ON",
_ => unreachable!(),
};
let library_type = match static_libraries {
"ON" => "static",
"OFF" => "dylib",
_ => unreachable!(),
};
let lib_loc;
let inc_dir;
if cfg!(feature = "build_libraries") {
let dst = cmake::Config::new("vendor")
.define("CMAKE_INSTALL_LIBDIR", "lib")
.define("BUILD_STATIC_LIBS", static_libraries)
.define("BUILD_SHARED_LIBS", shared_libraries)
.define("BUILD_TESTING", "OFF")
.define("EXAMPLES_INSTALL", "OFF")
.define("BUILD_ARKODE", feature!("arkode"))
.define("BUILD_CVODE", feature!("cvode"))
.define("BUILD_CVODES", feature!("cvodes"))
.define("BUILD_IDA", feature!("ida"))
.define("BUILD_IDAS", feature!("idas"))
.define("BUILD_KINSOL", feature!("kinsol"))
.define("OPENMP_ENABLE", feature!("nvecopenmp"))
.define("PTHREAD_ENABLE", feature!("nvecpthreads"))
.build();
let dst_disp = dst.display();
lib_loc = Some(format!("{}/lib", dst_disp));
inc_dir = Some(format!("{}/include", dst_disp));
} else {
lib_loc = get_env_var("SUNDIALS_LIBRARY_DIR");
inc_dir = get_env_var("SUNDIALS_INCLUDE_DIR");
}
if let Some(loc) = lib_loc {
println!("cargo:rustc-link-search=native={}", loc)
}
for lib_name in &[
"nvecserial",
"sunlinsolband",
"sunlinsoldense",
"sunlinsolpcg",
"sunlinsolspbcgs",
"sunlinsolspfgmr",
"sunlinsolspgmr",
"sunlinsolsptfqmr",
"sunmatrixband",
"sunmatrixdense",
"sunmatrixsparse",
"sunnonlinsolfixedpoint",
"sunnonlinsolnewton",
] {
println!(
"cargo:rustc-link-lib={}=sundials_{}",
library_type, lib_name
);
}
macro_rules! link {
($($s:tt),*) => {
$(if cfg!(feature = $s) {
println!("cargo:rustc-link-lib={}=sundials_{}", library_type, $s);
})*
}
}
link! {"arkode", "cvode", "cvodes", "ida", "idas", "kinsol", "nvecopenmp", "nvecpthreads"}
macro_rules! define {
($a:tt, $b:tt) => {
format!(
"-DUSE_{}={}",
stringify!($b),
if cfg!(feature = $a) { 1 } else { 0 }
)
};
}
let out_path = PathBuf::from(env::var("OUT_DIR").unwrap());
bindgen::Builder::default()
.header("wrapper.h")
.clang_arg(match inc_dir {
Some(dir) => format!("-I{}", dir),
None => "".to_owned(),
})
.clang_args(&[
define!("arkode", ARKODE),
define!("cvode", CVODE),
define!("cvodes", CVODES),
define!("ida", IDA),
define!("idas", IDAS),
define!("kinsol", KINSOL),
define!("nvecopenmp", OPENMP),
define!("nvecpthreads", PTHREADS),
])
.parse_callbacks(Box::new(ParseSignedConstants))
.generate()
.expect("Unable to generate bindings")
.write_to_file(out_path.join("bindings.rs"))
.expect("Couldn't write bindings!");
}