use std::collections::HashMap; struct Configs { lto: bool, clang: bool, bignum: bool, werror: bool, win32: bool, profile: bool, asan: bool, } impl Default for Configs { fn default() -> Self { let config_darwin = std::env::consts::OS == "macos"; let config_clang = config_darwin; Self { lto: false, clang: config_clang, bignum: true, werror: false, win32: std::env::consts::OS == "windows", profile: false, asan: false, } } } impl Configs { fn cflags(&self) -> Vec<&'static str> { let mut cflags = Vec::new(); if self.clang { cflags.extend_from_slice(&[ "-g", "-w", // "-Wall", // "-Wextra", // "-Wno-sign-compare", // "-Wno-missing-field-initializers", // "-Wundef", // "-Wuninitialized", // "-Wunused", // "-Wno-unused-parameter", // "-Wwrite-strings", // "-Wchar-subscripts", ]); } else { cflags.extend_from_slice(&[ "-g", "-w", // "-Wall", // "-Wno-array-bounds", // "-Wno-format-truncation", ]); } cflags.extend_from_slice(&["-fwrapv"]); if self.werror { cflags.extend_from_slice(&["-Werror"]); } cflags.extend_from_slice(&["-O2"]); if self.lto { cflags.extend_from_slice(&["-flto"]); } if self.profile { cflags.extend_from_slice(&["-p"]) } if self.asan { cflags.extend_from_slice(&["-fsanitize=address", "-fno-omit-frame-pointer"]) } cflags } fn defines(&self) -> HashMap<&'static str, Option> { let mut defines = HashMap::new(); defines.insert("_GNU_SOURCE", None); defines.insert( "CONFIG_VERSION", Some( "\"".to_string() + String::from_utf8( std::fs::read("deps/quickjs/VERSION").expect("Cannot read VERSION."), ) .expect("VERSION encoding error.") .trim() + "\"", ), ); if self.bignum { defines.insert("CONFIG_BIGNUM", None); } if self.win32 { defines.insert("__USE_MINGW_ANSI_STDIO", None); } defines } fn ldflags(&self) -> Vec<&'static str> { let mut ldflags = Vec::new(); ldflags.extend_from_slice(&["-g"]); if self.lto { ldflags.extend_from_slice(&["-flto"]); } if self.profile { ldflags.extend_from_slice(&["-p"]); } if self.asan { ldflags.extend_from_slice(&["-fsanitize=address", "-fno-omit-frame-pointer"]) } ldflags } fn libs(&self) -> Vec<&'static str> { let mut libs = Vec::new(); libs.extend_from_slice(&["-lm", "-lpthread"]); if !self.win32 { libs.extend_from_slice(&["-ldl"]); } libs } } fn compile(configs: &Configs) { let cflags = configs.cflags(); let ldflags = configs.ldflags(); let libs = configs.libs(); let defines = configs.defines(); let mut cc_builder = cc::Build::new(); cc_builder.files([ "deps/quickjs/quickjs.c", "deps/quickjs/libregexp.c", "deps/quickjs/libunicode.c", "deps/quickjs/cutils.c", "deps/quickjs/quickjs-libc.c", "deps/quickjs/libbf.c", ]); for cflag in cflags { cc_builder.flag_if_supported(cflag); } for ldflag in ldflags { cc_builder.flag_if_supported(ldflag); } for lib in libs { cc_builder.flag(lib); } for (name, value) in defines { if let Some(value) = value { cc_builder.define(name, value.as_str()); } else { cc_builder.define(name, None); } } cc_builder.compile("libquickjs.a"); } fn bindgen(configs: &Configs) { let bindings = bindgen::Builder::default() .header("deps/quickjs/quickjs.h") .header("deps/quickjs/quickjs-libc.h") .header("deps/quickjs/cutils.h") .generate() .expect("Unable to generate bindings."); let out_path = std::path::PathBuf::from(std::env::var("OUT_DIR").expect("OUT_DIR not defined.")); bindings .write_to_file(out_path.join("quickjs_bindings.rs")) .expect("Couldn't write bindings!"); } fn main() { println!("cargo:rerun-if-changed=deps"); let configs = Configs::default(); compile(&configs); bindgen(&configs); }