use glob::glob; use regex::Regex; use std::env; use std::fs::{create_dir_all, read_to_string, OpenOptions}; use std::io::Write; use std::path::PathBuf; fn h3_version() -> (String, String, String) { let version_contents = read_to_string("libh3/VERSION").unwrap(); let cap = Regex::new("^(?P[0-9]+)\\.(?P[0-9]+)\\.(?P[0-9]+)") .unwrap() .captures(&version_contents) .expect("version number not found"); ( cap["mj"].to_string(), cap["mn"].to_string(), cap["pt"].to_string(), ) } fn configure_header() -> (PathBuf, PathBuf) { let mut include_dir = PathBuf::from(env::var("OUT_DIR").unwrap()); include_dir.push("include"); create_dir_all(&include_dir).unwrap(); let (version_major, version_minor, version_patch) = h3_version(); let header_contents = read_to_string("libh3/src/h3lib/include/h3api.h.in") .unwrap() .replace("@H3_VERSION_MAJOR@", &version_major) .replace("@H3_VERSION_MINOR@", &version_minor) .replace("@H3_VERSION_PATCH@", &version_patch); let mut h3api_header = include_dir.clone(); h3api_header.push("h3api.h"); write!( OpenOptions::new() .create(true) .truncate(true) .write(true) .open(&h3api_header) .unwrap(), "{}", header_contents ) .unwrap(); (include_dir, h3api_header) } fn main() { println!("cargo:rerun-if-changed=libh3"); #[allow(unused_variables)] let (configured_includes, h3api_header) = configure_header(); cc::Build::new() .include("libh3/src/h3lib/include") .include(configured_includes) .files(glob("libh3/src/h3lib/lib/*.c").unwrap().map(|p| p.unwrap())) .compile("h3"); #[cfg(feature = "bindgen")] { let mut builder = bindgen::Builder::default().sort_semantically(true).header( h3api_header .as_path() .as_os_str() .to_owned() .into_string() .expect("Path could not be converted to string"), ); // read the contents of the header to extract functions and types let header_contents = read_to_string(h3api_header).expect("Unable to read h3 header"); for cap in Regex::new(r"H3_EXPORT\(\s*(?P[a-zA-Z0-9_]+)\s*\)") .unwrap() .captures_iter(&header_contents) { builder = builder.allowlist_function(&cap["func"]); } for cap in Regex::new(r"struct\s+\{[^\}]*}\s*(?P[a-zA-Z0-9_]+)") .unwrap() .captures_iter(&header_contents) { builder = builder.allowlist_type(&cap["type"]); } // Finish the builder and generate the bindings. let bindings = builder .generate() // Unwrap the Result and panic on failure. .expect("Unable to generate bindings"); // Write the bindings to the $OUT_DIR/bindings.rs file. let out_path = PathBuf::from(env::var("OUT_DIR").unwrap()); bindings .write_to_file(out_path.join("bindings.rs")) .expect("Couldn't write bindings!"); } }