1 #[cfg(feature = "generate")]
2 extern crate bindgen;
3 extern crate cc;
4 extern crate pkg_config;
5 
6 use pkg_config::Config;
7 use std::env;
8 use std::fmt;
9 use std::fs;
10 use std::path::Path;
11 use std::path::PathBuf;
12 
13 /// # Link Type Enumeration
14 ///
15 /// Holds the different types of linking we support in this
16 /// script. Used to keep track of what the default link type is and
17 /// what override has been specified, if any, in the environment.
18 #[derive(Eq, PartialEq)]
19 enum LinkType {
20     /// Static linking. This corresponds to the `static` type in Cargo.
21     Static,
22     /// Dynamic linking. This corresponds to the `dylib` type in Cargo.
23     Dynamic,
24 }
25 
26 impl fmt::Display for LinkType {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result27     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
28         write!(
29             f,
30             "{}",
31             match self {
32                 &LinkType::Static => "static",
33                 &LinkType::Dynamic => "dylib",
34             }
35         )
36     }
37 }
38 
env_var_bool(name: &str) -> Option<bool>39 fn env_var_bool(name: &str) -> Option<bool> {
40     env::var(name)
41         .ok()
42         .map(|s| match &s.to_string().to_lowercase()[..] {
43             "0" | "no" | "false" => false,
44             _ => true,
45         })
46 }
47 
48 /// # Link Type Override
49 ///
50 /// Retuns the override from the environment, if any is set.
link_type_override() -> Option<LinkType>51 fn link_type_override() -> Option<LinkType> {
52     let dynamic_env = env_var_bool("RUSTONIG_DYNAMIC_LIBONIG").map(|b| match b {
53         true => LinkType::Dynamic,
54         false => LinkType::Static,
55     });
56     let static_env = env_var_bool("RUSTONIG_STATIC_LIBONIG").map(|b| match b {
57         true => LinkType::Static,
58         false => LinkType::Dynamic,
59     });
60 
61     dynamic_env.or(static_env)
62 }
63 
compile()64 fn compile() {
65     bindgen_headers("oniguruma/src/oniguruma.h");
66 
67     let mut cc = cc::Build::new();
68     let out_dir = PathBuf::from(env::var("OUT_DIR").expect("OUT_DIR"));
69     let ref src = Path::new("oniguruma").join("src");
70     let config_h = out_dir.join("config.h");
71 
72     if env_var_bool("CARGO_FEATURE_PRINT_DEBUG").unwrap_or(false) {
73         cc.define("ONIG_DEBUG_PARSE", Some("1"));
74         cc.define("ONIG_DEBUG_COMPILE", Some("1"));
75         cc.define("ONIG_DEBUG_SEARCH", Some("1"));
76         cc.define("ONIG_DEBUG_MATCH", Some("1"));
77     }
78 
79     if !src.exists() {
80         panic!(
81             "Unable to find source files in {}. Is oniguruma submodule checked out?\n\
82              Try git submodule init; git submodule update",
83             src.display()
84         );
85     }
86 
87     let arch = env::var("CARGO_CFG_TARGET_ARCH");
88     let os = env::var("CARGO_CFG_TARGET_OS");
89     let bits = env::var("CARGO_CFG_TARGET_POINTER_WIDTH").unwrap();
90     if let Ok("windows") = os.as_ref().map(String::as_str) {
91         fs::copy(src.join(format!("config.h.win{}", bits)), config_h)
92             .expect("Can't copy config.h.win??");
93     } else {
94         let family = env::var("CARGO_CFG_TARGET_FAMILY");
95         if let Ok("unix") = family.as_ref().map(String::as_str) {
96             cc.define("HAVE_UNISTD_H", Some("1"));
97             cc.define("HAVE_SYS_TYPES_H", Some("1"));
98             cc.define("HAVE_SYS_TIME_H", Some("1"));
99         }
100 
101         // Can't use size_of::<c_long>(), because it'd refer to build arch, not target arch.
102         // so instead assume it's a non-exotic target (LP32/LP64).
103         fs::write(
104             config_h,
105             format!(
106                 "
107             #define HAVE_PROTOTYPES 1
108             #define STDC_HEADERS 1
109             #define HAVE_STRING_H 1
110             #define HAVE_STDARG_H 1
111             #define HAVE_STDLIB_H 1
112             #define HAVE_LIMITS_H 1
113             #define HAVE_INTTYPES_H 1
114             #define SIZEOF_INT 4
115             #define SIZEOF_SHORT 2
116             #define SIZEOF_LONG {0}
117             #define SIZEOF_VOIDP {0}
118             #define SIZEOF_LONG_LONG 8
119         ",
120                 if bits == "64" { "8" } else { "4" }
121             ),
122         )
123         .expect("Can't write config.h to OUT_DIR");
124     }
125     if let Ok("wasm32") = arch.as_ref().map(String::as_str) {
126         cc.define("ONIG_DISABLE_DIRECT_THREADING", Some("1"));
127         if let Ok("unknown") = os.as_ref().map(String::as_str) {
128             cc.define(
129                 "ONIG_EXTERN",
130                 Some(r#"__attribute__((visibility("default")))"#),
131             );
132         }
133     }
134 
135     cc.include(out_dir); // Read config.h from there
136     cc.include(src);
137 
138     let files = [
139         "regexec.c",
140         "regerror.c",
141         "regparse.c",
142         "regext.c",
143         "regcomp.c",
144         "reggnu.c",
145         "regenc.c",
146         "regsyntax.c",
147         "regtrav.c",
148         "regversion.c",
149         "st.c",
150         "onig_init.c",
151         "unicode.c",
152         "ascii.c",
153         "utf8.c",
154         "utf16_be.c",
155         "utf16_le.c",
156         "utf32_be.c",
157         "utf32_le.c",
158         "euc_jp.c",
159         "sjis.c",
160         "iso8859_1.c",
161         "iso8859_2.c",
162         "iso8859_3.c",
163         "iso8859_4.c",
164         "iso8859_5.c",
165         "iso8859_6.c",
166         "iso8859_7.c",
167         "iso8859_8.c",
168         "iso8859_9.c",
169         "iso8859_10.c",
170         "iso8859_11.c",
171         "iso8859_13.c",
172         "iso8859_14.c",
173         "iso8859_15.c",
174         "iso8859_16.c",
175         "euc_tw.c",
176         "euc_kr.c",
177         "big5.c",
178         "gb18030.c",
179         "koi8_r.c",
180         "cp1251.c",
181         "euc_jp_prop.c",
182         "sjis_prop.c",
183         "unicode_unfold_key.c",
184         "unicode_fold1_key.c",
185         "unicode_fold2_key.c",
186         "unicode_fold3_key.c",
187     ];
188     for file in files.iter() {
189         cc.file(src.join(file));
190     }
191 
192     if cfg!(feature = "posix-api") {
193         cc.file(src.join("regposix.c"));
194         cc.file(src.join("regposerr.c"));
195     }
196 
197     cc.warnings(false); // not actionable by the end user
198     cc.compile("onig");
199 }
200 
201 #[cfg(not(feature = "generate"))]
bindgen_headers(_path: &str)202 fn bindgen_headers(_path: &str) {}
203 
204 #[cfg(feature = "generate")]
bindgen_headers(path: &str)205 fn bindgen_headers(path: &str) {
206     let arch = env::var("CARGO_CFG_TARGET_ARCH");
207     let mut bindgen = bindgen::Builder::default()
208         .header(path)
209         .derive_eq(true)
210         .layout_tests(false);
211     if let Ok("wasm32") = arch.as_ref().map(String::as_str) {
212         bindgen = bindgen.clang_arg("-fvisibility=default");
213     }
214     let bindings = bindgen.generate().expect("bindgen");
215     let out_dir = env::var_os("OUT_DIR").expect("OUT_DIR");
216     let out_path = Path::new(&out_dir);
217     bindings
218         .write_to_file(out_path.join("bindings.rs"))
219         .expect("Couldn't write bindings!");
220 }
221 
main()222 pub fn main() {
223     let link_type = link_type_override();
224     let require_pkg_config = env_var_bool("RUSTONIG_SYSTEM_LIBONIG").unwrap_or(false);
225 
226     if require_pkg_config || link_type == Some(LinkType::Dynamic) {
227         let mut conf = Config::new();
228         // dynamically-generated headers can work with an older version
229         // pre-generated headers are for the latest
230         conf.atleast_version(if cfg!(feature = "generate") {
231             "6.8.0"
232         } else {
233             "6.9.3"
234         });
235         if link_type == Some(LinkType::Static) {
236             conf.statik(true);
237         }
238         match conf.probe("oniguruma") {
239             Ok(lib) => {
240                 for path in &lib.include_paths {
241                     let header = path.join("oniguruma.h");
242                     if header.exists() {
243                         bindgen_headers(&header.display().to_string());
244                         return;
245                     }
246                 }
247                 if require_pkg_config {
248                     panic!(
249                         "Unable to find oniguruma.h in include paths from pkg-config: {:?}",
250                         lib.include_paths
251                     );
252                 }
253             }
254             Err(ref err) if require_pkg_config => {
255                 panic!("Unable to find oniguruma in pkg-config, and RUSTONIG_SYSTEM_LIBONIG is set: {}", err);
256             }
257             _ => {}
258         }
259     }
260 
261     compile();
262 }
263