use cc; use rayon::prelude::*; use regex::Regex; use std::borrow::Cow; use std::path::Path; use std::{env, path::PathBuf}; use std::{fs, io}; //const LIBYUV_REPO: &str = "https://chromium.googlesource.com/libyuv/libyuv"; //const LIBYUV_COMMIT: &str = "af6ac82"; const FNC_PREFIX: &str = "rs_"; /*fn run_git_cmd(current_dir: &PathBuf, args: &[&str]) -> ExitStatus { Command::new("git") .current_dir(current_dir) .args(args) .status() .unwrap() }*/ fn rename_symbols( fnc_list: &[&str], include_files: &[fs::DirEntry], source_files: &[fs::DirEntry], ) { // Find all occurences of the function in every header and source files // and prefix it with FNC_PREFIX include_files .par_iter() .chain(source_files) .for_each(|file| { let mut content = fs::read_to_string(&file.path()).unwrap(); for line in fnc_list { let fnc = line.trim(); if fnc.is_empty() { continue; } // Split line using space as delimiter (If there is two words, the second word is the new name instead of using prefix) let split: Vec<&str> = fnc.split_whitespace().collect(); let fnc = split[0]; let new_name = if split.len() > 1 { split[1].to_owned() } else { format!("{}{}", FNC_PREFIX, fnc) }; let re = Regex::new(&format!(r"\b{}\b", fnc)).unwrap(); if let Cow::Owned(c) = re.replace_all(&content, &new_name) { content = c } } fs::write(&file.path(), content.to_string()).unwrap(); }); } fn copy_dir(source: impl AsRef, destination: impl AsRef) -> io::Result<()> { fs::create_dir_all(&destination)?; for entry in fs::read_dir(source)? { let entry = entry?; if entry.file_type()?.is_dir() { copy_dir(entry.path(), destination.as_ref().join(entry.file_name()))?; } else { fs::copy(entry.path(), destination.as_ref().join(entry.file_name()))?; } } Ok(()) } fn clone_if_needed(_output_dir: &PathBuf, libyuv_dir: &PathBuf) -> bool { if libyuv_dir.exists() { return false; // Already cloned } /*let status = run_git_cmd(output_dir, &["clone", LIBYUV_REPO]); if !status.success() { fs::remove_dir_all(&libyuv_dir).unwrap(); panic!("failed to clone libyuv, is git installed?"); } let status = run_git_cmd(&libyuv_dir, &["checkout", LIBYUV_COMMIT]); if !status.success() { fs::remove_dir_all(&libyuv_dir).unwrap(); panic!("failed to checkout to {}", LIBYUV_COMMIT); }*/ if let Err(err) = copy_dir("libyuv", libyuv_dir) { fs::remove_dir_all(&libyuv_dir).unwrap(); panic!("failed to copy libyuv: {:?}", err); } true } fn main() { let output_dir = PathBuf::from(env::var("OUT_DIR").unwrap()); let libyuv_dir = output_dir.join("libyuv"); let include_dir = libyuv_dir.join("include"); let source_dir = libyuv_dir.join("source"); let cloned = clone_if_needed(&output_dir, &libyuv_dir); let include_files = fs::read_dir(include_dir.join("libyuv")) .unwrap() .map(Result::unwrap) .filter(|f| f.path().extension().unwrap() == "h") .collect::>(); let source_files = fs::read_dir(source_dir) .unwrap() .map(Result::unwrap) .filter(|f| f.path().extension().unwrap() == "cc") .collect::>(); let fnc_content = fs::read_to_string("yuv_functions.txt").unwrap(); let fnc_list = fnc_content.lines().collect::>(); if cloned { // Rename symbols to avoid conflicts with other libraries // that have libyuv statically linked (e.g libwebrtc). rename_symbols(&fnc_list, &include_files, &source_files); } cc::Build::new() .warnings(false) .include(libyuv_dir.join("include")) .files(source_files.iter().map(|f| f.path())) .compile("yuv"); let mut bindgen = bindgen::Builder::default() .header(include_dir.join("libyuv.h").to_string_lossy()) .clang_arg(format!("-I{}", include_dir.to_str().unwrap())); for fnc in fnc_list { let new_name = format!("{}{}", FNC_PREFIX, fnc); bindgen = bindgen.allowlist_function(&new_name); } let output = bindgen.generate().unwrap(); let out_path = PathBuf::from(env::var("OUT_DIR").unwrap()).join("yuv.rs"); output.write_to_file(out_path).unwrap(); println!("cargo:rerun-if-changed=yuv_functions.txt"); }