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 FNC_PREFIX: &str = "rs_";
fn rename_symbols(
fnc_list: &[&str],
include_files: &[fs::DirEntry],
source_files: &[fs::DirEntry],
) {
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;
}
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<Path>, destination: impl AsRef<Path>) -> 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; }
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::<Vec<_>>();
let source_files = fs::read_dir(source_dir)
.unwrap()
.map(Result::unwrap)
.filter(|f| f.path().extension().unwrap() == "cc")
.collect::<Vec<_>>();
let fnc_content = fs::read_to_string("yuv_functions.txt").unwrap();
let fnc_list = fnc_content.lines().collect::<Vec<_>>();
if cloned {
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");
}