#![allow(unused)]
use std::path::PathBuf;
use std::string::ToString;
use flate2::read::GzDecoder;
use tar::Archive;
fn is_release_mode() -> bool {
let value = std::env::var("PROFILE")
.expect("missing PROFILE")
.to_lowercase();
&value == "release"
}
fn is_debug_mode() -> bool {
let value = std::env::var("PROFILE")
.expect("missing PROFILE")
.to_lowercase();
&value == "debug"
}
fn get_webp_output_dir() -> PathBuf {
let out_dir = std::env::var("OUT_DIR").expect("missing OUT_DIR");
let out_dir = PathBuf::from(out_dir).join("webp");
std::fs::create_dir_all(&out_dir).expect("unable to add webp dir under OUT_DIR");
out_dir
}
fn run_make(source_path: &PathBuf) {
let result = std::process::Command::new("make")
.arg("-C")
.arg(source_path)
.args(&["-f", "makefile.unix"])
.output()
.expect(&format!("make -C {:?} failed", source_path));
}
#[derive(Debug, Clone)]
pub struct WebpFiles {
release_dir: PathBuf,
lib_file: PathBuf,
decode_header_file: PathBuf,
encode_header_file: PathBuf,
types_header_file: PathBuf,
}
fn download_and_build_webp() -> Result<WebpFiles, String> {
let out_dir = get_webp_output_dir();
let download_dir = out_dir.join("download");
let source_dir = out_dir.join("source");
let release_dir = out_dir.join("release");
let lib_file = release_dir.join("libwebp.a");
let decode_header_file = release_dir.join("decode.h");
let encode_header_file = release_dir.join("encode.h");
let types_header_file = release_dir.join("types.h");
if is_debug_mode() {
let all_exists =
lib_file.exists() &&
decode_header_file.exists() &&
encode_header_file.exists() &&
types_header_file.exists();
if all_exists {
return Ok(WebpFiles{
release_dir,
lib_file,
decode_header_file,
encode_header_file,
types_header_file,
});
}
}
std::fs::remove_dir_all(&out_dir).map_err(|x| x.to_string())?;
std::fs::create_dir_all(&download_dir).map_err(|x| x.to_string())?;
let url = "https://github.com/webmproject/libwebp/tarball/1.0.3";
let tar_reply = reqwest::get(url).expect("unable to get webp tar file from github");
let tar = GzDecoder::new(tar_reply);
let mut archive = Archive::new(tar);
let tmp_source_dir: Option<PathBuf> = {
archive
.unpack(&download_dir)
.map_err(|x| format!(
"failed to unpack webp tar payload from github to {:?}: {:?}",
download_dir,
x
))?;
let xs = std::fs::read_dir(&download_dir)
.expect(&format!("unable to read dir {:?}", download_dir))
.filter_map(Result::ok)
.filter(|file| {
file.file_type()
.map(|x| x.is_dir())
.unwrap_or(false)
})
.collect::<Vec<std::fs::DirEntry>>();
match &xs[..] {
[x] => Some(x.path()),
_ => None,
}
};
let tmp_source_dir = tmp_source_dir.expect("unexpected tar output from github");
std::fs::rename(&tmp_source_dir, &source_dir)
.map_err(|x| format!(
"unable to rename from {:?} to {:?}: {}",
tmp_source_dir,
source_dir,
x,
))?;
run_make(&source_dir);
std::fs::create_dir_all(&release_dir).map_err(|x| x.to_string())?;
let cpy = |src: PathBuf, dest: &PathBuf| {
std::fs::copy(&src, dest).expect(&format!(
"unable to cpy from {:?} to {:?}",
src,
dest,
));
};
cpy(source_dir.join("src/libwebp.a"), &lib_file);
cpy(source_dir.join("src/webp/decode.h"), &decode_header_file);
cpy(source_dir.join("src/webp/encode.h"), &encode_header_file);
cpy(source_dir.join("src/webp/types.h"), &types_header_file);
std::fs::remove_dir_all(&download_dir).map_err(|x| x.to_string())?;
std::fs::remove_dir_all(&source_dir).map_err(|x| x.to_string())?;
Ok(WebpFiles{
release_dir,
lib_file,
decode_header_file,
encode_header_file,
types_header_file,
})
}
fn build_all() {
let out_path = PathBuf::from(std::env::var("OUT_DIR").unwrap());
let webp_files = match download_and_build_webp() {
Ok(x) => x,
Err(x) => panic!("{}", x),
};
println!("cargo:rustc-link-search=native={}", {
webp_files.release_dir
.to_str()
.expect("unable to get str")
});
println!("cargo:rustc-link-lib=static=webp");
bindgen::Builder::default()
.header(webp_files.decode_header_file.to_str().expect("PathBuf as str"))
.header(webp_files.encode_header_file.to_str().expect("PathBuf as str"))
.header(webp_files.types_header_file.to_str().expect("PathBuf as str"))
.generate_comments(true)
.generate()
.expect("Unable to generate bindings")
.write_to_file(out_path.join("bindings.rs"))
.expect("Couldn't write bindings!");
}
fn build_docs_only() {
let out_path = PathBuf::from(std::env::var("OUT_DIR").unwrap());
bindgen::Builder::default()
.header("include/webp/decode.h")
.header("include/webp/encode.h")
.header("include/webp/types.h")
.generate()
.expect("Unable to generate bindings")
.write_to_file(out_path.join("bindings.rs"))
.expect("Couldn't write bindings!");
}
fn main() {
cc::Build::new()
.file("cbits/encoder.c")
.file("cbits/decoder.c")
.compile("cbits");
#[cfg(feature="buildtype-docs-only")]
build_docs_only();
#[cfg(not(feature="buildtype-docs-only"))]
build_all();
}