diff options
Diffstat (limited to 'third_party/rust/bindgen/lib.rs')
-rw-r--r-- | third_party/rust/bindgen/lib.rs | 3068 |
1 files changed, 3068 insertions, 0 deletions
diff --git a/third_party/rust/bindgen/lib.rs b/third_party/rust/bindgen/lib.rs new file mode 100644 index 0000000000..5374742016 --- /dev/null +++ b/third_party/rust/bindgen/lib.rs @@ -0,0 +1,3068 @@ +//! Generate Rust bindings for C and C++ libraries. +//! +//! Provide a C/C++ header file, receive Rust FFI code to call into C/C++ +//! functions and use types defined in the header. +//! +//! See the [`Builder`](./struct.Builder.html) struct for usage. +//! +//! See the [Users Guide](https://rust-lang.github.io/rust-bindgen/) for +//! additional documentation. +#![deny(missing_docs)] +#![deny(unused_extern_crates)] +// To avoid rather annoying warnings when matching with CXCursor_xxx as a +// constant. +#![allow(non_upper_case_globals)] +// `quote!` nests quite deeply. +#![recursion_limit = "128"] + +#[macro_use] +extern crate bitflags; +#[macro_use] +extern crate lazy_static; +#[macro_use] +extern crate quote; + +#[cfg(feature = "logging")] +#[macro_use] +extern crate log; + +#[cfg(not(feature = "logging"))] +#[macro_use] +mod log_stubs; + +#[macro_use] +mod extra_assertions; + +// A macro to declare an internal module for which we *must* provide +// documentation for. If we are building with the "testing_only_docs" feature, +// then the module is declared public, and our `#![deny(missing_docs)]` pragma +// applies to it. This feature is used in CI, so we won't let anything slip by +// undocumented. Normal builds, however, will leave the module private, so that +// we don't expose internals to library consumers. +macro_rules! doc_mod { + ($m:ident, $doc_mod_name:ident) => { + #[cfg(feature = "testing_only_docs")] + pub mod $doc_mod_name { + //! Autogenerated documentation module. + pub use super::$m::*; + } + }; +} + +macro_rules! fn_with_regex_arg { + ($(#[$attrs:meta])* pub fn $($tokens:tt)*) => { + $(#[$attrs])* + /// Check the [regular expression arguments] section and the [regex] crate + /// documentation for further information. + /// + /// [regular expression arguments]: ./struct.Builder.html#regular-expression-arguments + /// [regex]: <https://docs.rs/regex> + pub fn $($tokens)* + }; +} + +mod clang; +mod codegen; +mod deps; +mod features; +pub mod ir; +mod parse; +mod regex_set; +mod time; + +pub mod callbacks; + +doc_mod!(clang, clang_docs); +doc_mod!(features, features_docs); +doc_mod!(ir, ir_docs); +doc_mod!(parse, parse_docs); +doc_mod!(regex_set, regex_set_docs); + +use codegen::CodegenError; +use ir::comment; + +pub use crate::codegen::{ + AliasVariation, EnumVariation, MacroTypeVariation, NonCopyUnionStyle, +}; +use crate::features::RustFeatures; +pub use crate::features::{ + RustTarget, LATEST_STABLE_RUST, RUST_TARGET_STRINGS, +}; +use crate::ir::context::{BindgenContext, ItemId}; +pub use crate::ir::function::Abi; +use crate::ir::item::Item; +use crate::parse::ParseError; +pub use crate::regex_set::RegexSet; + +use std::borrow::Cow; +use std::env; +use std::fs::{File, OpenOptions}; +use std::io::{self, Write}; +use std::path::{Path, PathBuf}; +use std::process::{Command, Stdio}; +use std::rc::Rc; + +// Some convenient typedefs for a fast hash map and hash set. +type HashMap<K, V> = ::rustc_hash::FxHashMap<K, V>; +type HashSet<K> = ::rustc_hash::FxHashSet<K>; +pub(crate) use std::collections::hash_map::Entry; + +/// Default prefix for the anon fields. +pub const DEFAULT_ANON_FIELDS_PREFIX: &str = "__bindgen_anon_"; +const DEFAULT_NON_EXTERN_FNS_SUFFIX: &str = "__extern"; + +fn file_is_cpp(name_file: &str) -> bool { + name_file.ends_with(".hpp") || + name_file.ends_with(".hxx") || + name_file.ends_with(".hh") || + name_file.ends_with(".h++") +} + +fn args_are_cpp(clang_args: &[String]) -> bool { + for w in clang_args.windows(2) { + if w[0] == "-xc++" || w[1] == "-xc++" { + return true; + } + if w[0] == "-x" && w[1] == "c++" { + return true; + } + if w[0] == "-include" && file_is_cpp(&w[1]) { + return true; + } + } + false +} + +bitflags! { + /// A type used to indicate which kind of items we have to generate. + pub struct CodegenConfig: u32 { + /// Whether to generate functions. + const FUNCTIONS = 1 << 0; + /// Whether to generate types. + const TYPES = 1 << 1; + /// Whether to generate constants. + const VARS = 1 << 2; + /// Whether to generate methods. + const METHODS = 1 << 3; + /// Whether to generate constructors + const CONSTRUCTORS = 1 << 4; + /// Whether to generate destructors. + const DESTRUCTORS = 1 << 5; + } +} + +impl CodegenConfig { + /// Returns true if functions should be generated. + pub fn functions(self) -> bool { + self.contains(CodegenConfig::FUNCTIONS) + } + + /// Returns true if types should be generated. + pub fn types(self) -> bool { + self.contains(CodegenConfig::TYPES) + } + + /// Returns true if constants should be generated. + pub fn vars(self) -> bool { + self.contains(CodegenConfig::VARS) + } + + /// Returns true if methds should be generated. + pub fn methods(self) -> bool { + self.contains(CodegenConfig::METHODS) + } + + /// Returns true if constructors should be generated. + pub fn constructors(self) -> bool { + self.contains(CodegenConfig::CONSTRUCTORS) + } + + /// Returns true if destructors should be generated. + pub fn destructors(self) -> bool { + self.contains(CodegenConfig::DESTRUCTORS) + } +} + +impl Default for CodegenConfig { + fn default() -> Self { + CodegenConfig::all() + } +} + +/// Configure and generate Rust bindings for a C/C++ header. +/// +/// This is the main entry point to the library. +/// +/// ```ignore +/// use bindgen::builder; +/// +/// // Configure and generate bindings. +/// let bindings = builder().header("path/to/input/header") +/// .allowlist_type("SomeCoolClass") +/// .allowlist_function("do_some_cool_thing") +/// .generate()?; +/// +/// // Write the generated bindings to an output file. +/// bindings.write_to_file("path/to/output.rs")?; +/// ``` +/// +/// # Enums +/// +/// Bindgen can map C/C++ enums into Rust in different ways. The way bindgen maps enums depends on +/// the pattern passed to several methods: +/// +/// 1. [`constified_enum_module()`](#method.constified_enum_module) +/// 2. [`bitfield_enum()`](#method.bitfield_enum) +/// 3. [`newtype_enum()`](#method.newtype_enum) +/// 4. [`rustified_enum()`](#method.rustified_enum) +/// +/// For each C enum, bindgen tries to match the pattern in the following order: +/// +/// 1. Constified enum module +/// 2. Bitfield enum +/// 3. Newtype enum +/// 4. Rustified enum +/// +/// If none of the above patterns match, then bindgen will generate a set of Rust constants. +/// +/// # Clang arguments +/// +/// Extra arguments can be passed to with clang: +/// 1. [`clang_arg()`](#method.clang_arg): takes a single argument +/// 2. [`clang_args()`](#method.clang_args): takes an iterator of arguments +/// 3. `BINDGEN_EXTRA_CLANG_ARGS` environment variable: whitespace separate +/// environment variable of arguments +/// +/// Clang arguments specific to your crate should be added via the +/// `clang_arg()`/`clang_args()` methods. +/// +/// End-users of the crate may need to set the `BINDGEN_EXTRA_CLANG_ARGS` environment variable to +/// add additional arguments. For example, to build against a different sysroot a user could set +/// `BINDGEN_EXTRA_CLANG_ARGS` to `--sysroot=/path/to/sysroot`. +/// +/// # Regular expression arguments +/// +/// Some [`Builder`] methods like the `allowlist_*` and `blocklist_*` family of methods allow +/// regular expressions as arguments. These regular expressions will be parenthesized and wrapped +/// in `^` and `$`. So if `<regex>` is passed as argument, the regular expression to be stored will +/// be `^(<regex>)$`. +/// +/// Releases of `bindgen` with a version lesser or equal to `0.62.0` used to accept the wildcard +/// pattern `*` as a valid regular expression. This behavior has been deprecated and the `.*` +/// pattern must be used instead. +#[derive(Debug, Default, Clone)] +pub struct Builder { + options: BindgenOptions, +} + +/// Construct a new [`Builder`](./struct.Builder.html). +pub fn builder() -> Builder { + Default::default() +} + +fn get_extra_clang_args() -> Vec<String> { + // Add any extra arguments from the environment to the clang command line. + let extra_clang_args = + match get_target_dependent_env_var("BINDGEN_EXTRA_CLANG_ARGS") { + None => return vec![], + Some(s) => s, + }; + // Try to parse it with shell quoting. If we fail, make it one single big argument. + if let Some(strings) = shlex::split(&extra_clang_args) { + return strings; + } + vec![extra_clang_args] +} + +impl Builder { + /// Generates the command line flags use for creating `Builder`. + pub fn command_line_flags(&self) -> Vec<String> { + let mut output_vector: Vec<String> = Vec::new(); + + if let Some(header) = self.options.input_headers.last().cloned() { + // Positional argument 'header' + output_vector.push(header); + } + + output_vector.push("--rust-target".into()); + output_vector.push(self.options.rust_target.into()); + + // FIXME(emilio): This is a bit hacky, maybe we should stop re-using the + // RustFeatures to store the "disable_untagged_union" call, and make it + // a different flag that we check elsewhere / in generate(). + if !self.options.rust_features.untagged_union && + RustFeatures::from(self.options.rust_target).untagged_union + { + output_vector.push("--disable-untagged-union".into()); + } + + if self.options.default_enum_style != Default::default() { + output_vector.push("--default-enum-style".into()); + output_vector.push( + match self.options.default_enum_style { + codegen::EnumVariation::Rust { + non_exhaustive: false, + } => "rust", + codegen::EnumVariation::Rust { + non_exhaustive: true, + } => "rust_non_exhaustive", + codegen::EnumVariation::NewType { + is_bitfield: true, + .. + } => "bitfield", + codegen::EnumVariation::NewType { + is_bitfield: false, + is_global, + } => { + if is_global { + "newtype_global" + } else { + "newtype" + } + } + codegen::EnumVariation::Consts => "consts", + codegen::EnumVariation::ModuleConsts => "moduleconsts", + } + .into(), + ) + } + + if self.options.default_macro_constant_type != Default::default() { + output_vector.push("--default-macro-constant-type".into()); + output_vector + .push(self.options.default_macro_constant_type.as_str().into()); + } + + if self.options.default_alias_style != Default::default() { + output_vector.push("--default-alias-style".into()); + output_vector + .push(self.options.default_alias_style.as_str().into()); + } + + if self.options.default_non_copy_union_style != Default::default() { + output_vector.push("--default-non-copy-union-style".into()); + output_vector.push( + self.options.default_non_copy_union_style.as_str().into(), + ); + } + + let regex_sets = &[ + (&self.options.bitfield_enums, "--bitfield-enum"), + (&self.options.newtype_enums, "--newtype-enum"), + (&self.options.newtype_global_enums, "--newtype-global-enum"), + (&self.options.rustified_enums, "--rustified-enum"), + ( + &self.options.rustified_non_exhaustive_enums, + "--rustified-enum-non-exhaustive", + ), + ( + &self.options.constified_enum_modules, + "--constified-enum-module", + ), + (&self.options.constified_enums, "--constified-enum"), + (&self.options.type_alias, "--type-alias"), + (&self.options.new_type_alias, "--new-type-alias"), + (&self.options.new_type_alias_deref, "--new-type-alias-deref"), + ( + &self.options.bindgen_wrapper_union, + "--bindgen-wrapper-union", + ), + (&self.options.manually_drop_union, "--manually-drop-union"), + (&self.options.blocklisted_types, "--blocklist-type"), + (&self.options.blocklisted_functions, "--blocklist-function"), + (&self.options.blocklisted_items, "--blocklist-item"), + (&self.options.blocklisted_files, "--blocklist-file"), + (&self.options.opaque_types, "--opaque-type"), + (&self.options.allowlisted_functions, "--allowlist-function"), + (&self.options.allowlisted_types, "--allowlist-type"), + (&self.options.allowlisted_vars, "--allowlist-var"), + (&self.options.allowlisted_files, "--allowlist-file"), + (&self.options.no_partialeq_types, "--no-partialeq"), + (&self.options.no_copy_types, "--no-copy"), + (&self.options.no_debug_types, "--no-debug"), + (&self.options.no_default_types, "--no-default"), + (&self.options.no_hash_types, "--no-hash"), + (&self.options.must_use_types, "--must-use-type"), + ]; + + for (set, flag) in regex_sets { + for item in set.get_items() { + output_vector.push((*flag).to_owned()); + output_vector.push(item.to_owned()); + } + } + + for (abi, set) in &self.options.abi_overrides { + for item in set.get_items() { + output_vector.push("--override-abi".to_owned()); + output_vector.push(format!("{}={}", item, abi)); + } + } + + if !self.options.layout_tests { + output_vector.push("--no-layout-tests".into()); + } + + if self.options.impl_debug { + output_vector.push("--impl-debug".into()); + } + + if self.options.impl_partialeq { + output_vector.push("--impl-partialeq".into()); + } + + if !self.options.derive_copy { + output_vector.push("--no-derive-copy".into()); + } + + if !self.options.derive_debug { + output_vector.push("--no-derive-debug".into()); + } + + if !self.options.derive_default { + output_vector.push("--no-derive-default".into()); + } else { + output_vector.push("--with-derive-default".into()); + } + + if self.options.derive_hash { + output_vector.push("--with-derive-hash".into()); + } + + if self.options.derive_partialord { + output_vector.push("--with-derive-partialord".into()); + } + + if self.options.derive_ord { + output_vector.push("--with-derive-ord".into()); + } + + if self.options.derive_partialeq { + output_vector.push("--with-derive-partialeq".into()); + } + + if self.options.derive_eq { + output_vector.push("--with-derive-eq".into()); + } + + if self.options.time_phases { + output_vector.push("--time-phases".into()); + } + + if !self.options.generate_comments { + output_vector.push("--no-doc-comments".into()); + } + + if !self.options.allowlist_recursively { + output_vector.push("--no-recursive-allowlist".into()); + } + + if self.options.objc_extern_crate { + output_vector.push("--objc-extern-crate".into()); + } + + if self.options.generate_block { + output_vector.push("--generate-block".into()); + } + + if self.options.block_extern_crate { + output_vector.push("--block-extern-crate".into()); + } + + if self.options.builtins { + output_vector.push("--builtins".into()); + } + + if let Some(ref prefix) = self.options.ctypes_prefix { + output_vector.push("--ctypes-prefix".into()); + output_vector.push(prefix.clone()); + } + + if self.options.anon_fields_prefix != DEFAULT_ANON_FIELDS_PREFIX { + output_vector.push("--anon-fields-prefix".into()); + output_vector.push(self.options.anon_fields_prefix.clone()); + } + + if self.options.emit_ast { + output_vector.push("--emit-clang-ast".into()); + } + + if self.options.emit_ir { + output_vector.push("--emit-ir".into()); + } + if let Some(ref graph) = self.options.emit_ir_graphviz { + output_vector.push("--emit-ir-graphviz".into()); + output_vector.push(graph.clone()) + } + if self.options.enable_cxx_namespaces { + output_vector.push("--enable-cxx-namespaces".into()); + } + if self.options.enable_function_attribute_detection { + output_vector.push("--enable-function-attribute-detection".into()); + } + if self.options.disable_name_namespacing { + output_vector.push("--disable-name-namespacing".into()); + } + if self.options.disable_nested_struct_naming { + output_vector.push("--disable-nested-struct-naming".into()); + } + + if self.options.disable_header_comment { + output_vector.push("--disable-header-comment".into()); + } + + if !self.options.codegen_config.functions() { + output_vector.push("--ignore-functions".into()); + } + + output_vector.push("--generate".into()); + + //Temporary placeholder for below 4 options + let mut options: Vec<String> = Vec::new(); + if self.options.codegen_config.functions() { + options.push("functions".into()); + } + if self.options.codegen_config.types() { + options.push("types".into()); + } + if self.options.codegen_config.vars() { + options.push("vars".into()); + } + if self.options.codegen_config.methods() { + options.push("methods".into()); + } + if self.options.codegen_config.constructors() { + options.push("constructors".into()); + } + if self.options.codegen_config.destructors() { + options.push("destructors".into()); + } + + output_vector.push(options.join(",")); + + if !self.options.codegen_config.methods() { + output_vector.push("--ignore-methods".into()); + } + + if !self.options.convert_floats { + output_vector.push("--no-convert-floats".into()); + } + + if !self.options.prepend_enum_name { + output_vector.push("--no-prepend-enum-name".into()); + } + + if self.options.fit_macro_constants { + output_vector.push("--fit-macro-constant-types".into()); + } + + if self.options.array_pointers_in_arguments { + output_vector.push("--use-array-pointers-in-arguments".into()); + } + + if let Some(ref wasm_import_module_name) = + self.options.wasm_import_module_name + { + output_vector.push("--wasm-import-module-name".into()); + output_vector.push(wasm_import_module_name.clone()); + } + + for line in &self.options.raw_lines { + output_vector.push("--raw-line".into()); + output_vector.push(line.clone()); + } + + for (module, lines) in &self.options.module_lines { + for line in lines.iter() { + output_vector.push("--module-raw-line".into()); + output_vector.push(module.clone()); + output_vector.push(line.clone()); + } + } + + if self.options.use_core { + output_vector.push("--use-core".into()); + } + + if self.options.conservative_inline_namespaces { + output_vector.push("--conservative-inline-namespaces".into()); + } + + if self.options.generate_inline_functions { + output_vector.push("--generate-inline-functions".into()); + } + + if !self.options.record_matches { + output_vector.push("--no-record-matches".into()); + } + + if !self.options.size_t_is_usize { + output_vector.push("--no-size_t-is-usize".into()); + } + + if !self.options.rustfmt_bindings { + output_vector.push("--no-rustfmt-bindings".into()); + } + + if let Some(path) = self + .options + .rustfmt_configuration_file + .as_ref() + .and_then(|f| f.to_str()) + { + output_vector.push("--rustfmt-configuration-file".into()); + output_vector.push(path.into()); + } + + if let Some(ref name) = self.options.dynamic_library_name { + output_vector.push("--dynamic-loading".into()); + output_vector.push(name.clone()); + } + + if self.options.dynamic_link_require_all { + output_vector.push("--dynamic-link-require-all".into()); + } + + if self.options.respect_cxx_access_specs { + output_vector.push("--respect-cxx-access-specs".into()); + } + + if self.options.translate_enum_integer_types { + output_vector.push("--translate-enum-integer-types".into()); + } + + if self.options.c_naming { + output_vector.push("--c-naming".into()); + } + + if self.options.force_explicit_padding { + output_vector.push("--explicit-padding".into()); + } + + if self.options.vtable_generation { + output_vector.push("--vtable-generation".into()); + } + + if self.options.sort_semantically { + output_vector.push("--sort-semantically".into()); + } + + if self.options.merge_extern_blocks { + output_vector.push("--merge-extern-blocks".into()); + } + + if self.options.wrap_unsafe_ops { + output_vector.push("--wrap-unsafe-ops".into()); + } + + #[cfg(feature = "cli")] + for callbacks in &self.options.parse_callbacks { + output_vector.extend(callbacks.cli_args()); + } + if self.options.wrap_static_fns { + output_vector.push("--wrap-static-fns".into()) + } + + if let Some(ref path) = self.options.wrap_static_fns_path { + output_vector.push("--wrap-static-fns-path".into()); + output_vector.push(path.display().to_string()); + } + + if let Some(ref suffix) = self.options.wrap_static_fns_suffix { + output_vector.push("--wrap-static-fns-suffix".into()); + output_vector.push(suffix.clone()); + } + + if cfg!(feature = "experimental") { + output_vector.push("--experimental".into()); + } + + // Add clang arguments + + output_vector.push("--".into()); + + if !self.options.clang_args.is_empty() { + output_vector.extend(self.options.clang_args.iter().cloned()); + } + + // To pass more than one header, we need to pass all but the last + // header via the `-include` clang arg + for header in &self.options.input_headers + [..self.options.input_headers.len().saturating_sub(1)] + { + output_vector.push("-include".to_string()); + output_vector.push(header.clone()); + } + + output_vector + } + + /// Add an input C/C++ header to generate bindings for. + /// + /// This can be used to generate bindings to a single header: + /// + /// ```ignore + /// let bindings = bindgen::Builder::default() + /// .header("input.h") + /// .generate() + /// .unwrap(); + /// ``` + /// + /// Or you can invoke it multiple times to generate bindings to multiple + /// headers: + /// + /// ```ignore + /// let bindings = bindgen::Builder::default() + /// .header("first.h") + /// .header("second.h") + /// .header("third.h") + /// .generate() + /// .unwrap(); + /// ``` + pub fn header<T: Into<String>>(mut self, header: T) -> Builder { + self.options.input_headers.push(header.into()); + self + } + + /// Add a depfile output which will be written alongside the generated bindings. + pub fn depfile<H: Into<String>, D: Into<PathBuf>>( + mut self, + output_module: H, + depfile: D, + ) -> Builder { + self.options.depfile = Some(deps::DepfileSpec { + output_module: output_module.into(), + depfile_path: depfile.into(), + }); + self + } + + /// Add `contents` as an input C/C++ header named `name`. + /// + /// The file `name` will be added to the clang arguments. + pub fn header_contents(mut self, name: &str, contents: &str) -> Builder { + // Apparently clang relies on having virtual FS correspondent to + // the real one, so we need absolute paths here + let absolute_path = env::current_dir() + .expect("Cannot retrieve current directory") + .join(name) + .to_str() + .expect("Cannot convert current directory name to string") + .to_owned(); + self.options + .input_header_contents + .push((absolute_path, contents.into())); + self + } + + /// Specify the rust target + /// + /// The default is the latest stable Rust version + pub fn rust_target(mut self, rust_target: RustTarget) -> Self { + #[allow(deprecated)] + if rust_target <= RustTarget::Stable_1_30 { + warn!( + "The {} rust target is deprecated. If you have a good reason to use this target please report it at https://github.com/rust-lang/rust-bindgen/issues", + String::from(rust_target) + ); + } + self.options.set_rust_target(rust_target); + self + } + + /// Disable support for native Rust unions, if supported. + pub fn disable_untagged_union(mut self) -> Self { + self.options.rust_features.untagged_union = false; + self + } + + /// Disable insertion of bindgen's version identifier into generated + /// bindings. + pub fn disable_header_comment(mut self) -> Self { + self.options.disable_header_comment = true; + self + } + + /// Set the output graphviz file. + pub fn emit_ir_graphviz<T: Into<String>>(mut self, path: T) -> Builder { + let path = path.into(); + self.options.emit_ir_graphviz = Some(path); + self + } + + /// Whether the generated bindings should contain documentation comments + /// (docstrings) or not. This is set to true by default. + /// + /// Note that clang by default excludes comments from system headers, pass + /// `-fretain-comments-from-system-headers` as + /// [`clang_arg`][Builder::clang_arg] to include them. It can also be told + /// to process all comments (not just documentation ones) using the + /// `-fparse-all-comments` flag. See [slides on clang comment parsing]( + /// https://llvm.org/devmtg/2012-11/Gribenko_CommentParsing.pdf) for + /// background and examples. + pub fn generate_comments(mut self, doit: bool) -> Self { + self.options.generate_comments = doit; + self + } + + /// Whether to allowlist recursively or not. Defaults to true. + /// + /// Given that we have explicitly allowlisted the "initiate_dance_party" + /// function in this C header: + /// + /// ```c + /// typedef struct MoonBoots { + /// int bouncy_level; + /// } MoonBoots; + /// + /// void initiate_dance_party(MoonBoots* boots); + /// ``` + /// + /// We would normally generate bindings to both the `initiate_dance_party` + /// function and the `MoonBoots` struct that it transitively references. By + /// configuring with `allowlist_recursively(false)`, `bindgen` will not emit + /// bindings for anything except the explicitly allowlisted items, and there + /// would be no emitted struct definition for `MoonBoots`. However, the + /// `initiate_dance_party` function would still reference `MoonBoots`! + /// + /// **Disabling this feature will almost certainly cause `bindgen` to emit + /// bindings that will not compile!** If you disable this feature, then it + /// is *your* responsibility to provide definitions for every type that is + /// referenced from an explicitly allowlisted item. One way to provide the + /// definitions is by using the [`Builder::raw_line`](#method.raw_line) + /// method, another would be to define them in Rust and then `include!(...)` + /// the bindings immediately afterwards. + pub fn allowlist_recursively(mut self, doit: bool) -> Self { + self.options.allowlist_recursively = doit; + self + } + + /// Generate `#[macro_use] extern crate objc;` instead of `use objc;` + /// in the prologue of the files generated from objective-c files + pub fn objc_extern_crate(mut self, doit: bool) -> Self { + self.options.objc_extern_crate = doit; + self + } + + /// Generate proper block signatures instead of void pointers. + pub fn generate_block(mut self, doit: bool) -> Self { + self.options.generate_block = doit; + self + } + + /// Generate `#[macro_use] extern crate block;` instead of `use block;` + /// in the prologue of the files generated from apple block files + pub fn block_extern_crate(mut self, doit: bool) -> Self { + self.options.block_extern_crate = doit; + self + } + + /// Whether to use the clang-provided name mangling. This is true by default + /// and probably needed for C++ features. + /// + /// However, some old libclang versions seem to return incorrect results in + /// some cases for non-mangled functions, see [1], so we allow disabling it. + /// + /// [1]: https://github.com/rust-lang/rust-bindgen/issues/528 + pub fn trust_clang_mangling(mut self, doit: bool) -> Self { + self.options.enable_mangling = doit; + self + } + + fn_with_regex_arg! { + /// Hide the given type from the generated bindings. Regular expressions are + /// supported. + /// + /// To blocklist types prefixed with "mylib" use `"mylib_.*"`. + pub fn blocklist_type<T: AsRef<str>>(mut self, arg: T) -> Builder { + self.options.blocklisted_types.insert(arg); + self + } + } + + fn_with_regex_arg! { + /// Hide the given function from the generated bindings. Regular expressions + /// are supported. + /// + /// Methods can be blocklisted by prefixing the name of the type implementing + /// them followed by an underscore. So if `Foo` has a method `bar`, it can + /// be blocklisted as `Foo_bar`. + /// + /// To blocklist functions prefixed with "mylib" use `"mylib_.*"`. + pub fn blocklist_function<T: AsRef<str>>(mut self, arg: T) -> Builder { + self.options.blocklisted_functions.insert(arg); + self + } + } + + fn_with_regex_arg! { + /// Hide the given item from the generated bindings, regardless of + /// whether it's a type, function, module, etc. Regular + /// expressions are supported. + /// + /// To blocklist items prefixed with "mylib" use `"mylib_.*"`. + pub fn blocklist_item<T: AsRef<str>>(mut self, arg: T) -> Builder { + self.options.blocklisted_items.insert(arg); + self + } + } + + fn_with_regex_arg! { + /// Hide any contents of the given file from the generated bindings, + /// regardless of whether it's a type, function, module etc. + pub fn blocklist_file<T: AsRef<str>>(mut self, arg: T) -> Builder { + self.options.blocklisted_files.insert(arg); + self + } + } + + fn_with_regex_arg! { + /// Treat the given type as opaque in the generated bindings. Regular + /// expressions are supported. + /// + /// To change types prefixed with "mylib" into opaque, use `"mylib_.*"`. + pub fn opaque_type<T: AsRef<str>>(mut self, arg: T) -> Builder { + self.options.opaque_types.insert(arg); + self + } + } + + fn_with_regex_arg! { + /// Allowlist the given type so that it (and all types that it transitively + /// refers to) appears in the generated bindings. Regular expressions are + /// supported. + /// + /// To allowlist types prefixed with "mylib" use `"mylib_.*"`. + pub fn allowlist_type<T: AsRef<str>>(mut self, arg: T) -> Builder { + self.options.allowlisted_types.insert(arg); + self + } + } + + fn_with_regex_arg! { + /// Allowlist the given function so that it (and all types that it + /// transitively refers to) appears in the generated bindings. Regular + /// expressions are supported. + /// + /// Methods can be allowlisted by prefixing the name of the type + /// implementing them followed by an underscore. So if `Foo` has a method + /// `bar`, it can be allowlisted as `Foo_bar`. + /// + /// To allowlist functions prefixed with "mylib" use `"mylib_.*"`. + pub fn allowlist_function<T: AsRef<str>>(mut self, arg: T) -> Builder { + self.options.allowlisted_functions.insert(arg); + self + } + } + + fn_with_regex_arg! { + /// Allowlist the given variable so that it (and all types that it + /// transitively refers to) appears in the generated bindings. Regular + /// expressions are supported. + /// + /// To allowlist variables prefixed with "mylib" use `"mylib_.*"`. + pub fn allowlist_var<T: AsRef<str>>(mut self, arg: T) -> Builder { + self.options.allowlisted_vars.insert(arg); + self + } + } + + fn_with_regex_arg! { + /// Allowlist the given file so that its contents appear in the generated bindings. + pub fn allowlist_file<T: AsRef<str>>(mut self, arg: T) -> Builder { + self.options.allowlisted_files.insert(arg); + self + } + } + + /// Set the default style of code to generate for enums + pub fn default_enum_style( + mut self, + arg: codegen::EnumVariation, + ) -> Builder { + self.options.default_enum_style = arg; + self + } + + fn_with_regex_arg! { + /// Mark the given enum (or set of enums, if using a pattern) as being + /// bitfield-like. Regular expressions are supported. + /// + /// This makes bindgen generate a type that isn't a rust `enum`. Regular + /// expressions are supported. + /// + /// This is similar to the newtype enum style, but with the bitwise + /// operators implemented. + pub fn bitfield_enum<T: AsRef<str>>(mut self, arg: T) -> Builder { + self.options.bitfield_enums.insert(arg); + self + } + } + + fn_with_regex_arg! { + /// Mark the given enum (or set of enums, if using a pattern) as a newtype. + /// Regular expressions are supported. + /// + /// This makes bindgen generate a type that isn't a Rust `enum`. Regular + /// expressions are supported. + pub fn newtype_enum<T: AsRef<str>>(mut self, arg: T) -> Builder { + self.options.newtype_enums.insert(arg); + self + } + } + + fn_with_regex_arg! { + /// Mark the given enum (or set of enums, if using a pattern) as a newtype + /// whose variants are exposed as global constants. + /// + /// Regular expressions are supported. + /// + /// This makes bindgen generate a type that isn't a Rust `enum`. Regular + /// expressions are supported. + pub fn newtype_global_enum<T: AsRef<str>>(mut self, arg: T) -> Builder { + self.options.newtype_global_enums.insert(arg); + self + } + } + + fn_with_regex_arg! { + /// Mark the given enum (or set of enums, if using a pattern) as a Rust + /// enum. + /// + /// This makes bindgen generate enums instead of constants. Regular + /// expressions are supported. + /// + /// **Use this with caution**, creating this in unsafe code + /// (including FFI) with an invalid value will invoke undefined behaviour. + /// You may want to use the newtype enum style instead. + pub fn rustified_enum<T: AsRef<str>>(mut self, arg: T) -> Builder { + self.options.rustified_enums.insert(arg); + self + } + } + + fn_with_regex_arg! { + /// Mark the given enum (or set of enums, if using a pattern) as a Rust + /// enum with the `#[non_exhaustive]` attribute. + /// + /// This makes bindgen generate enums instead of constants. Regular + /// expressions are supported. + /// + /// **Use this with caution**, creating this in unsafe code + /// (including FFI) with an invalid value will invoke undefined behaviour. + /// You may want to use the newtype enum style instead. + pub fn rustified_non_exhaustive_enum<T: AsRef<str>>( + mut self, + arg: T, + ) -> Builder { + self.options.rustified_non_exhaustive_enums.insert(arg); + self + } + } + + fn_with_regex_arg! { + /// Mark the given enum (or set of enums, if using a pattern) as a set of + /// constants that are not to be put into a module. + pub fn constified_enum<T: AsRef<str>>(mut self, arg: T) -> Builder { + self.options.constified_enums.insert(arg); + self + } + } + + fn_with_regex_arg! { + /// Mark the given enum (or set of enums, if using a pattern) as a set of + /// constants that should be put into a module. + /// + /// This makes bindgen generate modules containing constants instead of + /// just constants. Regular expressions are supported. + pub fn constified_enum_module<T: AsRef<str>>(mut self, arg: T) -> Builder { + self.options.constified_enum_modules.insert(arg); + self + } + } + + /// Set the default type for macro constants + pub fn default_macro_constant_type( + mut self, + arg: codegen::MacroTypeVariation, + ) -> Builder { + self.options.default_macro_constant_type = arg; + self + } + + /// Set the default style of code to generate for typedefs + pub fn default_alias_style( + mut self, + arg: codegen::AliasVariation, + ) -> Builder { + self.options.default_alias_style = arg; + self + } + + fn_with_regex_arg! { + /// Mark the given typedef alias (or set of aliases, if using a pattern) to + /// use regular Rust type aliasing. + /// + /// This is the default behavior and should be used if `default_alias_style` + /// was set to NewType or NewTypeDeref and you want to override it for a + /// set of typedefs. + pub fn type_alias<T: AsRef<str>>(mut self, arg: T) -> Builder { + self.options.type_alias.insert(arg); + self + } + } + + fn_with_regex_arg! { + /// Mark the given typedef alias (or set of aliases, if using a pattern) to + /// be generated as a new type by having the aliased type be wrapped in a + /// #[repr(transparent)] struct. + /// + /// Used to enforce stricter type checking. + pub fn new_type_alias<T: AsRef<str>>(mut self, arg: T) -> Builder { + self.options.new_type_alias.insert(arg); + self + } + } + + fn_with_regex_arg! { + /// Mark the given typedef alias (or set of aliases, if using a pattern) to + /// be generated as a new type by having the aliased type be wrapped in a + /// #[repr(transparent)] struct and also have an automatically generated + /// impl's of `Deref` and `DerefMut` to their aliased type. + pub fn new_type_alias_deref<T: AsRef<str>>(mut self, arg: T) -> Builder { + self.options.new_type_alias_deref.insert(arg); + self + } + } + + /// Set the default style of code to generate for unions with a non-Copy member. + pub fn default_non_copy_union_style( + mut self, + arg: codegen::NonCopyUnionStyle, + ) -> Self { + self.options.default_non_copy_union_style = arg; + self + } + + fn_with_regex_arg! { + /// Mark the given union (or set of union, if using a pattern) to use + /// a bindgen-generated wrapper for its members if at least one is non-Copy. + pub fn bindgen_wrapper_union<T: AsRef<str>>(mut self, arg: T) -> Self { + self.options.bindgen_wrapper_union.insert(arg); + self + } + } + + fn_with_regex_arg! { + /// Mark the given union (or set of union, if using a pattern) to use + /// [`::core::mem::ManuallyDrop`] for its members if at least one is non-Copy. + /// + /// Note: `ManuallyDrop` was stabilized in Rust 1.20.0, do not use it if your + /// MSRV is lower. + pub fn manually_drop_union<T: AsRef<str>>(mut self, arg: T) -> Self { + self.options.manually_drop_union.insert(arg); + self + } + } + + fn_with_regex_arg! { + /// Add a string to prepend to the generated bindings. The string is passed + /// through without any modification. + pub fn raw_line<T: Into<String>>(mut self, arg: T) -> Self { + self.options.raw_lines.push(arg.into()); + self + } + } + + /// Add a given line to the beginning of module `mod`. + pub fn module_raw_line<T, U>(mut self, mod_: T, line: U) -> Self + where + T: Into<String>, + U: Into<String>, + { + self.options + .module_lines + .entry(mod_.into()) + .or_insert_with(Vec::new) + .push(line.into()); + self + } + + /// Add a given set of lines to the beginning of module `mod`. + pub fn module_raw_lines<T, I>(mut self, mod_: T, lines: I) -> Self + where + T: Into<String>, + I: IntoIterator, + I::Item: Into<String>, + { + self.options + .module_lines + .entry(mod_.into()) + .or_insert_with(Vec::new) + .extend(lines.into_iter().map(Into::into)); + self + } + + /// Add an argument to be passed straight through to clang. + pub fn clang_arg<T: Into<String>>(mut self, arg: T) -> Builder { + self.options.clang_args.push(arg.into()); + self + } + + /// Add arguments to be passed straight through to clang. + pub fn clang_args<I>(mut self, iter: I) -> Builder + where + I: IntoIterator, + I::Item: AsRef<str>, + { + for arg in iter { + self = self.clang_arg(arg.as_ref()) + } + self + } + + /// Emit bindings for builtin definitions (for example `__builtin_va_list`) + /// in the generated Rust. + pub fn emit_builtins(mut self) -> Builder { + self.options.builtins = true; + self + } + + /// Avoid converting floats to `f32`/`f64` by default. + pub fn no_convert_floats(mut self) -> Self { + self.options.convert_floats = false; + self + } + + /// Set whether layout tests should be generated. + pub fn layout_tests(mut self, doit: bool) -> Self { + self.options.layout_tests = doit; + self + } + + /// Set whether `Debug` should be implemented, if it can not be derived automatically. + pub fn impl_debug(mut self, doit: bool) -> Self { + self.options.impl_debug = doit; + self + } + + /// Set whether `PartialEq` should be implemented, if it can not be derived automatically. + pub fn impl_partialeq(mut self, doit: bool) -> Self { + self.options.impl_partialeq = doit; + self + } + + /// Set whether `Copy` should be derived by default. + pub fn derive_copy(mut self, doit: bool) -> Self { + self.options.derive_copy = doit; + self + } + + /// Set whether `Debug` should be derived by default. + pub fn derive_debug(mut self, doit: bool) -> Self { + self.options.derive_debug = doit; + self + } + + /// Set whether `Default` should be derived by default. + pub fn derive_default(mut self, doit: bool) -> Self { + self.options.derive_default = doit; + self + } + + /// Set whether `Hash` should be derived by default. + pub fn derive_hash(mut self, doit: bool) -> Self { + self.options.derive_hash = doit; + self + } + + /// Set whether `PartialOrd` should be derived by default. + /// If we don't compute partialord, we also cannot compute + /// ord. Set the derive_ord to `false` when doit is `false`. + pub fn derive_partialord(mut self, doit: bool) -> Self { + self.options.derive_partialord = doit; + if !doit { + self.options.derive_ord = false; + } + self + } + + /// Set whether `Ord` should be derived by default. + /// We can't compute `Ord` without computing `PartialOrd`, + /// so we set the same option to derive_partialord. + pub fn derive_ord(mut self, doit: bool) -> Self { + self.options.derive_ord = doit; + self.options.derive_partialord = doit; + self + } + + /// Set whether `PartialEq` should be derived by default. + /// + /// If we don't derive `PartialEq`, we also cannot derive `Eq`, so deriving + /// `Eq` is also disabled when `doit` is `false`. + pub fn derive_partialeq(mut self, doit: bool) -> Self { + self.options.derive_partialeq = doit; + if !doit { + self.options.derive_eq = false; + } + self + } + + /// Set whether `Eq` should be derived by default. + /// + /// We can't derive `Eq` without also deriving `PartialEq`, so we also + /// enable deriving `PartialEq` when `doit` is `true`. + pub fn derive_eq(mut self, doit: bool) -> Self { + self.options.derive_eq = doit; + if doit { + self.options.derive_partialeq = doit; + } + self + } + + /// Set whether or not to time bindgen phases, and print information to + /// stderr. + pub fn time_phases(mut self, doit: bool) -> Self { + self.options.time_phases = doit; + self + } + + /// Emit Clang AST. + pub fn emit_clang_ast(mut self) -> Builder { + self.options.emit_ast = true; + self + } + + /// Emit IR. + pub fn emit_ir(mut self) -> Builder { + self.options.emit_ir = true; + self + } + + /// Enable C++ namespaces. + pub fn enable_cxx_namespaces(mut self) -> Builder { + self.options.enable_cxx_namespaces = true; + self + } + + /// Enable detecting must_use attributes on C functions. + /// + /// This is quite slow in some cases (see #1465), so it's disabled by + /// default. + /// + /// Note that for this to do something meaningful for now at least, the rust + /// target version has to have support for `#[must_use]`. + pub fn enable_function_attribute_detection(mut self) -> Self { + self.options.enable_function_attribute_detection = true; + self + } + + /// Disable name auto-namespacing. + /// + /// By default, bindgen mangles names like `foo::bar::Baz` to look like + /// `foo_bar_Baz` instead of just `Baz`. + /// + /// This method disables that behavior. + /// + /// Note that this intentionally does not change the names used for + /// allowlisting and blocklisting, which should still be mangled with the + /// namespaces. + /// + /// Note, also, that this option may cause bindgen to generate duplicate + /// names. + pub fn disable_name_namespacing(mut self) -> Builder { + self.options.disable_name_namespacing = true; + self + } + + /// Disable nested struct naming. + /// + /// The following structs have different names for C and C++. In case of C + /// they are visible as `foo` and `bar`. In case of C++ they are visible as + /// `foo` and `foo::bar`. + /// + /// ```c + /// struct foo { + /// struct bar { + /// } b; + /// }; + /// ``` + /// + /// Bindgen wants to avoid duplicate names by default so it follows C++ naming + /// and it generates `foo`/`foo_bar` instead of just `foo`/`bar`. + /// + /// This method disables this behavior and it is indented to be used only + /// for headers that were written for C. + pub fn disable_nested_struct_naming(mut self) -> Builder { + self.options.disable_nested_struct_naming = true; + self + } + + /// Treat inline namespaces conservatively. + /// + /// This is tricky, because in C++ is technically legal to override an item + /// defined in an inline namespace: + /// + /// ```cpp + /// inline namespace foo { + /// using Bar = int; + /// } + /// using Bar = long; + /// ``` + /// + /// Even though referencing `Bar` is a compiler error. + /// + /// We want to support this (arguably esoteric) use case, but we don't want + /// to make the rest of bindgen users pay an usability penalty for that. + /// + /// To support this, we need to keep all the inline namespaces around, but + /// then bindgen usage is a bit more difficult, because you cannot + /// reference, e.g., `std::string` (you'd need to use the proper inline + /// namespace). + /// + /// We could complicate a lot of the logic to detect name collisions, and if + /// not detected generate a `pub use inline_ns::*` or something like that. + /// + /// That's probably something we can do if we see this option is needed in a + /// lot of cases, to improve it's usability, but my guess is that this is + /// not going to be too useful. + pub fn conservative_inline_namespaces(mut self) -> Builder { + self.options.conservative_inline_namespaces = true; + self + } + + /// Whether inline functions should be generated or not. + /// + /// Note that they will usually not work. However you can use + /// `-fkeep-inline-functions` or `-fno-inline-functions` if you are + /// responsible of compiling the library to make them callable. + pub fn generate_inline_functions(mut self, doit: bool) -> Self { + self.options.generate_inline_functions = doit; + self + } + + /// Ignore functions. + pub fn ignore_functions(mut self) -> Builder { + self.options.codegen_config.remove(CodegenConfig::FUNCTIONS); + self + } + + /// Ignore methods. + pub fn ignore_methods(mut self) -> Builder { + self.options.codegen_config.remove(CodegenConfig::METHODS); + self + } + + /// Use core instead of libstd in the generated bindings. + pub fn use_core(mut self) -> Builder { + self.options.use_core = true; + self + } + + /// Use the given prefix for the raw types instead of `::std::os::raw`. + pub fn ctypes_prefix<T: Into<String>>(mut self, prefix: T) -> Builder { + self.options.ctypes_prefix = Some(prefix.into()); + self + } + + /// Use the given prefix for the anon fields. + pub fn anon_fields_prefix<T: Into<String>>(mut self, prefix: T) -> Builder { + self.options.anon_fields_prefix = prefix.into(); + self + } + + /// Allows configuring types in different situations, see the + /// [`ParseCallbacks`](./callbacks/trait.ParseCallbacks.html) documentation. + pub fn parse_callbacks( + mut self, + cb: Box<dyn callbacks::ParseCallbacks>, + ) -> Self { + self.options.parse_callbacks.push(Rc::from(cb)); + self + } + + /// Choose what to generate using a + /// [`CodegenConfig`](./struct.CodegenConfig.html). + pub fn with_codegen_config(mut self, config: CodegenConfig) -> Self { + self.options.codegen_config = config; + self + } + + /// Whether to detect include paths using clang_sys. + pub fn detect_include_paths(mut self, doit: bool) -> Self { + self.options.detect_include_paths = doit; + self + } + + /// Whether to try to fit macro constants to types smaller than u32/i32 + pub fn fit_macro_constants(mut self, doit: bool) -> Self { + self.options.fit_macro_constants = doit; + self + } + + /// Prepend the enum name to constant or newtype variants. + pub fn prepend_enum_name(mut self, doit: bool) -> Self { + self.options.prepend_enum_name = doit; + self + } + + /// Set whether `size_t` should be translated to `usize` automatically. + pub fn size_t_is_usize(mut self, is: bool) -> Self { + self.options.size_t_is_usize = is; + self + } + + /// Set whether rustfmt should format the generated bindings. + pub fn rustfmt_bindings(mut self, doit: bool) -> Self { + self.options.rustfmt_bindings = doit; + self + } + + /// Set whether we should record matched items in our regex sets. + pub fn record_matches(mut self, doit: bool) -> Self { + self.options.record_matches = doit; + self + } + + /// Set the absolute path to the rustfmt configuration file, if None, the standard rustfmt + /// options are used. + pub fn rustfmt_configuration_file(mut self, path: Option<PathBuf>) -> Self { + self = self.rustfmt_bindings(true); + self.options.rustfmt_configuration_file = path; + self + } + + /// Sets an explicit path to rustfmt, to be used when rustfmt is enabled. + pub fn with_rustfmt<P: Into<PathBuf>>(mut self, path: P) -> Self { + self.options.rustfmt_path = Some(path.into()); + self + } + + /// If true, always emit explicit padding fields. + /// + /// If a struct needs to be serialized in its native format (padding bytes + /// and all), for example writing it to a file or sending it on the network, + /// then this should be enabled, as anything reading the padding bytes of + /// a struct may lead to Undefined Behavior. + pub fn explicit_padding(mut self, doit: bool) -> Self { + self.options.force_explicit_padding = doit; + self + } + + /// If true, enables experimental support to generate vtable functions. + /// + /// Should mostly work, though some edge cases are likely to be broken. + pub fn vtable_generation(mut self, doit: bool) -> Self { + self.options.vtable_generation = doit; + self + } + + /// If true, enables the sorting of the output in a predefined manner. + /// + /// TODO: Perhaps move the sorting order out into a config + pub fn sort_semantically(mut self, doit: bool) -> Self { + self.options.sort_semantically = doit; + self + } + + /// If true, merges extern blocks. + pub fn merge_extern_blocks(mut self, doit: bool) -> Self { + self.options.merge_extern_blocks = doit; + self + } + + /// Generate the Rust bindings using the options built up thus far. + pub fn generate(mut self) -> Result<Bindings, BindgenError> { + // Add any extra arguments from the environment to the clang command line. + self.options.clang_args.extend(get_extra_clang_args()); + + // Transform input headers to arguments on the clang command line. + self.options.clang_args.extend( + self.options.input_headers + [..self.options.input_headers.len().saturating_sub(1)] + .iter() + .flat_map(|header| ["-include".into(), header.to_string()]), + ); + + let input_unsaved_files = + std::mem::take(&mut self.options.input_header_contents) + .into_iter() + .map(|(name, contents)| clang::UnsavedFile::new(name, contents)) + .collect::<Vec<_>>(); + + Bindings::generate(self.options, input_unsaved_files) + } + + /// Preprocess and dump the input header files to disk. + /// + /// This is useful when debugging bindgen, using C-Reduce, or when filing + /// issues. The resulting file will be named something like `__bindgen.i` or + /// `__bindgen.ii` + pub fn dump_preprocessed_input(&self) -> io::Result<()> { + let clang = + clang_sys::support::Clang::find(None, &[]).ok_or_else(|| { + io::Error::new( + io::ErrorKind::Other, + "Cannot find clang executable", + ) + })?; + + // The contents of a wrapper file that includes all the input header + // files. + let mut wrapper_contents = String::new(); + + // Whether we are working with C or C++ inputs. + let mut is_cpp = args_are_cpp(&self.options.clang_args); + + // For each input header, add `#include "$header"`. + for header in &self.options.input_headers { + is_cpp |= file_is_cpp(header); + + wrapper_contents.push_str("#include \""); + wrapper_contents.push_str(header); + wrapper_contents.push_str("\"\n"); + } + + // For each input header content, add a prefix line of `#line 0 "$name"` + // followed by the contents. + for (name, contents) in &self.options.input_header_contents { + is_cpp |= file_is_cpp(name); + + wrapper_contents.push_str("#line 0 \""); + wrapper_contents.push_str(name); + wrapper_contents.push_str("\"\n"); + wrapper_contents.push_str(contents); + } + + let wrapper_path = PathBuf::from(if is_cpp { + "__bindgen.cpp" + } else { + "__bindgen.c" + }); + + { + let mut wrapper_file = File::create(&wrapper_path)?; + wrapper_file.write_all(wrapper_contents.as_bytes())?; + } + + let mut cmd = Command::new(clang.path); + cmd.arg("-save-temps") + .arg("-E") + .arg("-C") + .arg("-c") + .arg(&wrapper_path) + .stdout(Stdio::piped()); + + for a in &self.options.clang_args { + cmd.arg(a); + } + + for a in get_extra_clang_args() { + cmd.arg(a); + } + + let mut child = cmd.spawn()?; + + let mut preprocessed = child.stdout.take().unwrap(); + let mut file = File::create(if is_cpp { + "__bindgen.ii" + } else { + "__bindgen.i" + })?; + io::copy(&mut preprocessed, &mut file)?; + + if child.wait()?.success() { + Ok(()) + } else { + Err(io::Error::new( + io::ErrorKind::Other, + "clang exited with non-zero status", + )) + } + } + + fn_with_regex_arg! { + /// Don't derive `PartialEq` for a given type. Regular + /// expressions are supported. + pub fn no_partialeq<T: Into<String>>(mut self, arg: T) -> Builder { + self.options.no_partialeq_types.insert(arg.into()); + self + } + } + + fn_with_regex_arg! { + /// Don't derive `Copy` for a given type. Regular + /// expressions are supported. + pub fn no_copy<T: Into<String>>(mut self, arg: T) -> Self { + self.options.no_copy_types.insert(arg.into()); + self + } + } + + fn_with_regex_arg! { + /// Don't derive `Debug` for a given type. Regular + /// expressions are supported. + pub fn no_debug<T: Into<String>>(mut self, arg: T) -> Self { + self.options.no_debug_types.insert(arg.into()); + self + } + } + + fn_with_regex_arg! { + /// Don't derive/impl `Default` for a given type. Regular + /// expressions are supported. + pub fn no_default<T: Into<String>>(mut self, arg: T) -> Self { + self.options.no_default_types.insert(arg.into()); + self + } + } + + fn_with_regex_arg! { + /// Don't derive `Hash` for a given type. Regular + /// expressions are supported. + pub fn no_hash<T: Into<String>>(mut self, arg: T) -> Builder { + self.options.no_hash_types.insert(arg.into()); + self + } + } + + fn_with_regex_arg! { + /// Add `#[must_use]` for the given type. Regular + /// expressions are supported. + pub fn must_use_type<T: Into<String>>(mut self, arg: T) -> Builder { + self.options.must_use_types.insert(arg.into()); + self + } + } + + /// Set whether `arr[size]` should be treated as `*mut T` or `*mut [T; size]` (same for mut) + pub fn array_pointers_in_arguments(mut self, doit: bool) -> Self { + self.options.array_pointers_in_arguments = doit; + self + } + + /// Set the wasm import module name + pub fn wasm_import_module_name<T: Into<String>>( + mut self, + import_name: T, + ) -> Self { + self.options.wasm_import_module_name = Some(import_name.into()); + self + } + + /// Specify the dynamic library name if we are generating bindings for a shared library. + pub fn dynamic_library_name<T: Into<String>>( + mut self, + dynamic_library_name: T, + ) -> Self { + self.options.dynamic_library_name = Some(dynamic_library_name.into()); + self + } + + /// Require successful linkage for all routines in a shared library. + /// This allows us to optimize function calls by being able to safely assume function pointers + /// are valid. + pub fn dynamic_link_require_all(mut self, req: bool) -> Self { + self.options.dynamic_link_require_all = req; + self + } + + /// Generate bindings as `pub` only if the bound item is publically accessible by C++. + pub fn respect_cxx_access_specs(mut self, doit: bool) -> Self { + self.options.respect_cxx_access_specs = doit; + self + } + + /// Always translate enum integer types to native Rust integer types. + /// + /// This will result in enums having types such as `u32` and `i16` instead + /// of `c_uint` and `c_short`. Types for Rustified enums are always + /// translated. + pub fn translate_enum_integer_types(mut self, doit: bool) -> Self { + self.options.translate_enum_integer_types = doit; + self + } + + /// Generate types with C style naming. + /// + /// This will add prefixes to the generated type names. For example instead of a struct `A` we + /// will generate struct `struct_A`. Currently applies to structs, unions, and enums. + pub fn c_naming(mut self, doit: bool) -> Self { + self.options.c_naming = doit; + self + } + + /// Override the ABI of a given function. Regular expressions are supported. + pub fn override_abi<T: Into<String>>(mut self, abi: Abi, arg: T) -> Self { + self.options + .abi_overrides + .entry(abi) + .or_default() + .insert(arg.into()); + self + } + + /// If true, wraps unsafe operations in unsafe blocks. + pub fn wrap_unsafe_ops(mut self, doit: bool) -> Self { + self.options.wrap_unsafe_ops = doit; + self + } + + #[cfg(feature = "experimental")] + /// Whether to generate extern wrappers for `static` and `static inline` functions. Defaults to + /// false. + pub fn wrap_static_fns(mut self, doit: bool) -> Self { + self.options.wrap_static_fns = doit; + self + } + + #[cfg(feature = "experimental")] + /// Set the path for the source code file that would be created if any wrapper functions must + /// be generated due to the presence of static functions. + /// + /// Bindgen will automatically add the right extension to the header and source code files. + pub fn wrap_static_fns_path<T: AsRef<Path>>(mut self, path: T) -> Self { + self.options.wrap_static_fns_path = Some(path.as_ref().to_owned()); + self + } + + #[cfg(feature = "experimental")] + /// Set the suffix added to the extern wrapper functions generated for `static` and `static + /// inline` functions. + pub fn wrap_static_fns_suffix<T: AsRef<str>>(mut self, suffix: T) -> Self { + self.options.wrap_static_fns_suffix = Some(suffix.as_ref().to_owned()); + self + } +} + +/// Configuration options for generated bindings. +#[derive(Clone, Debug)] +struct BindgenOptions { + /// The set of types that have been blocklisted and should not appear + /// anywhere in the generated code. + blocklisted_types: RegexSet, + + /// The set of functions that have been blocklisted and should not appear + /// in the generated code. + blocklisted_functions: RegexSet, + + /// The set of items, regardless of item-type, that have been + /// blocklisted and should not appear in the generated code. + blocklisted_items: RegexSet, + + /// The set of files whose contents should be blocklisted and should not + /// appear in the generated code. + blocklisted_files: RegexSet, + + /// The set of types that should be treated as opaque structures in the + /// generated code. + opaque_types: RegexSet, + + /// The explicit rustfmt path. + rustfmt_path: Option<PathBuf>, + + /// The path to which we should write a Makefile-syntax depfile (if any). + depfile: Option<deps::DepfileSpec>, + + /// The set of types that we should have bindings for in the generated + /// code. + /// + /// This includes all types transitively reachable from any type in this + /// set. One might think of allowlisted types/vars/functions as GC roots, + /// and the generated Rust code as including everything that gets marked. + allowlisted_types: RegexSet, + + /// Allowlisted functions. See docs for `allowlisted_types` for more. + allowlisted_functions: RegexSet, + + /// Allowlisted variables. See docs for `allowlisted_types` for more. + allowlisted_vars: RegexSet, + + /// The set of files whose contents should be allowlisted. + allowlisted_files: RegexSet, + + /// The default style of code to generate for enums + default_enum_style: codegen::EnumVariation, + + /// The enum patterns to mark an enum as a bitfield + /// (newtype with bitwise operations). + bitfield_enums: RegexSet, + + /// The enum patterns to mark an enum as a newtype. + newtype_enums: RegexSet, + + /// The enum patterns to mark an enum as a global newtype. + newtype_global_enums: RegexSet, + + /// The enum patterns to mark an enum as a Rust enum. + rustified_enums: RegexSet, + + /// The enum patterns to mark an enum as a non-exhaustive Rust enum. + rustified_non_exhaustive_enums: RegexSet, + + /// The enum patterns to mark an enum as a module of constants. + constified_enum_modules: RegexSet, + + /// The enum patterns to mark an enum as a set of constants. + constified_enums: RegexSet, + + /// The default type for C macro constants. + default_macro_constant_type: codegen::MacroTypeVariation, + + /// The default style of code to generate for typedefs. + default_alias_style: codegen::AliasVariation, + + /// Typedef patterns that will use regular type aliasing. + type_alias: RegexSet, + + /// Typedef patterns that will be aliased by creating a new struct. + new_type_alias: RegexSet, + + /// Typedef patterns that will be wrapped in a new struct and have + /// Deref and Deref to their aliased type. + new_type_alias_deref: RegexSet, + + /// The default style of code to generate for union containing non-Copy + /// members. + default_non_copy_union_style: codegen::NonCopyUnionStyle, + + /// The union patterns to mark an non-Copy union as using the bindgen + /// generated wrapper. + bindgen_wrapper_union: RegexSet, + + /// The union patterns to mark an non-Copy union as using the + /// `::core::mem::ManuallyDrop` wrapper. + manually_drop_union: RegexSet, + + /// Whether we should generate builtins or not. + builtins: bool, + + /// True if we should dump the Clang AST for debugging purposes. + emit_ast: bool, + + /// True if we should dump our internal IR for debugging purposes. + emit_ir: bool, + + /// Output graphviz dot file. + emit_ir_graphviz: Option<String>, + + /// True if we should emulate C++ namespaces with Rust modules in the + /// generated bindings. + enable_cxx_namespaces: bool, + + /// True if we should try to find unexposed attributes in functions, in + /// order to be able to generate #[must_use] attributes in Rust. + enable_function_attribute_detection: bool, + + /// True if we should avoid mangling names with namespaces. + disable_name_namespacing: bool, + + /// True if we should avoid generating nested struct names. + disable_nested_struct_naming: bool, + + /// True if we should avoid embedding version identifiers into source code. + disable_header_comment: bool, + + /// True if we should generate layout tests for generated structures. + layout_tests: bool, + + /// True if we should implement the Debug trait for C/C++ structures and types + /// that do not support automatically deriving Debug. + impl_debug: bool, + + /// True if we should implement the PartialEq trait for C/C++ structures and types + /// that do not support automatically deriving PartialEq. + impl_partialeq: bool, + + /// True if we should derive Copy trait implementations for C/C++ structures + /// and types. + derive_copy: bool, + + /// True if we should derive Debug trait implementations for C/C++ structures + /// and types. + derive_debug: bool, + + /// True if we should derive Default trait implementations for C/C++ structures + /// and types. + derive_default: bool, + + /// True if we should derive Hash trait implementations for C/C++ structures + /// and types. + derive_hash: bool, + + /// True if we should derive PartialOrd trait implementations for C/C++ structures + /// and types. + derive_partialord: bool, + + /// True if we should derive Ord trait implementations for C/C++ structures + /// and types. + derive_ord: bool, + + /// True if we should derive PartialEq trait implementations for C/C++ structures + /// and types. + derive_partialeq: bool, + + /// True if we should derive Eq trait implementations for C/C++ structures + /// and types. + derive_eq: bool, + + /// True if we should avoid using libstd to use libcore instead. + use_core: bool, + + /// An optional prefix for the "raw" types, like `c_int`, `c_void`... + ctypes_prefix: Option<String>, + + /// The prefix for the anon fields. + anon_fields_prefix: String, + + /// Whether to time the bindgen phases. + time_phases: bool, + + /// Whether we should convert float types to f32/f64 types. + convert_floats: bool, + + /// The set of raw lines to prepend to the top-level module of generated + /// Rust code. + raw_lines: Vec<String>, + + /// The set of raw lines to prepend to each of the modules. + /// + /// This only makes sense if the `enable_cxx_namespaces` option is set. + module_lines: HashMap<String, Vec<String>>, + + /// The set of arguments to pass straight through to Clang. + clang_args: Vec<String>, + + /// The input header files. + input_headers: Vec<String>, + + /// Tuples of unsaved file contents of the form (name, contents). + input_header_contents: Vec<(String, String)>, + + /// A user-provided visitor to allow customizing different kinds of + /// situations. + parse_callbacks: Vec<Rc<dyn callbacks::ParseCallbacks>>, + + /// Which kind of items should we generate? By default, we'll generate all + /// of them. + codegen_config: CodegenConfig, + + /// Whether to treat inline namespaces conservatively. + /// + /// See the builder method description for more details. + conservative_inline_namespaces: bool, + + /// Whether to keep documentation comments in the generated output. See the + /// documentation for more details. Defaults to true. + generate_comments: bool, + + /// Whether to generate inline functions. Defaults to false. + generate_inline_functions: bool, + + /// Whether to allowlist types recursively. Defaults to true. + allowlist_recursively: bool, + + /// Instead of emitting 'use objc;' to files generated from objective c files, + /// generate '#[macro_use] extern crate objc;' + objc_extern_crate: bool, + + /// Instead of emitting 'use block;' to files generated from objective c files, + /// generate '#[macro_use] extern crate block;' + generate_block: bool, + + /// Instead of emitting 'use block;' to files generated from objective c files, + /// generate '#[macro_use] extern crate block;' + block_extern_crate: bool, + + /// Whether to use the clang-provided name mangling. This is true and + /// probably needed for C++ features. + /// + /// However, some old libclang versions seem to return incorrect results in + /// some cases for non-mangled functions, see [1], so we allow disabling it. + /// + /// [1]: https://github.com/rust-lang/rust-bindgen/issues/528 + enable_mangling: bool, + + /// Whether to detect include paths using clang_sys. + detect_include_paths: bool, + + /// Whether to try to fit macro constants into types smaller than u32/i32 + fit_macro_constants: bool, + + /// Whether to prepend the enum name to constant or newtype variants. + prepend_enum_name: bool, + + /// Version of the Rust compiler to target + rust_target: RustTarget, + + /// Features to enable, derived from `rust_target` + rust_features: RustFeatures, + + /// Whether we should record which items in the regex sets ever matched. + /// + /// This may be a bit slower, but will enable reporting of unused allowlist + /// items via the `error!` log. + record_matches: bool, + + /// Whether `size_t` should be translated to `usize` automatically. + size_t_is_usize: bool, + + /// Whether rustfmt should format the generated bindings. + rustfmt_bindings: bool, + + /// The absolute path to the rustfmt configuration file, if None, the standard rustfmt + /// options are used. + rustfmt_configuration_file: Option<PathBuf>, + + /// The set of types that we should not derive `PartialEq` for. + no_partialeq_types: RegexSet, + + /// The set of types that we should not derive `Copy` for. + no_copy_types: RegexSet, + + /// The set of types that we should not derive `Debug` for. + no_debug_types: RegexSet, + + /// The set of types that we should not derive/impl `Default` for. + no_default_types: RegexSet, + + /// The set of types that we should not derive `Hash` for. + no_hash_types: RegexSet, + + /// The set of types that we should be annotated with `#[must_use]`. + must_use_types: RegexSet, + + /// Decide if C arrays should be regular pointers in rust or array pointers + array_pointers_in_arguments: bool, + + /// Wasm import module name. + wasm_import_module_name: Option<String>, + + /// The name of the dynamic library (if we are generating bindings for a shared library). If + /// this is None, no dynamic bindings are created. + dynamic_library_name: Option<String>, + + /// Require successful linkage for all routines in a shared library. + /// This allows us to optimize function calls by being able to safely assume function pointers + /// are valid. No effect if `dynamic_library_name` is None. + dynamic_link_require_all: bool, + + /// Only make generated bindings `pub` if the items would be publically accessible + /// by C++. + respect_cxx_access_specs: bool, + + /// Always translate enum integer types to native Rust integer types. + translate_enum_integer_types: bool, + + /// Generate types with C style naming. + c_naming: bool, + + /// Always output explicit padding fields + force_explicit_padding: bool, + + /// Emit vtable functions. + vtable_generation: bool, + + /// Sort the code generation. + sort_semantically: bool, + + /// Deduplicate `extern` blocks. + merge_extern_blocks: bool, + + abi_overrides: HashMap<Abi, RegexSet>, + + /// Whether to wrap unsafe operations in unsafe blocks or not. + wrap_unsafe_ops: bool, + + wrap_static_fns: bool, + + wrap_static_fns_suffix: Option<String>, + + wrap_static_fns_path: Option<PathBuf>, +} + +impl BindgenOptions { + fn build(&mut self) { + let regex_sets = [ + &mut self.allowlisted_vars, + &mut self.allowlisted_types, + &mut self.allowlisted_functions, + &mut self.allowlisted_files, + &mut self.blocklisted_types, + &mut self.blocklisted_functions, + &mut self.blocklisted_items, + &mut self.blocklisted_files, + &mut self.opaque_types, + &mut self.bitfield_enums, + &mut self.constified_enums, + &mut self.constified_enum_modules, + &mut self.newtype_enums, + &mut self.newtype_global_enums, + &mut self.rustified_enums, + &mut self.rustified_non_exhaustive_enums, + &mut self.type_alias, + &mut self.new_type_alias, + &mut self.new_type_alias_deref, + &mut self.bindgen_wrapper_union, + &mut self.manually_drop_union, + &mut self.no_partialeq_types, + &mut self.no_copy_types, + &mut self.no_debug_types, + &mut self.no_default_types, + &mut self.no_hash_types, + &mut self.must_use_types, + ]; + let record_matches = self.record_matches; + for regex_set in self.abi_overrides.values_mut().chain(regex_sets) { + regex_set.build(record_matches); + } + } + + /// Update rust target version + pub fn set_rust_target(&mut self, rust_target: RustTarget) { + self.rust_target = rust_target; + + // Keep rust_features synced with rust_target + self.rust_features = rust_target.into(); + } + + /// Get features supported by target Rust version + pub fn rust_features(&self) -> RustFeatures { + self.rust_features + } + + fn last_callback<T>( + &self, + f: impl Fn(&dyn callbacks::ParseCallbacks) -> Option<T>, + ) -> Option<T> { + self.parse_callbacks + .iter() + .filter_map(|cb| f(cb.as_ref())) + .last() + } + + fn all_callbacks<T>( + &self, + f: impl Fn(&dyn callbacks::ParseCallbacks) -> Vec<T>, + ) -> Vec<T> { + self.parse_callbacks + .iter() + .flat_map(|cb| f(cb.as_ref())) + .collect() + } + + fn process_comment(&self, comment: &str) -> String { + let comment = comment::preprocess(comment); + self.parse_callbacks + .last() + .and_then(|cb| cb.process_comment(&comment)) + .unwrap_or(comment) + } +} + +impl Default for BindgenOptions { + fn default() -> BindgenOptions { + macro_rules! options { + ($($field:ident $(: $value:expr)?,)* --default-fields-- $($default_field:ident,)*) => { + BindgenOptions { + $($field $(: $value)*,)* + $($default_field: Default::default(),)* + } + }; + } + + let rust_target = RustTarget::default(); + + options! { + rust_target, + rust_features: rust_target.into(), + layout_tests: true, + derive_copy: true, + derive_debug: true, + anon_fields_prefix: DEFAULT_ANON_FIELDS_PREFIX.into(), + convert_floats: true, + codegen_config: CodegenConfig::all(), + generate_comments: true, + allowlist_recursively: true, + enable_mangling: true, + detect_include_paths: true, + prepend_enum_name: true, + record_matches: true, + rustfmt_bindings: true, + size_t_is_usize: true, + + --default-fields-- + blocklisted_types, + blocklisted_functions, + blocklisted_items, + blocklisted_files, + opaque_types, + rustfmt_path, + depfile, + allowlisted_types, + allowlisted_functions, + allowlisted_vars, + allowlisted_files, + default_enum_style, + bitfield_enums, + newtype_enums, + newtype_global_enums, + rustified_enums, + rustified_non_exhaustive_enums, + constified_enums, + constified_enum_modules, + default_macro_constant_type, + default_alias_style, + type_alias, + new_type_alias, + new_type_alias_deref, + default_non_copy_union_style, + bindgen_wrapper_union, + manually_drop_union, + builtins, + emit_ast, + emit_ir, + emit_ir_graphviz, + impl_debug, + impl_partialeq, + derive_default, + derive_hash, + derive_partialord, + derive_ord, + derive_partialeq, + derive_eq, + enable_cxx_namespaces, + enable_function_attribute_detection, + disable_name_namespacing, + disable_nested_struct_naming, + disable_header_comment, + use_core, + ctypes_prefix, + raw_lines, + module_lines, + clang_args, + input_headers, + input_header_contents, + parse_callbacks, + conservative_inline_namespaces, + generate_inline_functions, + generate_block, + objc_extern_crate, + block_extern_crate, + fit_macro_constants, + time_phases, + rustfmt_configuration_file, + no_partialeq_types, + no_copy_types, + no_debug_types, + no_default_types, + no_hash_types, + must_use_types, + array_pointers_in_arguments, + wasm_import_module_name, + dynamic_library_name, + dynamic_link_require_all, + respect_cxx_access_specs, + translate_enum_integer_types, + c_naming, + force_explicit_padding, + vtable_generation, + sort_semantically, + merge_extern_blocks, + abi_overrides, + wrap_unsafe_ops, + wrap_static_fns, + wrap_static_fns_suffix, + wrap_static_fns_path, + } + } +} + +#[cfg(feature = "runtime")] +fn ensure_libclang_is_loaded() { + if clang_sys::is_loaded() { + return; + } + + // XXX (issue #350): Ensure that our dynamically loaded `libclang` + // doesn't get dropped prematurely, nor is loaded multiple times + // across different threads. + + lazy_static! { + static ref LIBCLANG: std::sync::Arc<clang_sys::SharedLibrary> = { + clang_sys::load().expect("Unable to find libclang"); + clang_sys::get_library().expect( + "We just loaded libclang and it had better still be \ + here!", + ) + }; + } + + clang_sys::set_library(Some(LIBCLANG.clone())); +} + +#[cfg(not(feature = "runtime"))] +fn ensure_libclang_is_loaded() {} + +/// Error type for rust-bindgen. +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +#[non_exhaustive] +pub enum BindgenError { + /// The header was a folder. + FolderAsHeader(PathBuf), + /// Permissions to read the header is insufficient. + InsufficientPermissions(PathBuf), + /// The header does not exist. + NotExist(PathBuf), + /// Clang diagnosed an error. + ClangDiagnostic(String), + /// Code generation reported an error. + Codegen(CodegenError), +} + +impl std::fmt::Display for BindgenError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + BindgenError::FolderAsHeader(h) => { + write!(f, "'{}' is a folder", h.display()) + } + BindgenError::InsufficientPermissions(h) => { + write!(f, "insufficient permissions to read '{}'", h.display()) + } + BindgenError::NotExist(h) => { + write!(f, "header '{}' does not exist.", h.display()) + } + BindgenError::ClangDiagnostic(message) => { + write!(f, "clang diagnosed error: {}", message) + } + BindgenError::Codegen(err) => { + write!(f, "codegen error: {}", err) + } + } + } +} + +impl std::error::Error for BindgenError {} + +/// Generated Rust bindings. +#[derive(Debug)] +pub struct Bindings { + options: BindgenOptions, + warnings: Vec<String>, + module: proc_macro2::TokenStream, +} + +pub(crate) const HOST_TARGET: &str = + include_str!(concat!(env!("OUT_DIR"), "/host-target.txt")); + +// Some architecture triplets are different between rust and libclang, see #1211 +// and duplicates. +fn rust_to_clang_target(rust_target: &str) -> String { + if rust_target.starts_with("aarch64-apple-") { + let mut clang_target = "arm64-apple-".to_owned(); + clang_target + .push_str(rust_target.strip_prefix("aarch64-apple-").unwrap()); + return clang_target; + } else if rust_target.starts_with("riscv64gc-") { + let mut clang_target = "riscv64-".to_owned(); + clang_target.push_str(rust_target.strip_prefix("riscv64gc-").unwrap()); + return clang_target; + } else if rust_target.ends_with("-espidf") { + let mut clang_target = + rust_target.strip_suffix("-espidf").unwrap().to_owned(); + clang_target.push_str("-elf"); + if clang_target.starts_with("riscv32imc-") { + clang_target = "riscv32-".to_owned() + + clang_target.strip_prefix("riscv32imc-").unwrap(); + } + return clang_target; + } + rust_target.to_owned() +} + +/// Returns the effective target, and whether it was explicitly specified on the +/// clang flags. +fn find_effective_target(clang_args: &[String]) -> (String, bool) { + let mut args = clang_args.iter(); + while let Some(opt) = args.next() { + if opt.starts_with("--target=") { + let mut split = opt.split('='); + split.next(); + return (split.next().unwrap().to_owned(), true); + } + + if opt == "-target" { + if let Some(target) = args.next() { + return (target.clone(), true); + } + } + } + + // If we're running from a build script, try to find the cargo target. + if let Ok(t) = env::var("TARGET") { + return (rust_to_clang_target(&t), false); + } + + (rust_to_clang_target(HOST_TARGET), false) +} + +impl Bindings { + /// Generate bindings for the given options. + pub(crate) fn generate( + mut options: BindgenOptions, + input_unsaved_files: Vec<clang::UnsavedFile>, + ) -> Result<Bindings, BindgenError> { + ensure_libclang_is_loaded(); + + #[cfg(feature = "runtime")] + debug!( + "Generating bindings, libclang at {}", + clang_sys::get_library().unwrap().path().display() + ); + #[cfg(not(feature = "runtime"))] + debug!("Generating bindings, libclang linked"); + + options.build(); + + let (effective_target, explicit_target) = + find_effective_target(&options.clang_args); + + let is_host_build = + rust_to_clang_target(HOST_TARGET) == effective_target; + + // NOTE: The is_host_build check wouldn't be sound normally in some + // cases if we were to call a binary (if you have a 32-bit clang and are + // building on a 64-bit system for example). But since we rely on + // opening libclang.so, it has to be the same architecture and thus the + // check is fine. + if !explicit_target && !is_host_build { + options + .clang_args + .insert(0, format!("--target={}", effective_target)); + }; + + fn detect_include_paths(options: &mut BindgenOptions) { + if !options.detect_include_paths { + return; + } + + // Filter out include paths and similar stuff, so we don't incorrectly + // promote them to `-isystem`. + let clang_args_for_clang_sys = { + let mut last_was_include_prefix = false; + options + .clang_args + .iter() + .filter(|arg| { + if last_was_include_prefix { + last_was_include_prefix = false; + return false; + } + + let arg = &**arg; + + // https://clang.llvm.org/docs/ClangCommandLineReference.html + // -isystem and -isystem-after are harmless. + if arg == "-I" || arg == "--include-directory" { + last_was_include_prefix = true; + return false; + } + + if arg.starts_with("-I") || + arg.starts_with("--include-directory=") + { + return false; + } + + true + }) + .cloned() + .collect::<Vec<_>>() + }; + + debug!( + "Trying to find clang with flags: {:?}", + clang_args_for_clang_sys + ); + + let clang = match clang_sys::support::Clang::find( + None, + &clang_args_for_clang_sys, + ) { + None => return, + Some(clang) => clang, + }; + + debug!("Found clang: {:?}", clang); + + // Whether we are working with C or C++ inputs. + let is_cpp = args_are_cpp(&options.clang_args) || + options.input_headers.iter().any(|h| file_is_cpp(h)); + + let search_paths = if is_cpp { + clang.cpp_search_paths + } else { + clang.c_search_paths + }; + + if let Some(search_paths) = search_paths { + for path in search_paths.into_iter() { + if let Ok(path) = path.into_os_string().into_string() { + options.clang_args.push("-isystem".to_owned()); + options.clang_args.push(path); + } + } + } + } + + detect_include_paths(&mut options); + + #[cfg(unix)] + fn can_read(perms: &std::fs::Permissions) -> bool { + use std::os::unix::fs::PermissionsExt; + perms.mode() & 0o444 > 0 + } + + #[cfg(not(unix))] + fn can_read(_: &std::fs::Permissions) -> bool { + true + } + + if let Some(h) = options.input_headers.last() { + let path = Path::new(h); + if let Ok(md) = std::fs::metadata(path) { + if md.is_dir() { + return Err(BindgenError::FolderAsHeader(path.into())); + } + if !can_read(&md.permissions()) { + return Err(BindgenError::InsufficientPermissions( + path.into(), + )); + } + let h = h.clone(); + options.clang_args.push(h); + } else { + return Err(BindgenError::NotExist(path.into())); + } + } + + for (idx, f) in input_unsaved_files.iter().enumerate() { + if idx != 0 || !options.input_headers.is_empty() { + options.clang_args.push("-include".to_owned()); + } + options.clang_args.push(f.name.to_str().unwrap().to_owned()) + } + + debug!("Fixed-up options: {:?}", options); + + let time_phases = options.time_phases; + let mut context = BindgenContext::new(options, &input_unsaved_files); + + if is_host_build { + debug_assert_eq!( + context.target_pointer_size(), + std::mem::size_of::<*mut ()>(), + "{:?} {:?}", + effective_target, + HOST_TARGET + ); + } + + { + let _t = time::Timer::new("parse").with_output(time_phases); + parse(&mut context)?; + } + + let (module, options, warnings) = + codegen::codegen(context).map_err(BindgenError::Codegen)?; + + Ok(Bindings { + options, + warnings, + module, + }) + } + + /// Write these bindings as source text to a file. + pub fn write_to_file<P: AsRef<Path>>(&self, path: P) -> io::Result<()> { + let file = OpenOptions::new() + .write(true) + .truncate(true) + .create(true) + .open(path.as_ref())?; + self.write(Box::new(file))?; + Ok(()) + } + + /// Write these bindings as source text to the given `Write`able. + pub fn write<'a>(&self, mut writer: Box<dyn Write + 'a>) -> io::Result<()> { + if !self.options.disable_header_comment { + let version = option_env!("CARGO_PKG_VERSION"); + let header = format!( + "/* automatically generated by rust-bindgen {} */\n\n", + version.unwrap_or("(unknown version)") + ); + writer.write_all(header.as_bytes())?; + } + + for line in self.options.raw_lines.iter() { + writer.write_all(line.as_bytes())?; + writer.write_all("\n".as_bytes())?; + } + + if !self.options.raw_lines.is_empty() { + writer.write_all("\n".as_bytes())?; + } + + let bindings = self.module.to_string(); + + match self.rustfmt_generated_string(&bindings) { + Ok(rustfmt_bindings) => { + writer.write_all(rustfmt_bindings.as_bytes())?; + } + Err(err) => { + eprintln!( + "Failed to run rustfmt: {} (non-fatal, continuing)", + err + ); + writer.write_all(bindings.as_bytes())?; + } + } + Ok(()) + } + + /// Gets the rustfmt path to rustfmt the generated bindings. + fn rustfmt_path(&self) -> io::Result<Cow<PathBuf>> { + debug_assert!(self.options.rustfmt_bindings); + if let Some(ref p) = self.options.rustfmt_path { + return Ok(Cow::Borrowed(p)); + } + if let Ok(rustfmt) = env::var("RUSTFMT") { + return Ok(Cow::Owned(rustfmt.into())); + } + #[cfg(feature = "which-rustfmt")] + match which::which("rustfmt") { + Ok(p) => Ok(Cow::Owned(p)), + Err(e) => { + Err(io::Error::new(io::ErrorKind::Other, format!("{}", e))) + } + } + #[cfg(not(feature = "which-rustfmt"))] + // No rustfmt binary was specified, so assume that the binary is called + // "rustfmt" and that it is in the user's PATH. + Ok(Cow::Owned("rustfmt".into())) + } + + /// Checks if rustfmt_bindings is set and runs rustfmt on the string + fn rustfmt_generated_string<'a>( + &self, + source: &'a str, + ) -> io::Result<Cow<'a, str>> { + let _t = time::Timer::new("rustfmt_generated_string") + .with_output(self.options.time_phases); + + if !self.options.rustfmt_bindings { + return Ok(Cow::Borrowed(source)); + } + + let rustfmt = self.rustfmt_path()?; + let mut cmd = Command::new(&*rustfmt); + + cmd.stdin(Stdio::piped()).stdout(Stdio::piped()); + + if let Some(path) = self + .options + .rustfmt_configuration_file + .as_ref() + .and_then(|f| f.to_str()) + { + cmd.args(["--config-path", path]); + } + + let mut child = cmd.spawn()?; + let mut child_stdin = child.stdin.take().unwrap(); + let mut child_stdout = child.stdout.take().unwrap(); + + let source = source.to_owned(); + + // Write to stdin in a new thread, so that we can read from stdout on this + // thread. This keeps the child from blocking on writing to its stdout which + // might block us from writing to its stdin. + let stdin_handle = ::std::thread::spawn(move || { + let _ = child_stdin.write_all(source.as_bytes()); + source + }); + + let mut output = vec![]; + io::copy(&mut child_stdout, &mut output)?; + + let status = child.wait()?; + let source = stdin_handle.join().expect( + "The thread writing to rustfmt's stdin doesn't do \ + anything that could panic", + ); + + match String::from_utf8(output) { + Ok(bindings) => match status.code() { + Some(0) => Ok(Cow::Owned(bindings)), + Some(2) => Err(io::Error::new( + io::ErrorKind::Other, + "Rustfmt parsing errors.".to_string(), + )), + Some(3) => { + warn!("Rustfmt could not format some lines."); + Ok(Cow::Owned(bindings)) + } + _ => Err(io::Error::new( + io::ErrorKind::Other, + "Internal rustfmt error".to_string(), + )), + }, + _ => Ok(Cow::Owned(source)), + } + } + + /// Emit all the warning messages raised while generating the bindings in a build script. + /// + /// If you are using `bindgen` outside of a build script you should use [`Bindings::warnings`] + /// and handle the messages accordingly instead. + #[inline] + pub fn emit_warnings(&self) { + for message in &self.warnings { + println!("cargo:warning={}", message); + } + } + + /// Return all the warning messages raised while generating the bindings. + #[inline] + pub fn warnings(&self) -> &[String] { + &self.warnings + } +} + +impl std::fmt::Display for Bindings { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let mut bytes = vec![]; + self.write(Box::new(&mut bytes) as Box<dyn Write>) + .expect("writing to a vec cannot fail"); + f.write_str( + std::str::from_utf8(&bytes) + .expect("we should only write bindings that are valid utf-8"), + ) + } +} + +/// Determines whether the given cursor is in any of the files matched by the +/// options. +fn filter_builtins(ctx: &BindgenContext, cursor: &clang::Cursor) -> bool { + ctx.options().builtins || !cursor.is_builtin() +} + +/// Parse one `Item` from the Clang cursor. +fn parse_one( + ctx: &mut BindgenContext, + cursor: clang::Cursor, + parent: Option<ItemId>, +) -> clang_sys::CXChildVisitResult { + if !filter_builtins(ctx, &cursor) { + return CXChildVisit_Continue; + } + + use clang_sys::CXChildVisit_Continue; + match Item::parse(cursor, parent, ctx) { + Ok(..) => {} + Err(ParseError::Continue) => {} + Err(ParseError::Recurse) => { + cursor.visit(|child| parse_one(ctx, child, parent)); + } + } + CXChildVisit_Continue +} + +/// Parse the Clang AST into our `Item` internal representation. +fn parse(context: &mut BindgenContext) -> Result<(), BindgenError> { + use clang_sys::*; + + let mut error = None; + for d in context.translation_unit().diags().iter() { + let msg = d.format(); + let is_err = d.severity() >= CXDiagnostic_Error; + if is_err { + let error = error.get_or_insert_with(String::new); + error.push_str(&msg); + error.push('\n'); + } else { + eprintln!("clang diag: {}", msg); + } + } + + if let Some(message) = error { + return Err(BindgenError::ClangDiagnostic(message)); + } + + let cursor = context.translation_unit().cursor(); + + if context.options().emit_ast { + fn dump_if_not_builtin(cur: &clang::Cursor) -> CXChildVisitResult { + if !cur.is_builtin() { + clang::ast_dump(cur, 0) + } else { + CXChildVisit_Continue + } + } + cursor.visit(|cur| dump_if_not_builtin(&cur)); + } + + let root = context.root_module(); + context.with_module(root, |context| { + cursor.visit(|cursor| parse_one(context, cursor, None)) + }); + + assert!( + context.current_module() == context.root_module(), + "How did this happen?" + ); + Ok(()) +} + +/// Extracted Clang version data +#[derive(Debug)] +pub struct ClangVersion { + /// Major and minor semver, if parsing was successful + pub parsed: Option<(u32, u32)>, + /// full version string + pub full: String, +} + +/// Get the major and the minor semver numbers of Clang's version +pub fn clang_version() -> ClangVersion { + ensure_libclang_is_loaded(); + + //Debian clang version 11.0.1-2 + let raw_v: String = clang::extract_clang_version(); + let split_v: Option<Vec<&str>> = raw_v + .split_whitespace() + .find(|t| t.chars().next().map_or(false, |v| v.is_ascii_digit())) + .map(|v| v.split('.').collect()); + if let Some(v) = split_v { + if v.len() >= 2 { + let maybe_major = v[0].parse::<u32>(); + let maybe_minor = v[1].parse::<u32>(); + if let (Ok(major), Ok(minor)) = (maybe_major, maybe_minor) { + return ClangVersion { + parsed: Some((major, minor)), + full: raw_v.clone(), + }; + } + } + }; + ClangVersion { + parsed: None, + full: raw_v.clone(), + } +} + +/// Looks for the env var `var_${TARGET}`, and falls back to just `var` when it is not found. +fn get_target_dependent_env_var(var: &str) -> Option<String> { + if let Ok(target) = env::var("TARGET") { + if let Ok(v) = env::var(format!("{}_{}", var, target)) { + return Some(v); + } + if let Ok(v) = env::var(format!("{}_{}", var, target.replace('-', "_"))) + { + return Some(v); + } + } + env::var(var).ok() +} + +/// A ParseCallbacks implementation that will act on file includes by echoing a rerun-if-changed +/// line +/// +/// When running inside a `build.rs` script, this can be used to make cargo invalidate the +/// generated bindings whenever any of the files included from the header change: +/// ``` +/// use bindgen::builder; +/// let bindings = builder() +/// .header("path/to/input/header") +/// .parse_callbacks(Box::new(bindgen::CargoCallbacks)) +/// .generate(); +/// ``` +#[derive(Debug)] +pub struct CargoCallbacks; + +impl callbacks::ParseCallbacks for CargoCallbacks { + fn include_file(&self, filename: &str) { + println!("cargo:rerun-if-changed={}", filename); + } +} + +/// Test command_line_flag function. +#[test] +fn commandline_flag_unit_test_function() { + //Test 1 + let bindings = crate::builder(); + let command_line_flags = bindings.command_line_flags(); + + let test_cases = vec![ + "--rust-target", + "--no-derive-default", + "--generate", + "functions,types,vars,methods,constructors,destructors", + ] + .iter() + .map(|&x| x.into()) + .collect::<Vec<String>>(); + + assert!(test_cases.iter().all(|x| command_line_flags.contains(x))); + + //Test 2 + let bindings = crate::builder() + .header("input_header") + .allowlist_type("Distinct_Type") + .allowlist_function("safe_function"); + + let command_line_flags = bindings.command_line_flags(); + let test_cases = vec![ + "--rust-target", + "input_header", + "--no-derive-default", + "--generate", + "functions,types,vars,methods,constructors,destructors", + "--allowlist-type", + "Distinct_Type", + "--allowlist-function", + "safe_function", + ] + .iter() + .map(|&x| x.into()) + .collect::<Vec<String>>(); + println!("{:?}", command_line_flags); + + assert!(test_cases.iter().all(|x| command_line_flags.contains(x))); +} + +#[test] +fn test_rust_to_clang_target() { + assert_eq!(rust_to_clang_target("aarch64-apple-ios"), "arm64-apple-ios"); +} + +#[test] +fn test_rust_to_clang_target_riscv() { + assert_eq!( + rust_to_clang_target("riscv64gc-unknown-linux-gnu"), + "riscv64-unknown-linux-gnu" + ) +} + +#[test] +fn test_rust_to_clang_target_espidf() { + assert_eq!( + rust_to_clang_target("riscv32imc-esp-espidf"), + "riscv32-esp-elf" + ); + assert_eq!( + rust_to_clang_target("xtensa-esp32-espidf"), + "xtensa-esp32-elf" + ); +} |