| use std::{env, fs, path::PathBuf}; | 
 |  | 
 | static VERSION: &str = "1.0.27"; | 
 |  | 
 | fn link(name: &str, bundled: bool) { | 
 |     use std::env::var; | 
 |     let target = var("TARGET").unwrap(); | 
 |     let target: Vec<_> = target.split('-').collect(); | 
 |     if target.get(2) == Some(&"windows") { | 
 |         println!("cargo:rustc-link-lib=dylib={}", name); | 
 |         if bundled && target.get(3) == Some(&"gnu") { | 
 |             let dir = var("CARGO_MANIFEST_DIR").unwrap(); | 
 |             println!("cargo:rustc-link-search=native={}/{}", dir, target[0]); | 
 |         } | 
 |     } | 
 | } | 
 |  | 
 | pub fn link_framework(name: &str) { | 
 |     println!("cargo:rustc-link-lib=framework={}", name); | 
 | } | 
 |  | 
 | fn get_macos_major_version() -> Option<usize> { | 
 |     if !cfg!(target_os = "macos") { | 
 |         return None; | 
 |     } | 
 |  | 
 |     let output = std::process::Command::new("sw_vers") | 
 |         .args(["-productVersion"]) | 
 |         .output() | 
 |         .unwrap(); | 
 |     let version = std::str::from_utf8(&output.stdout).unwrap().trim_end(); | 
 |     let components: Vec<&str> = version.split('.').collect(); | 
 |     let major: usize = components[0].parse().unwrap(); | 
 |     Some(major) | 
 | } | 
 |  | 
 | fn find_libusb_pkg(statik: bool) -> bool { | 
 |     if std::env::var("CARGO_CFG_TARGET_ENV") == Ok("msvc".into()) { | 
 |         #[cfg(target_os = "windows")] | 
 |         return match vcpkg::Config::new().find_package("libusb") { | 
 |             Ok(_) => true, | 
 |             Err(e) => { | 
 |                 if pkg_config::probe_library("libusb-1.0").is_ok() { | 
 |                     true | 
 |                 } else { | 
 |                     println!("Can't find libusb pkg: {:?}", e); | 
 |                     false | 
 |                 } | 
 |             } | 
 |         }; | 
 |     } | 
 |     // https://github.com/rust-lang/rust/issues/96943 | 
 |     let needs_rustc_issue_96943_workaround: bool = get_macos_major_version() | 
 |         .map(|major| major >= 11) | 
 |         .unwrap_or_default(); | 
 |  | 
 |     match pkg_config::Config::new().statik(statik).probe("libusb-1.0") { | 
 |         Ok(l) => { | 
 |             for lib in l.libs { | 
 |                 if statik { | 
 |                     if needs_rustc_issue_96943_workaround && lib == "objc" { | 
 |                         continue; | 
 |                     } | 
 |                     println!("cargo:rustc-link-lib=static={}", lib); | 
 |                 } | 
 |             } | 
 |             // Provide metadata and include directory for dependencies | 
 |             if statik { | 
 |                 println!("cargo:static=1"); | 
 |             } | 
 |             assert!(l.include_paths.len() <= 1); // Cannot have multiple env vars with same name | 
 |             for path in l.include_paths { | 
 |                 println!("cargo:include={}", path.to_str().unwrap()); | 
 |             } | 
 |             println!("cargo:version_number={}", l.version); | 
 |             true | 
 |         } | 
 |         Err(e) => { | 
 |             println!("Can't find libusb pkg: {:?}", e); | 
 |             false | 
 |         } | 
 |     } | 
 | } | 
 |  | 
 | fn make_source() { | 
 |     let libusb_source = PathBuf::from("libusb"); | 
 |  | 
 |     /* | 
 |     Example environment variables and values: | 
 |  | 
 |     CARGO_CFG_TARGET_ARCH: aarch64 | 
 |     CARGO_CFG_TARGET_ENDIAN: little | 
 |     CARGO_CFG_TARGET_ENV: | 
 |     CARGO_CFG_TARGET_FAMILY: unix | 
 |     CARGO_CFG_TARGET_OS: android | 
 |     CARGO_CFG_TARGET_POINTER_WIDTH: 64 | 
 |     CARGO_CFG_TARGET_VENDOR: unknown | 
 |     CARGO_CFG_UNIX: | 
 |     */ | 
 |  | 
 |     // Provide metadata and include directory for dependencies | 
 |     println!("cargo:vendored=1"); | 
 |     println!("cargo:static=1"); | 
 |     let include_dir = PathBuf::from(env::var("OUT_DIR").unwrap()).join("include"); | 
 |     fs::create_dir_all(&include_dir).unwrap(); | 
 |     fs::copy( | 
 |         libusb_source.join("libusb/libusb.h"), | 
 |         include_dir.join("libusb.h"), | 
 |     ) | 
 |     .unwrap(); | 
 |     println!("cargo:include={}", include_dir.to_str().unwrap()); | 
 |  | 
 |     fs::File::create(format!("{}/{}", include_dir.display(), "config.h")).unwrap(); | 
 |     let mut base_config = cc::Build::new(); | 
 |     base_config.include(&include_dir); | 
 |     base_config.include(libusb_source.join("libusb")); | 
 |  | 
 |     base_config.define("PRINTF_FORMAT(a, b)", Some("")); | 
 |     base_config.define("ENABLE_LOGGING", Some("1")); | 
 |  | 
 |     if std::env::var("CARGO_CFG_TARGET_ENV") == Ok("msvc".into()) { | 
 |         fs::copy( | 
 |             libusb_source.join("msvc/config.h"), | 
 |             include_dir.join("config.h"), | 
 |         ) | 
 |         .unwrap(); | 
 |     } | 
 |  | 
 |     if std::env::var("CARGO_CFG_TARGET_OS") == Ok("macos".into()) { | 
 |         base_config.define("OS_DARWIN", Some("1")); | 
 |         base_config.define("TARGET_OS_OSX", Some("1")); | 
 |         base_config.file(libusb_source.join("libusb/os/darwin_usb.c")); | 
 |         link_framework("CoreFoundation"); | 
 |         link_framework("IOKit"); | 
 |         link_framework("Security"); | 
 |         link("objc", false); | 
 |     } | 
 |  | 
 |     if std::env::var("CARGO_CFG_TARGET_OS") == Ok("linux".into()) | 
 |         || std::env::var("CARGO_CFG_TARGET_OS") == Ok("android".into()) | 
 |     { | 
 |         base_config.define("OS_LINUX", Some("1")); | 
 |         base_config.define("HAVE_ASM_TYPES_H", Some("1")); | 
 |         base_config.define("_GNU_SOURCE", Some("1")); | 
 |         base_config.define("HAVE_TIMERFD", Some("1")); | 
 |         base_config.define("HAVE_EVENTFD", Some("1")); | 
 |         base_config.file(libusb_source.join("libusb/os/linux_netlink.c")); | 
 |         base_config.file(libusb_source.join("libusb/os/linux_usbfs.c")); | 
 |     } | 
 |  | 
 |     if std::env::var("CARGO_CFG_TARGET_FAMILY") == Ok("unix".into()) { | 
 |         base_config.define("HAVE_SYS_TIME_H", Some("1")); | 
 |         base_config.define("HAVE_NFDS_T", Some("1")); | 
 |         base_config.define("PLATFORM_POSIX", Some("1")); | 
 |         base_config.define("HAVE_CLOCK_GETTIME", Some("1")); | 
 |         base_config.define( | 
 |             "DEFAULT_VISIBILITY", | 
 |             Some("__attribute__((visibility(\"default\")))"), | 
 |         ); | 
 |  | 
 |         if let Ok(lib) = pkg_config::probe_library("libudev") { | 
 |             base_config.define("USE_UDEV", Some("1")); | 
 |             base_config.define("HAVE_LIBUDEV", Some("1")); | 
 |             base_config.file(libusb_source.join("libusb/os/linux_udev.c")); | 
 |             for path in lib.include_paths { | 
 |                 base_config.include(path.to_str().unwrap()); | 
 |             } | 
 |         }; | 
 |  | 
 |         println!("Including posix!"); | 
 |         base_config.file(libusb_source.join("libusb/os/events_posix.c")); | 
 |         base_config.file(libusb_source.join("libusb/os/threads_posix.c")); | 
 |     } | 
 |  | 
 |     if std::env::var("CARGO_CFG_TARGET_OS") == Ok("windows".into()) { | 
 |         if std::env::var("CARGO_CFG_TARGET_ENV") == Ok("msvc".into()) { | 
 |             base_config.flag("/source-charset:utf-8"); | 
 |         } | 
 |  | 
 |         base_config.warnings(false); | 
 |         base_config.define("OS_WINDOWS", Some("1")); | 
 |         base_config.file(libusb_source.join("libusb/os/events_windows.c")); | 
 |         base_config.file(libusb_source.join("libusb/os/threads_windows.c")); | 
 |         base_config.file(libusb_source.join("libusb/os/windows_common.c")); | 
 |         base_config.file(libusb_source.join("libusb/os/windows_usbdk.c")); | 
 |         base_config.file(libusb_source.join("libusb/os/windows_winusb.c")); | 
 |  | 
 |         base_config.define("DEFAULT_VISIBILITY", Some("")); | 
 |         base_config.define("PLATFORM_WINDOWS", Some("1")); | 
 |         link("user32", false); | 
 |     } | 
 |  | 
 |     base_config.file(libusb_source.join("libusb/core.c")); | 
 |     base_config.file(libusb_source.join("libusb/descriptor.c")); | 
 |     base_config.file(libusb_source.join("libusb/hotplug.c")); | 
 |     base_config.file(libusb_source.join("libusb/io.c")); | 
 |     base_config.file(libusb_source.join("libusb/strerror.c")); | 
 |     base_config.file(libusb_source.join("libusb/sync.c")); | 
 |  | 
 |     base_config.compile("usb-vendored"); | 
 |     println!("cargo:version_number={}", VERSION); | 
 | } | 
 |  | 
 | fn main() { | 
 |     println!("cargo:rerun-if-env-changed=LIBUSB_STATIC"); | 
 |     let statik = { | 
 |         if cfg!(target_os = "macos") { | 
 |             match std::env::var("LIBUSB_STATIC").unwrap_or_default().as_ref() { | 
 |                 "" | "0" => false, | 
 |                 _ => true, | 
 |             } | 
 |         } else { | 
 |             std::env::var("CARGO_CFG_TARGET_FEATURE") | 
 |                 .map(|s| s.contains("crt-static")) | 
 |                 .unwrap_or_default() | 
 |         } | 
 |     }; | 
 |  | 
 |     let is_freebsd = std::env::var("CARGO_CFG_TARGET_OS") == Ok("freebsd".into()); | 
 |  | 
 |     if (!is_freebsd && cfg!(feature = "vendored")) || !find_libusb_pkg(statik) { | 
 |         make_source(); | 
 |     } | 
 | } |