| use pkg_config::Config; |
| use std::env; |
| use std::fmt; |
| use std::fs; |
| use std::path::Path; |
| use std::path::PathBuf; |
| |
| /// # Link Type Enumeration |
| /// |
| /// Holds the different types of linking we support in this |
| /// script. Used to keep track of what the default link type is and |
| /// what override has been specified, if any, in the environment. |
| #[derive(Eq, PartialEq)] |
| enum LinkType { |
| /// Static linking. This corresponds to the `static` type in Cargo. |
| Static, |
| /// Dynamic linking. This corresponds to the `dylib` type in Cargo. |
| Dynamic, |
| } |
| |
| impl fmt::Display for LinkType { |
| fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
| write!( |
| f, |
| "{}", |
| match self { |
| &LinkType::Static => "static", |
| &LinkType::Dynamic => "dylib", |
| } |
| ) |
| } |
| } |
| |
| fn env_var_bool(name: &str) -> Option<bool> { |
| if name.starts_with("RUSTONIG") { |
| println!("cargo:rerun-if-env-changed={}", name); |
| } |
| env::var(name) |
| .ok() |
| .map(|s| match &s.to_string().to_lowercase()[..] { |
| "0" | "no" | "false" => false, |
| _ => true, |
| }) |
| } |
| |
| /// # Link Type Override |
| /// |
| /// Retuns the override from the environment, if any is set. |
| fn link_type_override() -> Option<LinkType> { |
| let dynamic_env = env_var_bool("RUSTONIG_DYNAMIC_LIBONIG").map(|b| match b { |
| true => LinkType::Dynamic, |
| false => LinkType::Static, |
| }); |
| let static_env = env_var_bool("RUSTONIG_STATIC_LIBONIG").map(|b| match b { |
| true => LinkType::Static, |
| false => LinkType::Dynamic, |
| }); |
| |
| dynamic_env.or(static_env) |
| } |
| |
| fn compile() { |
| bindgen_headers("oniguruma/src/oniguruma.h"); |
| |
| let mut cc = cc::Build::new(); |
| let out_dir = PathBuf::from(env::var("OUT_DIR").expect("OUT_DIR")); |
| let ref src = Path::new("oniguruma").join("src"); |
| let config_h = out_dir.join("config.h"); |
| |
| if env_var_bool("CARGO_FEATURE_PRINT_DEBUG").unwrap_or(false) { |
| cc.define("ONIG_DEBUG_PARSE", Some("1")); |
| cc.define("ONIG_DEBUG_COMPILE", Some("1")); |
| cc.define("ONIG_DEBUG_SEARCH", Some("1")); |
| cc.define("ONIG_DEBUG_MATCH", Some("1")); |
| } |
| |
| if !src.exists() { |
| panic!( |
| "Unable to find source files in {}. Is oniguruma submodule checked out?\n\ |
| Try git submodule init; git submodule update", |
| src.display() |
| ); |
| } |
| |
| let arch = env::var("CARGO_CFG_TARGET_ARCH"); |
| let os = env::var("CARGO_CFG_TARGET_OS"); |
| let bits = env::var("CARGO_CFG_TARGET_POINTER_WIDTH").unwrap(); |
| if let Ok("windows") = os.as_ref().map(String::as_str) { |
| fs::copy(src.join(format!("config.h.win{}", bits)), config_h) |
| .expect("Can't copy config.h.win??"); |
| } else { |
| let family = env::var("CARGO_CFG_TARGET_FAMILY"); |
| if let Ok("unix") = family.as_ref().map(String::as_str) { |
| cc.define("HAVE_UNISTD_H", Some("1")); |
| cc.define("HAVE_SYS_TYPES_H", Some("1")); |
| cc.define("HAVE_SYS_TIME_H", Some("1")); |
| } |
| |
| // Can't use size_of::<c_long>(), because it'd refer to build arch, not target arch. |
| // so instead assume it's a non-exotic target (LP32/LP64). |
| fs::write( |
| config_h, |
| format!( |
| " |
| #define HAVE_PROTOTYPES 1 |
| #define STDC_HEADERS 1 |
| #define HAVE_STRING_H 1 |
| #define HAVE_STDARG_H 1 |
| #define HAVE_STDLIB_H 1 |
| #define HAVE_LIMITS_H 1 |
| #define HAVE_INTTYPES_H 1 |
| #define SIZEOF_INT 4 |
| #define SIZEOF_SHORT 2 |
| #define SIZEOF_LONG {0} |
| #define SIZEOF_VOIDP {0} |
| #define SIZEOF_LONG_LONG 8 |
| ", |
| if bits == "64" { "8" } else { "4" } |
| ), |
| ) |
| .expect("Can't write config.h to OUT_DIR"); |
| } |
| if let Ok("wasm32") = arch.as_ref().map(String::as_str) { |
| cc.define("ONIG_DISABLE_DIRECT_THREADING", Some("1")); |
| if let Ok("unknown") = os.as_ref().map(String::as_str) { |
| cc.define( |
| "ONIG_EXTERN", |
| Some(r#"__attribute__((visibility("default")))"#), |
| ); |
| } |
| } |
| |
| cc.include(out_dir); // Read config.h from there |
| cc.include(src); |
| |
| let files = [ |
| "regexec.c", |
| "regerror.c", |
| "regparse.c", |
| "regext.c", |
| "regcomp.c", |
| "reggnu.c", |
| "regenc.c", |
| "regsyntax.c", |
| "regtrav.c", |
| "regversion.c", |
| "st.c", |
| "onig_init.c", |
| "unicode.c", |
| "ascii.c", |
| "utf8.c", |
| "utf16_be.c", |
| "utf16_le.c", |
| "utf32_be.c", |
| "utf32_le.c", |
| "euc_jp.c", |
| "sjis.c", |
| "iso8859_1.c", |
| "iso8859_2.c", |
| "iso8859_3.c", |
| "iso8859_4.c", |
| "iso8859_5.c", |
| "iso8859_6.c", |
| "iso8859_7.c", |
| "iso8859_8.c", |
| "iso8859_9.c", |
| "iso8859_10.c", |
| "iso8859_11.c", |
| "iso8859_13.c", |
| "iso8859_14.c", |
| "iso8859_15.c", |
| "iso8859_16.c", |
| "euc_tw.c", |
| "euc_kr.c", |
| "big5.c", |
| "gb18030.c", |
| "koi8_r.c", |
| "cp1251.c", |
| "euc_jp_prop.c", |
| "sjis_prop.c", |
| "unicode_unfold_key.c", |
| "unicode_fold1_key.c", |
| "unicode_fold2_key.c", |
| "unicode_fold3_key.c", |
| ]; |
| for file in files.iter() { |
| cc.file(src.join(file)); |
| } |
| |
| if cfg!(feature = "posix-api") { |
| cc.file(src.join("regposix.c")); |
| cc.file(src.join("regposerr.c")); |
| } |
| |
| cc.warnings(false); // not actionable by the end user |
| cc.compile("onig"); |
| } |
| |
| #[cfg(not(feature = "generate"))] |
| fn bindgen_headers(_path: &str) {} |
| |
| #[cfg(feature = "generate")] |
| fn bindgen_headers(path: &str) { |
| let arch = env::var("CARGO_CFG_TARGET_ARCH"); |
| let mut bindgen = bindgen::Builder::default() |
| .header(path) |
| .derive_eq(true) |
| .layout_tests(false); |
| if let Ok("wasm32") = arch.as_ref().map(String::as_str) { |
| bindgen = bindgen.clang_arg("-fvisibility=default"); |
| } |
| let bindings = bindgen.generate().expect("bindgen"); |
| let out_dir = env::var_os("OUT_DIR").expect("OUT_DIR"); |
| let out_path = Path::new(&out_dir); |
| bindings |
| .write_to_file(out_path.join("bindings.rs")) |
| .expect("Couldn't write bindings!"); |
| } |
| |
| pub fn main() { |
| let link_type = link_type_override(); |
| let require_pkg_config = env_var_bool("RUSTONIG_SYSTEM_LIBONIG").unwrap_or(false); |
| |
| if require_pkg_config || link_type == Some(LinkType::Dynamic) { |
| let mut conf = Config::new(); |
| // dynamically-generated headers can work with an older version |
| // pre-generated headers are for the latest |
| conf.atleast_version(if cfg!(feature = "generate") { |
| "6.8.0" |
| } else { |
| "6.9.3" |
| }); |
| if link_type == Some(LinkType::Static) { |
| conf.statik(true); |
| } |
| match conf.probe("oniguruma") { |
| Ok(lib) => { |
| for path in &lib.include_paths { |
| let header = path.join("oniguruma.h"); |
| if header.exists() { |
| bindgen_headers(&header.display().to_string()); |
| return; |
| } |
| } |
| if require_pkg_config { |
| panic!( |
| "Unable to find oniguruma.h in include paths from pkg-config: {:?}", |
| lib.include_paths |
| ); |
| } |
| } |
| Err(ref err) if require_pkg_config => { |
| panic!("Unable to find oniguruma in pkg-config, and RUSTONIG_SYSTEM_LIBONIG is set: {}", err); |
| } |
| _ => {} |
| } |
| } |
| |
| compile(); |
| } |