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