use std::{collections::HashSet, env, path::PathBuf}; const MIN_VERSION: &str = "0.10"; fn main() { if cfg!(target_os = "freebsd") { env_var_set_default("ZBAR_INCLUDE_DIRS", "/usr/include"); env_var_set_default("ZBAR_LIB_DIRS", "/usr/lib"); env_var_set_default("ZBAR_LIBS", "zbar"); } let lib_dirs = find_zbar_lib_dirs(); for d in &lib_dirs { if !d.exists() { panic!("ZBar library directory does not exist: {}", d.to_string_lossy()); } println!("cargo:rustc-link-search=native={}", d.to_string_lossy()); } let include_dirs = find_zbar_include_dirs(); for d in &include_dirs { if !d.exists() { panic!("ZBar include directory does not exist: {}", d.to_string_lossy()); } println!("cargo:include={}", d.to_string_lossy()); } println!("cargo:rerun-if-env-changed=ZBAR_LIBS"); let target = env::var("TARGET").unwrap(); let libs_env = env::var("ZBAR_LIBS").ok(); let libs = match libs_env { Some(ref v) => v.split(':').map(|x| x.to_owned()).collect(), None => { #[allow(clippy::if_same_then_else)] if target.contains("windows") { vec!["zbar".to_string()] // TODO: not sure } else if target.contains("freebsd") { vec!["zbar".to_string()] } else { run_pkg_config().libs } }, }; let kind = determine_mode(&lib_dirs, libs.as_slice()); for lib in libs.into_iter() { println!("cargo:rustc-link-lib={}={}", kind, lib); } println!("cargo:rerun-if-env-changed=ZBAR_DYLIB_STDCPP"); let kind = env::var("ZBAR_DYLIB_STDCPP"); match kind.as_ref().map(|s| &s[..]) { Ok("0") => (), Ok(_) => println!("cargo:rustc-link-lib=dylib=stdc++"), Err(_) => (), } } fn env_var_set_default(name: &str, value: &str) { if env::var(name).is_err() { env::set_var(name, value); } } fn find_zbar_lib_dirs() -> Vec { println!("cargo:rerun-if-env-changed=ZBAR_LIB_DIRS"); env::var("ZBAR_LIB_DIRS") .map(|x| x.split(':').map(PathBuf::from).collect::>()) .or_else(|_| Ok(vec![find_zbar_dir()?.join("lib")])) .or_else(|_: env::VarError| -> Result<_, env::VarError> { Ok(run_pkg_config().link_paths) }) .expect("Couldn't find ZBar library directory") } fn find_zbar_include_dirs() -> Vec { println!("cargo:rerun-if-env-changed=ZBAR_INCLUDE_DIRS"); env::var("ZBAR_INCLUDE_DIRS") .map(|x| x.split(':').map(PathBuf::from).collect::>()) .or_else(|_| Ok(vec![find_zbar_dir()?.join("include")])) .or_else(|_: env::VarError| -> Result<_, env::VarError> { Ok(run_pkg_config().include_paths) }) .expect("Couldn't find ZBar include directory") } fn find_zbar_dir() -> Result { println!("cargo:rerun-if-env-changed=ZBAR_DIR"); env::var("ZBAR_DIR").map(PathBuf::from) } fn determine_mode>(libdirs: &[PathBuf], libs: &[T]) -> &'static str { println!("cargo:rerun-if-env-changed=ZBAR_STATIC"); let kind = env::var("ZBAR_STATIC").ok(); match kind.as_ref().map(|s| &s[..]) { Some("0") => return "dylib", Some(_) => return "static", None => {}, } let files = libdirs .iter() .flat_map(|d| d.read_dir().unwrap()) .map(|e| e.unwrap()) .map(|e| e.file_name()) .filter_map(|e| e.into_string().ok()) .collect::>(); let can_static = libs.iter().all(|l| { files.contains(&format!("lib{}.a", l.as_ref())) || files.contains(&format!("{}.lib", l.as_ref())) }); let can_dylib = libs.iter().all(|l| { files.contains(&format!("lib{}.so", l.as_ref())) || files.contains(&format!("{}.dll", l.as_ref())) || files.contains(&format!("lib{}.dylib", l.as_ref())) }); match (can_static, can_dylib) { (true, false) => return "static", (false, true) => return "dylib", (false, false) => { panic!( "ZBar libdirs at `{:?}` do not contain the required files to either statically or \ dynamically link ZBar", libdirs ); }, (true, true) => {}, } "dylib" } fn run_pkg_config() -> pkg_config::Library { pkg_config::Config::new() .cargo_metadata(false) .atleast_version(MIN_VERSION) .probe("zbar") .unwrap(); pkg_config::Config::new().cargo_metadata(false).probe("zbar").unwrap() }