blob: 138e9d875441269e733ffa8b49f17472e08fa0d0 [file] [log] [blame] [edit]
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();
}