use bindgen::Builder;
use copy_dir::copy_dir;
use std::env;
use std::fs::{copy, remove_dir_all, remove_file};
use std::path::Path;
use std::process::Command;
fn main() {
let build = Build::new();
build.generate_bindings();
if let Ok(ipasir) = env::var("IPASIR") {
build.copy_existing_library(ipasir);
}
if !build.static_library_exists() {
build.remove_cadical_dir();
build.copy_cadical_dir();
build.configure_cadical();
build.make_cadical();
build.copy_cadical_library();
build.remove_cadical_dir();
}
build.static_link_to_ipasir();
build.dynamic_link_to_cpp_stdlib();
}
struct Build {
pub out_dir: String,
}
impl Build {
fn new() -> Self {
Self { out_dir: env::var("OUT_DIR").unwrap() }
}
fn generate_bindings(&self) {
Builder::default()
.header("vendor/ipasir/ipasir.h").generate().unwrap()
.write_to_file(self.path("bindings.rs")).unwrap();
}
fn static_library_exists(&self) -> bool {
Path::new(&self.ipasir_out()).exists()
}
fn remove_cadical_dir(&self) {
let _ = remove_dir_all(self.path("cadical"));
}
fn copy_cadical_dir(&self) {
copy_dir("vendor/cadical", self.path("cadical")).unwrap();
}
fn configure_cadical(&self) {
Command::new(self.path("cadical/configure"))
.arg("-fPIC")
.current_dir(self.path("cadical"))
.spawn().unwrap().wait().unwrap();
}
fn make_cadical(&self) {
Command::new("make")
.current_dir(self.path("cadical/build"))
.spawn().unwrap().wait().unwrap();
}
fn copy_cadical_library(&self) {
if self.static_library_exists() {
remove_file(self.ipasir_out()).unwrap();
}
copy(
self.path("cadical/build/libcadical.a"),
self.ipasir_out(),
).unwrap();
}
fn copy_existing_library(&self, ipasir: String) {
if self.static_library_exists() {
remove_file(self.ipasir_out()).unwrap();
}
copy(ipasir, self.ipasir_out()).unwrap();
}
fn static_link_to_ipasir(&self) {
println!("cargo:rustc-link-search={}", self.out_dir);
println!("cargo:rustc-link-lib=static=ipasir");
}
fn dynamic_link_to_cpp_stdlib(&self) {
let target = env::var("TARGET").unwrap();
let name = if target.contains("msvc") {
return;
} else if target.contains("apple") {
"c++"
} else if target.contains("freebsd") {
"c++"
} else if target.contains("openbsd") {
"c++"
} else {
"stdc++"
};
println!("cargo:rustc-link-lib=dylib={}", name);
}
fn ipasir_out(&self) -> String {
self.path("libipasir.a")
}
fn path(&self, p: &'static str) -> String {
format!("{}/{}", self.out_dir, p)
}
}