1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
5 //! Build script for the Gecko Profiler bindings.
7 //! This file is executed by cargo when this crate is built. It generates the
8 //! `$OUT_DIR/bindings.rs` file which is then included by `src/gecko_bindings/mod.rs`.
11 extern crate lazy_static;
13 use bindgen::{Builder, CodegenConfig};
16 use std::path::PathBuf;
19 static ref OUTDIR_PATH: PathBuf = PathBuf::from(env::var_os("OUT_DIR").unwrap()).join("gecko");
22 const BINDINGS_FILE: &str = "bindings.rs";
25 static ref BINDGEN_FLAGS: Vec<String> = {
26 // Load build-specific config overrides.
27 let path = mozbuild::TOPOBJDIR.join("tools/profiler/rust-api/extra-bindgen-flags");
28 println!("cargo:rerun-if-changed={}", path.to_str().unwrap());
29 fs::read_to_string(path).expect("Failed to read extra-bindgen-flags file")
31 .map(std::borrow::ToOwned::to_owned)
34 static ref SEARCH_PATHS: Vec<PathBuf> = vec![
35 mozbuild::TOPOBJDIR.join("dist/include"),
36 mozbuild::TOPOBJDIR.join("dist/include/nspr"),
40 fn search_include(name: &str) -> Option<PathBuf> {
41 for path in SEARCH_PATHS.iter() {
42 let file = path.join(name);
50 fn add_include(name: &str) -> String {
51 let file = match search_include(name) {
53 None => panic!("Include not found: {}", name),
55 let file_path = String::from(file.to_str().unwrap());
56 println!("cargo:rerun-if-changed={}", file_path);
60 fn generate_bindings() {
61 let mut builder = Builder::default()
62 .enable_cxx_namespaces()
63 .with_codegen_config(CodegenConfig::TYPES | CodegenConfig::VARS | CodegenConfig::FUNCTIONS)
64 .disable_untagged_union()
65 .size_t_is_usize(true);
67 for dir in SEARCH_PATHS.iter() {
68 builder = builder.clang_arg("-I").clang_arg(dir.to_str().unwrap());
72 .clang_arg("-include")
73 .clang_arg(add_include("mozilla-config.h"));
75 for item in &*BINDGEN_FLAGS {
76 builder = builder.clang_arg(item);
79 let bindings = builder
80 .header(add_include("GeckoProfiler.h"))
81 .header(add_include("ProfilerBindings.h"))
82 .allowlist_function("gecko_profiler_.*")
83 .allowlist_var("mozilla::profiler::detail::RacyFeatures::sActiveAndFeatures")
84 .allowlist_type("mozilla::profiler::detail::RacyFeatures")
85 .rustified_enum("mozilla::StackCaptureOptions")
86 .rustified_enum("mozilla::MarkerSchema_Location")
87 .rustified_enum("mozilla::MarkerSchema_Format")
88 .rustified_enum("mozilla::MarkerSchema_Searchable")
89 // Converting std::string to an opaque type makes some platforms build
90 // successfully. Otherwise, it fails to build because MarkerSchema has
91 // some std::strings as its fields.
92 .opaque_type("std::string")
93 // std::vector needs to be converted to an opaque type because, if it's
94 // not an opaque type, bindgen can't find its size properly and
95 // MarkerSchema's total size reduces. That causes a heap buffer overflow.
96 .opaque_type("std::vector")
97 .raw_line("pub use self::root::*;")
98 // Tell cargo to invalidate the built crate whenever any of the
99 // included header files changed.
100 .parse_callbacks(Box::new(bindgen::CargoCallbacks::new()))
101 // Finish the builder and generate the bindings.
103 // Unwrap the Result and panic on failure.
104 .expect("Unable to generate bindings");
106 let out_file = OUTDIR_PATH.join(BINDINGS_FILE);
108 .write_to_file(out_file)
109 .expect("Couldn't write bindings!");
113 println!("cargo:rerun-if-changed=build.rs");
114 println!("cargo:out_dir={}", env::var("OUT_DIR").unwrap());
116 fs::create_dir_all(&*OUTDIR_PATH).unwrap();