Bug 1888590 - Mark some subtests on trusted-types-event-handlers.html as failing...
[gecko.git] / third_party / rust / ohttp / build.rs
bloba63be2c1c393c2c263b167703d28df9f35659039
1 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
2 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
3 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
4 // option. This file may not be copied, modified, or distributed
5 // except according to those terms.
7 #![deny(clippy::pedantic)]
9 #[cfg(feature = "nss")]
10 mod nss {
11     use bindgen::Builder;
12     use serde_derive::Deserialize;
13     use std::{
14         collections::HashMap,
15         env, fs,
16         path::{Path, PathBuf},
17         process::Command,
18     };
20     const BINDINGS_DIR: &str = "bindings";
21     const BINDINGS_CONFIG: &str = "bindings.toml";
23     // This is the format of a single section of the configuration file.
24     #[derive(Deserialize)]
25     struct Bindings {
26         /// types that are explicitly included
27         #[serde(default)]
28         types: Vec<String>,
29         /// functions that are explicitly included
30         #[serde(default)]
31         functions: Vec<String>,
32         /// variables (and `#define`s) that are explicitly included
33         #[serde(default)]
34         variables: Vec<String>,
35         /// types that should be explicitly marked as opaque
36         #[serde(default)]
37         opaque: Vec<String>,
38         /// enumerations that are turned into a module (without this, the enum is
39         /// mapped using the default, which means that the individual values are
40         /// formed with an underscore as <enum_type>_<enum_value_name>).
41         #[serde(default)]
42         enums: Vec<String>,
44         /// Any item that is specifically excluded; if none of the types, functions,
45         /// or variables fields are specified, everything defined will be mapped,
46         /// so this can be used to limit that.
47         #[serde(default)]
48         exclude: Vec<String>,
50         /// Whether the file is to be interpreted as C++
51         #[serde(default)]
52         cplusplus: bool,
53     }
55     fn is_debug() -> bool {
56         env::var("DEBUG")
57             .map(|d| d.parse::<bool>().unwrap_or(false))
58             .unwrap_or(false)
59     }
61     // bindgen needs access to libclang.
62     // On windows, this doesn't just work, you have to set LIBCLANG_PATH.
63     // Rather than download the 400Mb+ files, like gecko does, let's just reuse their work.
64     fn setup_clang() {
65         if env::consts::OS != "windows" {
66             return;
67         }
68         println!("rerun-if-env-changed=LIBCLANG_PATH");
69         println!("rerun-if-env-changed=MOZBUILD_STATE_PATH");
70         if env::var("LIBCLANG_PATH").is_ok() {
71             return;
72         }
73         let mozbuild_root = if let Ok(dir) = env::var("MOZBUILD_STATE_PATH") {
74             PathBuf::from(dir.trim())
75         } else {
76             eprintln!("warning: Building without a gecko setup is not likely to work.");
77             eprintln!("         A working libclang is needed to build neqo.");
78             eprintln!("         Either LIBCLANG_PATH or MOZBUILD_STATE_PATH needs to be set.");
79             eprintln!();
80             eprintln!("    We recommend checking out https://github.com/mozilla/gecko-dev");
81             eprintln!("    Then run `./mach bootstrap` which will retrieve clang.");
82             eprintln!("    Make sure to export MOZBUILD_STATE_PATH when building.");
83             return;
84         };
85         let libclang_dir = mozbuild_root.join("clang").join("lib");
86         if libclang_dir.is_dir() {
87             env::set_var("LIBCLANG_PATH", libclang_dir.to_str().unwrap());
88             println!("rustc-env:LIBCLANG_PATH={}", libclang_dir.to_str().unwrap());
89         } else {
90             println!("warning: LIBCLANG_PATH isn't set; maybe run ./mach bootstrap with gecko");
91         }
92     }
94     fn nss_dir() -> Option<PathBuf> {
95         // Note that this returns a relative path because UNC
96         // paths on windows cause certain tools to explode.
97         env::var("NSS_DIR").ok().map(|dir| {
98             let dir = PathBuf::from(dir.trim());
99             assert!(dir.is_dir());
100             dir
101         })
102     }
104     fn get_bash() -> PathBuf {
105         // When running under MOZILLABUILD, we need to make sure not to invoke
106         // another instance of bash that might be sitting around (like WSL).
107         match env::var("MOZILLABUILD") {
108             Ok(d) => PathBuf::from(d).join("msys").join("bin").join("bash.exe"),
109             Err(_) => PathBuf::from("bash"),
110         }
111     }
113     fn run_build_script(dir: &Path) {
114         let mut build_nss = vec![
115             String::from("./build.sh"),
116             String::from("-Ddisable_tests=1"),
117             String::from("-Denable_draft_hpke=1"),
118         ];
119         if is_debug() {
120             build_nss.push(String::from("--static"));
121         } else {
122             build_nss.push(String::from("-o"));
123         }
124         if let Ok(d) = env::var("NSS_JOBS") {
125             build_nss.push(String::from("-j"));
126             build_nss.push(d);
127         }
128         let status = Command::new(get_bash())
129             .args(build_nss)
130             .current_dir(dir)
131             .status()
132             .expect("couldn't start NSS build");
133         assert!(status.success(), "NSS build failed");
134     }
136     fn dynamic_link() {
137         let libs = if env::consts::OS == "windows" {
138             &["nssutil3.dll", "nss3.dll"]
139         } else {
140             &["nssutil3", "nss3"]
141         };
142         dynamic_link_both(libs);
143     }
145     fn dynamic_link_both(extra_libs: &[&str]) {
146         let nspr_libs = if env::consts::OS == "windows" {
147             &["libplds4", "libplc4", "libnspr4"]
148         } else {
149             &["plds4", "plc4", "nspr4"]
150         };
151         for lib in nspr_libs.iter().chain(extra_libs) {
152             println!("cargo:rustc-link-lib=dylib={}", lib);
153         }
154     }
156     fn static_link() {
157         let mut static_libs = vec![
158             "certdb",
159             "certhi",
160             "cryptohi",
161             "freebl",
162             "nss_static",
163             "nssb",
164             "nssdev",
165             "nsspki",
166             "nssutil",
167             "pk11wrap",
168             "pkcs12",
169             "pkcs7",
170             "smime",
171             "softokn_static",
172         ];
173         if env::consts::OS != "macos" {
174             static_libs.push("sqlite");
175         }
176         for lib in static_libs {
177             println!("cargo:rustc-link-lib=static={}", lib);
178         }
180         // Dynamic libs that aren't transitively included by NSS libs.
181         let mut other_libs = Vec::new();
182         if env::consts::OS != "windows" {
183             other_libs.extend_from_slice(&["pthread", "dl", "c", "z"]);
184         }
185         if env::consts::OS == "macos" {
186             other_libs.push("sqlite3");
187         }
188         dynamic_link_both(&other_libs);
189     }
191     fn get_includes(nsstarget: &Path, nssdist: &Path) -> Vec<PathBuf> {
192         let nsprinclude = nsstarget.join("include").join("nspr");
193         let nssinclude = nssdist.join("public").join("nss");
194         let includes = vec![nsprinclude, nssinclude];
195         for i in &includes {
196             println!("cargo:include={}", i.to_str().unwrap());
197         }
198         includes
199     }
201     fn build_bindings(base: &str, bindings: &Bindings, flags: &[String]) {
202         let suffix = if bindings.cplusplus { ".hpp" } else { ".h" };
203         let header_path = PathBuf::from(BINDINGS_DIR).join(String::from(base) + suffix);
204         let header = header_path.to_str().unwrap();
205         let out = PathBuf::from(env::var("OUT_DIR").unwrap()).join(String::from(base) + ".rs");
207         println!("cargo:rerun-if-changed={}", header);
209         let mut builder = Builder::default().header(header);
210         builder = builder.generate_comments(false);
211         builder = builder.size_t_is_usize(true);
213         builder = builder.clang_arg("-v");
215         builder = builder.clang_arg("-DNO_NSPR_10_SUPPORT");
216         if env::consts::OS == "windows" {
217             builder = builder.clang_arg("-DWIN");
218         } else if env::consts::OS == "macos" {
219             builder = builder.clang_arg("-DDARWIN");
220         } else if env::consts::OS == "linux" {
221             builder = builder.clang_arg("-DLINUX");
222         } else if env::consts::OS == "android" {
223             builder = builder.clang_arg("-DLINUX");
224             builder = builder.clang_arg("-DANDROID");
225         }
226         if bindings.cplusplus {
227             builder = builder.clang_args(&["-x", "c++", "-std=c++11"]);
228         }
230         builder = builder.clang_args(flags);
232         // Apply the configuration.
233         for v in &bindings.types {
234             builder = builder.allowlist_type(v);
235         }
236         for v in &bindings.functions {
237             builder = builder.allowlist_function(v);
238         }
239         for v in &bindings.variables {
240             builder = builder.allowlist_var(v);
241         }
242         for v in &bindings.exclude {
243             builder = builder.blocklist_item(v);
244         }
245         for v in &bindings.opaque {
246             builder = builder.opaque_type(v);
247         }
248         for v in &bindings.enums {
249             builder = builder.constified_enum_module(v);
250         }
252         let bindings = builder.generate().expect("unable to generate bindings");
253         bindings
254             .write_to_file(out)
255             .expect("couldn't write bindings");
256     }
258     fn build_nss(nss: &Path) -> Vec<String> {
259         setup_clang();
261         run_build_script(nss);
263         // $NSS_DIR/../dist/
264         let nssdist = nss.parent().unwrap().join("dist");
265         println!("cargo:rerun-if-env-changed=NSS_TARGET");
266         let nsstarget = env::var("NSS_TARGET")
267             .unwrap_or_else(|_| fs::read_to_string(nssdist.join("latest")).unwrap());
268         let nsstarget = nssdist.join(nsstarget.trim());
270         let includes = get_includes(&nsstarget, &nssdist);
272         let nsslibdir = nsstarget.join("lib");
273         println!(
274             "cargo:rustc-link-search=native={}",
275             nsslibdir.to_str().unwrap()
276         );
277         if is_debug() {
278             static_link();
279         } else {
280             dynamic_link();
281         }
283         let mut flags: Vec<String> = Vec::new();
284         for i in includes {
285             flags.push(String::from("-I") + i.to_str().unwrap());
286         }
288         flags
289     }
291     fn pkg_config() -> Vec<String> {
292         let modversion = Command::new("pkg-config")
293             .args(&["--modversion", "nss"])
294             .output()
295             .expect("pkg-config reports NSS as absent")
296             .stdout;
297         let modversion_str = String::from_utf8(modversion).expect("non-UTF8 from pkg-config");
298         let mut v = modversion_str.split('.');
299         assert_eq!(
300             v.next(),
301             Some("3"),
302             "NSS version 3.62 or higher is needed (or set $NSS_DIR)"
303         );
304         if let Some(minor) = v.next() {
305             let minor = minor
306                 .trim_end()
307                 .parse::<u32>()
308                 .expect("NSS minor version is not a number");
309             assert!(
310                 minor >= 62,
311                 "NSS version 3.62 or higher is needed (or set $NSS_DIR)",
312             );
313         }
315         let cfg = Command::new("pkg-config")
316             .args(&["--cflags", "--libs", "nss"])
317             .output()
318             .expect("NSS flags not returned by pkg-config")
319             .stdout;
320         let cfg_str = String::from_utf8(cfg).expect("non-UTF8 from pkg-config");
322         let mut flags: Vec<String> = Vec::new();
323         for f in cfg_str.split(' ') {
324             if let Some(include) = f.strip_prefix("-I") {
325                 flags.push(String::from(f));
326                 println!("cargo:include={}", include);
327             } else if let Some(path) = f.strip_prefix("-L") {
328                 println!("cargo:rustc-link-search=native={}", path);
329             } else if let Some(lib) = f.strip_prefix("-l") {
330                 println!("cargo:rustc-link-lib=dylib={}", lib);
331             } else {
332                 println!("Warning: Unknown flag from pkg-config: {}", f);
333             }
334         }
336         flags
337     }
339     #[cfg(feature = "gecko")]
340     fn setup_for_gecko() -> Vec<String> {
341         use mozbuild::TOPOBJDIR;
343         let mut flags: Vec<String> = Vec::new();
345         let fold_libs = mozbuild::config::MOZ_FOLD_LIBS;
346         let libs = if fold_libs {
347             vec!["nss3"]
348         } else {
349             vec!["nssutil3", "nss3", "ssl3", "plds4", "plc4", "nspr4"]
350         };
352         for lib in &libs {
353             println!("cargo:rustc-link-lib=dylib={}", lib);
354         }
356         if fold_libs {
357             println!(
358                 "cargo:rustc-link-search=native={}",
359                 TOPOBJDIR.join("security").to_str().unwrap()
360             );
361         } else {
362             println!(
363                 "cargo:rustc-link-search=native={}",
364                 TOPOBJDIR.join("dist").join("bin").to_str().unwrap()
365             );
366             let nsslib_path = TOPOBJDIR.join("security").join("nss").join("lib");
367             println!(
368                 "cargo:rustc-link-search=native={}",
369                 nsslib_path.join("nss").join("nss_nss3").to_str().unwrap()
370             );
371             println!(
372                 "cargo:rustc-link-search=native={}",
373                 nsslib_path.join("ssl").join("ssl_ssl3").to_str().unwrap()
374             );
375             println!(
376                 "cargo:rustc-link-search=native={}",
377                 TOPOBJDIR
378                     .join("config")
379                     .join("external")
380                     .join("nspr")
381                     .join("pr")
382                     .to_str()
383                     .unwrap()
384             );
385         }
387         let flags_path = TOPOBJDIR.join("netwerk/socket/neqo/extra-bindgen-flags");
389         println!("cargo:rerun-if-changed={}", flags_path.to_str().unwrap());
390         flags = fs::read_to_string(flags_path)
391             .expect("Failed to read extra-bindgen-flags file")
392             .split_whitespace()
393             .map(std::borrow::ToOwned::to_owned)
394             .collect();
396         flags.push(String::from("-include"));
397         flags.push(
398             TOPOBJDIR
399                 .join("dist")
400                 .join("include")
401                 .join("mozilla-config.h")
402                 .to_str()
403                 .unwrap()
404                 .to_string(),
405         );
406         flags
407     }
409     #[cfg(not(feature = "gecko"))]
410     fn setup_for_gecko() -> Vec<String> {
411         unreachable!()
412     }
414     pub fn build() {
415         println!("cargo:rerun-if-env-changed=NSS_DIR");
416         let flags = if cfg!(feature = "gecko") {
417             setup_for_gecko()
418         } else {
419             nss_dir().map_or_else(pkg_config, |nss| build_nss(&nss))
420         };
422         let config_file = PathBuf::from(BINDINGS_DIR).join(BINDINGS_CONFIG);
423         println!("cargo:rerun-if-changed={}", config_file.to_str().unwrap());
424         let config = fs::read_to_string(config_file).expect("unable to read binding configuration");
425         let config: HashMap<String, Bindings> = ::toml::from_str(&config).unwrap();
427         for (k, v) in &config {
428             build_bindings(k, v, &flags[..]);
429         }
430     }
433 fn main() {
434     #[cfg(feature = "nss")]
435     nss::build();