use anyhow::{anyhow, bail, Result}; use cfg_if::cfg_if; use once_cell::sync::OnceCell; use std::{ env, path::{Path, PathBuf}, }; fn main() -> Result<()> { #[cfg(feature = "codegen")] codegen()?; #[cfg(feature = "link")] link()?; Ok(()) } #[cfg(feature = "codegen")] fn codegen() -> Result<()> { let include_dir = libsvm_include()?; let header_file = include_dir.join("libsvm").join("svm.h"); let out_file = concat!(env!("CARGO_MANIFEST_DIR"), "/src/bindings.rs"); let builder = bindgen::Builder::default() .header(format!("{}", header_file.display())) .parse_callbacks(Box::new(bindgen::CargoCallbacks)); let bindings = builder .generate() .map_err(|_| anyhow!("Unable to generate bindings"))?; // Write the bindings to the $OUT_DIR/bindings.rs file. bindings .write_to_file(out_file) .map_err(|_| anyhow!("unable to write bindings"))?; Ok(()) } #[cfg(feature = "link")] fn link() -> Result<()> { let library_dir = libsvm_library()?; println!("cargo:rustc-link-search={}", library_dir.display()); println!("cargo:rustc-link-lib=dylib=svm"); Ok(()) } fn libsvm_include() -> Result<&'static Path> { static LIBSVM_INCLUDE: OnceCell = OnceCell::new(); LIBSVM_INCLUDE.get_or_try_init(|| { if let Some(path) = get_env_path("LIBSVM_INCLUDE") { return Ok(path); } let path = { cfg_if! { if #[cfg(target_os = "linux")] { libsvm_path()?.join("include") } else { bail!("Unable to find libsvm library. Try to set LIBSVM_PATH environment variable."); } } }; Ok(path) }) .map(|path| path.as_ref()) } fn libsvm_library() -> Result<&'static Path> { static LIBSVM_LIBRARY: OnceCell = OnceCell::new(); LIBSVM_LIBRARY.get_or_try_init(|| { if let Some(path) = get_env_path("LIBSVM_LIBRARY") { return Ok(path); } let path = { cfg_if! { if #[cfg(target_os = "linux")] { libsvm_path()?.join("lib") } else { bail!("Unable to find libsvm library. Try to set LIBSVM_PATH environment variable."); } } }; Ok(path) }) .map(|path| path.as_ref()) } fn libsvm_path() -> Result<&'static Path> { static LIBSVM_PATH: OnceCell = OnceCell::new(); LIBSVM_PATH.get_or_try_init(|| { if let Some(path) = get_env_path("LIBSVM_PATH") { return Ok(path); } let path = { cfg_if! { if #[cfg(target_os = "linux")] { PathBuf::from("/usr") } else { bail!("Unable to find libsvm library. Try to set LIBSVM_PATH environment variable."); } } }; Ok(path) }).map(|path| path.as_ref()) } fn get_env_path(name: &str) -> Option { println!("rerun-if-env-changed={}", name); env::var_os(name).map(PathBuf::from) }