| 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(); |
| } |
| } |