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()] } 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<PathBuf> {
println!("cargo:rerun-if-env-changed=ZBAR_LIB_DIRS");
env::var("ZBAR_LIB_DIRS")
.map(|x| x.split(':').map(PathBuf::from).collect::<Vec<PathBuf>>())
.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<PathBuf> {
println!("cargo:rerun-if-env-changed=ZBAR_INCLUDE_DIRS");
env::var("ZBAR_INCLUDE_DIRS")
.map(|x| x.split(':').map(PathBuf::from).collect::<Vec<PathBuf>>())
.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<PathBuf, env::VarError> {
println!("cargo:rerun-if-env-changed=ZBAR_DIR");
env::var("ZBAR_DIR").map(PathBuf::from)
}
fn determine_mode<T: AsRef<str>>(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::<HashSet<_>>();
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()
}