use std::env;
use std::env::VarError;
use std::path::Path;
use std::path::PathBuf;
use std::process::Command;
#[allow(clippy::too_many_lines)]
fn main() {
let os = env::consts::OS;
let arch = env::consts::ARCH;
let git_hash = Command::new("git")
.args(["rev-parse", "HEAD"])
.output()
.ok()
.and_then(|output| String::from_utf8(output.stdout).ok())
.map_or_else(|| "unknown".to_string(), |s| s.trim().to_string());
println!("cargo:rustc-env=TDC_TOOLKIT_GIT_REF={git_hash}");
let rustc_version = Command::new("rustc")
.arg("--version")
.output()
.ok()
.and_then(|output| String::from_utf8(output.stdout).ok())
.map_or_else(|| "unknown".to_string(), |s| s.trim().to_string());
println!("cargo:rustc-env=TDC_TOOLKIT_RUSTC_VERSION={rustc_version}");
println!("cargo::rerun-if-changed=.git/HEAD");
if cfg!(not(feature = "multiharp")) {
println!("cargo::warning=Using the mhlib_wrapper stub implementation.");
return;
}
assert!(
!(!(arch == "x86_64" && (os == "linux" || os == "windows")) && cfg!(feature = "multiharp")),
"feature multiharp was requested, but cannot be built on this architecture or operating system. Check your build configuration."
);
let mut include_dir = String::from("not_found");
let mut lib_dir = String::from("not_found");
let mut lib_dir_path: PathBuf;
if os == "linux" && arch == "x86_64" {
match env::var("MHLIB_LIB_DIR") {
Ok(val) => {
lib_dir_path = PathBuf::from(val);
assert!(
lib_dir_path.exists(),
"MHLIB_LIB_DIR was set, but the path does not seem to exist. Don't know what to do, exiting. Value was: {}",
lib_dir_path.display()
);
println!(
"cargo::warning=Using the value of the MHLIB_LIB_DIR environment variable to find the MultiHarp shared library."
);
}
Err(e) => match e {
VarError::NotPresent => {
let manifest_dir =
env::var("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR not set");
lib_dir_path =
PathBuf::from(manifest_dir.clone()).join("MHLib_v3.1.0.0_64bit/library");
if lib_dir_path.exists() {
println!(
"cargo::warning=Using an existing copy of the MultiHarp shared library in CARGO_MANIFEST_DIR {manifest_dir}"
);
} else {
lib_dir_path = PathBuf::from("/usr/local/lib/mh150");
if lib_dir_path.exists() {
println!(
"cargo::warning=Using the system installation of the MultiHarp shared library."
);
} else {
Command::new(
PathBuf::from(manifest_dir.clone())
.join("install_mhlib.sh")
.as_os_str(),
)
.output()
.expect("mhlib download failed");
lib_dir_path = PathBuf::from(manifest_dir.clone())
.join("MHLib_v3.1.0.0_64bit/library");
assert!(
lib_dir_path.exists(),
"Could not find a copy of the MultiHarp library. Attempted to download the MultiHarp library and failed. Don't know what to do. Exiting.",
);
println!(
"cargo::warning=Downloaded a new copy of the MultiHarp shared library and placed it in CARGO_MANIFEST_DIR {manifest_dir}."
);
}
}
}
VarError::NotUnicode(_) => {
panic!(
"Error occurred trying to read the MHLIB_PATH environment variable; Rust claims that the value is not valid Unicode."
);
}
},
}
lib_dir = lib_dir_path.to_string_lossy().into_owned();
if lib_dir_path.join("mhlib.h").exists() {
println!(
"cargo::warning=Found MultiHarp header files in the same directory as the shared library. Using them."
);
include_dir.clone_from(&lib_dir);
} else {
let include_dir_path = Path::new("/usr/local/include/mh150");
assert!(
include_dir_path.exists(),
"Could not find header files in the lib_dir {}, tried to find them in the include_dir {} instead but this directory also appears to be missing. Don't know what to do; exiting.",
lib_dir_path.display(),
include_dir_path.display(),
);
println!(
"cargo::warning=Did not find MultiHarp header files in the same directory as the shared library. Using a separate include directory."
);
include_dir = include_dir_path.to_string_lossy().into_owned();
}
println!("cargo::rustc-link-search=native={lib_dir}");
println!("cargo::rustc-link-lib=dylib=mhlib");
println!("cargo::rustc-link-arg=-Wl,-rpath={lib_dir}");
} else if os == "windows" && arch == "x86_64" {
include_dir = String::from("C:\\Program Files\\PicoQuant\\MultiHarp-MHLibv31");
lib_dir = include_dir.clone();
assert!(
Path::new(&include_dir).exists(),
"Include and library directory does not exist: {include_dir}"
);
println!("cargo::rustc-link-search=native={lib_dir}");
println!("cargo::rustc-link-lib=dylib=mhlib64");
}
let bindings = bindgen::Builder::default()
.header("wrapper.h")
.clang_arg(format!("-I{include_dir}"))
.parse_callbacks(Box::new(bindgen::CargoCallbacks::new()))
.generate()
.expect("Unable to generate bindings");
let out_path = PathBuf::from(env::var("OUT_DIR").unwrap());
bindings
.write_to_file(out_path.join("bindings.rs"))
.expect("Couldn't write bindings!");
println!("cargo::rerun-if-changed=wrapper.h");
println!("cargo::rerun-if-changed={include_dir}");
println!("cargo::rerun-if-changed={lib_dir}");
println!("cargo::warning=Value of include_dir: {include_dir}");
println!("cargo::warning=Value of lib_dir: {lib_dir}");
}