/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ //! Build script for the Gecko Profiler bindings. //! //! This file is executed by cargo when this crate is built. It generates the //! `$OUT_DIR/bindings.rs` file which is then included by `src/gecko_bindings/mod.rs`. #[macro_use] extern crate lazy_static; use bindgen::{Builder, CargoCallbacks, CodegenConfig}; use std::env; use std::fs; use std::path::PathBuf; lazy_static! { static ref OUTDIR_PATH: PathBuf = PathBuf::from(env::var_os("OUT_DIR").unwrap()).join("gecko"); } const BINDINGS_FILE: &str = "bindings.rs"; lazy_static! { static ref BINDGEN_FLAGS: Vec = { // Load build-specific config overrides. let path = mozbuild::TOPOBJDIR.join("tools/profiler/rust-api/extra-bindgen-flags"); println!("cargo:rerun-if-changed={}", path.to_str().unwrap()); fs::read_to_string(path).expect("Failed to read extra-bindgen-flags file") .split_whitespace() .map(std::borrow::ToOwned::to_owned) .collect() }; static ref SEARCH_PATHS: Vec = vec![ mozbuild::TOPOBJDIR.join("dist/include"), mozbuild::TOPOBJDIR.join("dist/include/nspr"), ]; } fn search_include(name: &str) -> Option { for path in SEARCH_PATHS.iter() { let file = path.join(name); if file.is_file() { return Some(file); } } None } fn add_include(name: &str) -> String { let file = match search_include(name) { Some(file) => file, None => panic!("Include not found: {}", name), }; let file_path = String::from(file.to_str().unwrap()); println!("cargo:rerun-if-changed={}", file_path); file_path } fn generate_bindings() { let mut builder = Builder::default() .enable_cxx_namespaces() .with_codegen_config(CodegenConfig::TYPES | CodegenConfig::VARS | CodegenConfig::FUNCTIONS) .disable_untagged_union() .size_t_is_usize(true); for dir in SEARCH_PATHS.iter() { builder = builder.clang_arg("-I").clang_arg(dir.to_str().unwrap()); } builder = builder .clang_arg("-include") .clang_arg(add_include("mozilla-config.h")); for item in &*BINDGEN_FLAGS { builder = builder.clang_arg(item); } let bindings = builder .header(add_include("GeckoProfiler.h")) .header(add_include("ProfilerBindings.h")) .allowlist_function("gecko_profiler_.*") .allowlist_var("mozilla::profiler::detail::RacyFeatures::sActiveAndFeatures") .allowlist_type("mozilla::profiler::detail::RacyFeatures") .rustified_enum("mozilla::StackCaptureOptions") .rustified_enum("mozilla::MarkerSchema_Location") .rustified_enum("mozilla::MarkerSchema_Format") .rustified_enum("mozilla::MarkerSchema_Searchable") // Converting std::string to an opaque type makes some platforms build // successfully. Otherwise, it fails to build because MarkerSchema has // some std::strings as its fields. .opaque_type("std::string") // std::vector needs to be converted to an opaque type because, if it's // not an opaque type, bindgen can't find its size properly and // MarkerSchema's total size reduces. That causes a heap buffer overflow. .opaque_type("std::vector") .raw_line("pub use self::root::*;") // Tell cargo to invalidate the built crate whenever any of the // included header files changed. .parse_callbacks(Box::new(CargoCallbacks)) // Finish the builder and generate the bindings. .generate() // Unwrap the Result and panic on failure. .expect("Unable to generate bindings"); let out_file = OUTDIR_PATH.join(BINDINGS_FILE); bindings .write_to_file(out_file) .expect("Couldn't write bindings!"); } fn main() { println!("cargo:rerun-if-changed=build.rs"); println!("cargo:out_dir={}", env::var("OUT_DIR").unwrap()); fs::create_dir_all(&*OUTDIR_PATH).unwrap(); generate_bindings(); }