use std::{env, fs}; use std::io::{Read, Write}; use std::path::PathBuf; use regex::Regex; fn main(){ let mut c = cc::Build::new(); let root = PathBuf::from(env::var_os("CARGO_MANIFEST_DIR").unwrap()); let config_dir = PathBuf::from(env::var_os("OUT_DIR").unwrap()).join("include"); let libusb_src = root.join("libusb").join("libusb"); fs::create_dir_all(&config_dir).unwrap(); let libusb_src_os = libusb_src.join("os"); c.include(&config_dir); c.include(&libusb_src); c.include(&libusb_src_os); c.warnings(false); let src_files = vec![ "core.c", "descriptor.c", "hotplug.c", "io.c", "strerror.c", "sync.c", ]; for file in src_files.iter() { c.file(libusb_src.join(file)); } let mut src_os_files:Vec<&str>=vec![]; if env::var("CARGO_CFG_TARGET_FAMILY") == Ok("unix".into()) { src_os_files=vec![ "events_posix.c", "threads_posix.c", ]; if env::var("CARGO_CFG_TARGET_OS") == Ok("linux".into()) || env::var("CARGO_CFG_TARGET_OS") == Ok("android".into()) { c.define("OS_LINUX", Some("1")); // c.define("HAVE_ASM_TYPES_H", Some("1")); c.define("_GNU_SOURCE", Some("1")); c.define("HAVE_TIMERFD", Some("1")); c.define("HAVE_EVENTFD", Some("1")); src_os_files.push("linux_netlink.c"); src_os_files.push("linux_usbfs.c"); } if env::var("CARGO_CFG_TARGET_OS") == Ok("macos".into()) { c.define("OS_DARWIN", Some("1")); c.define("TARGET_OS_OSX", Some("1")); c.file(libusb_src_os.join("darwin_usb.c")); println!("cargo:rustc-link-lib=framework=CoreFoundation"); println!("cargo:rustc-link-lib=framework=IOKit"); println!("cargo:rustc-link-lib=framework=Security"); println!("cargo:rustc-link-lib=objc"); } } if env::var("CARGO_CFG_TARGET_OS") == Ok("windows".into()) { #[cfg(target_env = "msvc")] c.flag("/source-charset:utf-8"); c.warnings(false); c.define("OS_WINDOWS", Some("1")); src_os_files=vec![ "events_windows.c", "threads_windows.c", "windows_common.c", "windows_usbdk.c", "windows_winusb.c", ]; if env::var("CARGO_CFG_TARGET_ENV") != Ok("msvc".into()) { c.define("DEFAULT_VISIBILITY", Some("")); c.define("PLATFORM_WINDOWS", Some("1")); } println!("cargo:rustc-link-lib=dylib={}", "user32"); }else { c.define( "DEFAULT_VISIBILITY", Some("__attribute__((visibility(\"default\")))"), ); } for file in src_os_files.iter() { c.file(libusb_src_os.join(file)); } let mut params = Params{ c: &mut c, root: &root, config_dir: &config_dir, libusb_src_dir: &libusb_src, libusb_src_os_dir: &libusb_src_os, }; gen_config_h(&mut params); let version = get_libusb_version(&libusb_src); println!("cargo:warning=version: {}", version); let out_dir = PathBuf::from(env::var_os("OUT_DIR").unwrap()); let dep_dir = out_dir.parent().unwrap().parent().unwrap().parent().unwrap().join("deps"); c.compile("usb1.0"); fs::copy(out_dir.join("libusb1.0.a"), dep_dir.join("libusb1.0.a")).unwrap(); fs::copy(out_dir.join("usb1.0.lib"), dep_dir.join("usb1.0.lib")).unwrap(); } fn get_libusb_version_one(src: &str, e: &str)->i32{ let res = format!(r"#define LIBUSB_{} (\d+)(\s+)#endif", e); let re = Regex::new(&res).unwrap(); let caps = re.captures(&src).unwrap(); let version = caps.get(1).unwrap().as_str(); version.parse::().unwrap() } fn get_libusb_version(libusb_src: &PathBuf)->String{ let mut f = fs::File::open(libusb_src.join("version.h")).unwrap(); let mut h_str = String::new(); let _ = f.read_to_string(&mut h_str).unwrap(); let v1 = get_libusb_version_one(&h_str, "MAJOR"); let v2 = get_libusb_version_one(&h_str, "MINOR"); let v3 = get_libusb_version_one(&h_str, "MICRO"); format!("{}.{}.{}", v1, v2, v3) } #[allow(unused)] struct Params<'a>{ c: &'a mut cc::Build, root: &'a PathBuf, config_dir: &'a PathBuf, libusb_src_dir: &'a PathBuf, libusb_src_os_dir: &'a PathBuf, } fn gen_config_h(params: &mut Params){ if env::var("CARGO_CFG_TARGET_ENV") == Ok("msvc".into()) { fs::copy( params.root.join("libusb").join("msvc").join("config.h"), params.config_dir.join("config.h"), ) .unwrap(); }else if env::var("CARGO_CFG_TARGET_OS") == Ok("android".into()){ fs::copy( params.root.join("libusb").join("android").join("config.h"), params.config_dir.join("config.h"), ) .unwrap(); }else if env::var("CARGO_CFG_TARGET_OS") == Ok("macos".into()) { fs::copy( params.root.join("libusb").join("Xcode").join("config.h"), params.config_dir.join("config.h"), ) .unwrap(); } else if env::var("CARGO_CFG_TARGET_FAMILY") == Ok("unix".into()) { let mut config_h = fs::File::create(params.config_dir.join("config.h")).unwrap(); write!(config_h, "{}", CONFIG_H_UNIX_CONTENT).unwrap(); let version = get_libusb_version(¶ms.libusb_src_dir); let package_string = format!("libusb-1.0 {}", &version); params.c.define("PACKAGE_VERSION", Some(version.as_str())); params.c.define("PACKAGE_STRING", Some(package_string.as_str())); params.c.define("VERSION", Some(version.as_str())); } } const CONFIG_H_UNIX_CONTENT: &str = r#" // #define DEFAULT_VISIBILITY __attribute__ ((visibility ("default"))) /* Define to 1 to enable message logging. */ #define ENABLE_LOGGING 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_ASM_TYPES_H */ /* Define to 1 if you have the `clock_gettime' function. */ #define HAVE_CLOCK_GETTIME 1 /* Define to 1 if you have the declaration of `EFD_CLOEXEC', and to 0 if you don't. */ #define HAVE_DECL_EFD_CLOEXEC 1 /* Define to 1 if you have the declaration of `EFD_NONBLOCK', and to 0 if you don't. */ #define HAVE_DECL_EFD_NONBLOCK 1 /* Define to 1 if you have the declaration of `TFD_CLOEXEC', and to 0 if you don't. */ #define HAVE_DECL_TFD_CLOEXEC 1 /* Define to 1 if you have the declaration of `TFD_NONBLOCK', and to 0 if you don't. */ #define HAVE_DECL_TFD_NONBLOCK 1 /* Define to 1 if you have the header file. */ #define HAVE_DLFCN_H 1 /* Define to 1 if you have the header file. */ #define HAVE_INTTYPES_H 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_IOKIT_USB_IOUSBHOSTFAMILYDEFINITIONS_H */ /* Define to 1 if you have the `udev' library (-ludev). */ // #define HAVE_LIBUDEV 1 /* Define to 1 if the system has the type `nfds_t'. */ #define HAVE_NFDS_T 1 /* Define to 1 if you have the `pipe2' function. */ #define HAVE_PIPE2 1 /* Define to 1 if you have the `pthread_condattr_setclock' function. */ #define HAVE_PTHREAD_CONDATTR_SETCLOCK 1 /* Define to 1 if you have the `pthread_setname_np' function. */ #define HAVE_PTHREAD_SETNAME_NP 1 /* Define to 1 if you have the `pthread_threadid_np' function. */ /* #undef HAVE_PTHREAD_THREADID_NP */ /* Define to 1 if you have the header file. */ #define HAVE_STDINT_H 1 /* Define to 1 if you have the header file. */ #define HAVE_STDIO_H 1 /* Define to 1 if you have the header file. */ #define HAVE_STDLIB_H 1 /* Define to 1 if you have the header file. */ #define HAVE_STRINGS_H 1 /* Define to 1 if you have the header file. */ #define HAVE_STRING_H 1 /* Define to 1 if the system has the type `struct timespec'. */ /* #undef HAVE_STRUCT_TIMESPEC */ /* Define to 1 if you have the `syslog' function. */ /* #undef HAVE_SYSLOG */ /* Define to 1 if you have the header file. */ #define HAVE_SYS_STAT_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_TIME_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_TYPES_H 1 /* Define to 1 if you have the header file. */ #define HAVE_UNISTD_H 1 /* Define to the sub-directory where libtool stores uninstalled libraries. */ #define LT_OBJDIR ".libs/" /* Name of package */ #define PACKAGE "libusb-1.0" /* Define to the address where bug reports for this package should be sent. */ #define PACKAGE_BUGREPORT "libusb-devel@lists.sourceforge.net" /* Define to the full name of this package. */ #define PACKAGE_NAME "libusb-1.0" /* Define to the one symbol short name of this package. */ #define PACKAGE_TARNAME "libusb-1.0" /* Define to the home page for this package. */ #define PACKAGE_URL "http://libusb.info" /* Define to 1 if compiling for a POSIX platform. */ #define PLATFORM_POSIX 1 /* Define to 1 if compiling for a Windows platform. */ /* #undef PLATFORM_WINDOWS */ /* Define to the attribute for enabling parameter checks on printf-like functions. */ #define PRINTF_FORMAT(a, b) __attribute__ ((__format__ (__printf__, a, b))) /* Define to 1 if all of the C90 standard headers exist (not just the ones required in a freestanding environment). This macro is provided for backward compatibility; new code need not use it. */ #define STDC_HEADERS 1 /* UMockdev hotplug code is not racy */ /* #undef UMOCKDEV_HOTPLUG */ /* Define to 1 to output logging messages to the systemwide log. */ /* #undef USE_SYSTEM_LOGGING_FACILITY */ /* Define to the oldest supported Windows version. */ /* #undef _WIN32_WINNT */ /* Define to `__inline__' or `__inline' if that's what the C compiler calls it, or to nothing if 'inline' is not supported under any name. */ #ifndef __cplusplus /* #undef inline */ #endif "#;