libusb-src 1.0.26

FFI bindings for libusb. Can be easily cross compiled。
Documentation
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>;

    #[cfg(target_family = "unix")]
    {
        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())
        {
            src_os_files.push("linux_netlink.c");
            src_os_files.push("linux_usbfs.c");
        }
    }
    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",
        ];

        #[cfg(not(target_env = "msvc"))]
        {
            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);
    c.compile("usb");
}

fn get_libusb_version_one(src: &str, e: &str)->i32{
    let res = format!(r"#define LIBUSB_{} (\d+)\n#endif", e);
    let re = Regex::new(&res).unwrap();
    let caps = re.captures(&src).unwrap();
    let version = caps.get(1).unwrap().as_str();
    version.parse::<i32>().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)
}
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_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(&params.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 <asm/types.h> 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 <dlfcn.h> header file. */
#define HAVE_DLFCN_H 1

/* Define to 1 if the system has eventfd functionality. */
#define HAVE_EVENTFD 1

/* Define to 1 if you have the <inttypes.h> header file. */
#define HAVE_INTTYPES_H 1

/* Define to 1 if you have the <IOKit/usb/IOUSBHostFamilyDefinitions.h> 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 <stdint.h> header file. */
#define HAVE_STDINT_H 1

/* Define to 1 if you have the <stdio.h> header file. */
#define HAVE_STDIO_H 1

/* Define to 1 if you have the <stdlib.h> header file. */
#define HAVE_STDLIB_H 1

/* Define to 1 if you have the <strings.h> header file. */
#define HAVE_STRINGS_H 1

/* Define to 1 if you have the <string.h> 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 <sys/stat.h> header file. */
#define HAVE_SYS_STAT_H 1

/* Define to 1 if you have the <sys/time.h> header file. */
#define HAVE_SYS_TIME_H 1

/* Define to 1 if you have the <sys/types.h> header file. */
#define HAVE_SYS_TYPES_H 1

/* Define to 1 if the system has timerfd functionality. */
#define HAVE_TIMERFD 1

/* Define to 1 if you have the <unistd.h> 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 */


/* Enable GNU extensions. */
#define _GNU_SOURCE 1

/* 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

        "#;