diff --git a/src/builder.rs b/src/builder.rs new file mode 100644 index 0000000000..cb06850263 --- /dev/null +++ b/src/builder.rs @@ -0,0 +1,2195 @@ +use std::{ + collections::HashMap, + env, + fs::File, + io::{self, Write}, + path::PathBuf, + process::{Command, Stdio}, +}; + +use crate::{ + args_are_cpp, + callbacks::ParseCallbacks, + clang, + codegen::{AliasVariation, EnumVariation, MacroTypeVariation}, + deps::DepfileSpec, + features::{RustFeatures, RustTarget, LATEST_STABLE_RUST}, + file_is_cpp, get_extra_clang_args, + regex_set::{RegexItems, RegexSet}, + BindgenError, BindgenState, Bindings, CodegenConfig, + DEFAULT_ANON_FIELDS_PREFIX, +}; + +/// 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`. +#[derive(Debug, Default)] +pub struct Builder { + parse_callbacks: Option>, + inputs: BindgenInputs, +} + +impl Builder { + /// Generates the command line flags use for creating `Builder`. + pub fn command_line_flags(&self) -> Vec { + let mut output_vector: Vec = Vec::new(); + + if let Some(header) = self.inputs.input_headers.last().cloned() { + // Positional argument 'header' + output_vector.push(header); + } + + output_vector.push("--rust-target".into()); + output_vector.push(self.inputs.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.inputs.rust_features.untagged_union && + RustFeatures::from(self.inputs.rust_target).untagged_union + { + output_vector.push("--disable-untagged-union".into()); + } + + if self.inputs.default_enum_style != Default::default() { + output_vector.push("--default-enum-style".into()); + output_vector.push( + match self.inputs.default_enum_style { + EnumVariation::Rust { + non_exhaustive: false, + } => "rust", + EnumVariation::Rust { + non_exhaustive: true, + } => "rust_non_exhaustive", + EnumVariation::NewType { + is_bitfield: true, .. + } => "bitfield", + EnumVariation::NewType { + is_bitfield: false, + is_global, + } => { + if is_global { + "newtype_global" + } else { + "newtype" + } + } + EnumVariation::Consts => "consts", + EnumVariation::ModuleConsts => "moduleconsts", + } + .into(), + ) + } + + if self.inputs.default_macro_constant_type != Default::default() { + output_vector.push("--default-macro-constant-type".into()); + output_vector + .push(self.inputs.default_macro_constant_type.as_str().into()); + } + + if self.inputs.default_alias_style != Default::default() { + output_vector.push("--default-alias-style".into()); + output_vector.push(self.inputs.default_alias_style.as_str().into()); + } + + if self.inputs.default_non_copy_union_style != Default::default() { + output_vector.push("--default-non-copy-union-style".into()); + output_vector + .push(self.inputs.default_non_copy_union_style.as_str().into()); + } + + let regex_items = &[ + (&self.inputs.bitfield_enums, "--bitfield-enum"), + (&self.inputs.newtype_enums, "--newtype-enum"), + (&self.inputs.newtype_global_enums, "--newtype-global-enum"), + (&self.inputs.rustified_enums, "--rustified-enum"), + ( + &self.inputs.rustified_non_exhaustive_enums, + "--rustified-enum-non-exhaustive", + ), + ( + &self.inputs.constified_enum_modules, + "--constified-enum-module", + ), + (&self.inputs.constified_enums, "--constified-enum"), + (&self.inputs.type_alias, "--type-alias"), + (&self.inputs.new_type_alias, "--new-type-alias"), + (&self.inputs.new_type_alias_deref, "--new-type-alias-deref"), + ( + &self.inputs.bindgen_wrapper_union, + "--bindgen-wrapper-union", + ), + (&self.inputs.manually_drop_union, "--manually-drop-union"), + (&self.inputs.blocklisted_types, "--blocklist-type"), + (&self.inputs.blocklisted_functions, "--blocklist-function"), + (&self.inputs.blocklisted_items, "--blocklist-item"), + (&self.inputs.blocklisted_files, "--blocklist-file"), + (&self.inputs.opaque_types, "--opaque-type"), + (&self.inputs.allowlisted_functions, "--allowlist-function"), + (&self.inputs.allowlisted_types, "--allowlist-type"), + (&self.inputs.allowlisted_vars, "--allowlist-var"), + (&self.inputs.allowlisted_files, "--allowlist-file"), + (&self.inputs.no_partialeq_types, "--no-partialeq"), + (&self.inputs.no_copy_types, "--no-copy"), + (&self.inputs.no_debug_types, "--no-debug"), + (&self.inputs.no_default_types, "--no-default"), + (&self.inputs.no_hash_types, "--no-hash"), + (&self.inputs.must_use_types, "--must-use-type"), + ]; + + for (items, flag) in regex_items { + for item in items.get_items() { + output_vector.push((*flag).to_owned()); + output_vector.push(item.to_owned()); + } + } + + if !self.inputs.layout_tests { + output_vector.push("--no-layout-tests".into()); + } + + if self.inputs.impl_debug { + output_vector.push("--impl-debug".into()); + } + + if self.inputs.impl_partialeq { + output_vector.push("--impl-partialeq".into()); + } + + if !self.inputs.derive_copy { + output_vector.push("--no-derive-copy".into()); + } + + if !self.inputs.derive_debug { + output_vector.push("--no-derive-debug".into()); + } + + if self.inputs.derive_default { + output_vector.push("--with-derive-default".into()); + } else { + output_vector.push("--no-derive-default".into()); + } + + if self.inputs.derive_hash { + output_vector.push("--with-derive-hash".into()); + } + + if self.inputs.derive_partialord { + output_vector.push("--with-derive-partialord".into()); + } + + if self.inputs.derive_ord { + output_vector.push("--with-derive-ord".into()); + } + + if self.inputs.derive_partialeq { + output_vector.push("--with-derive-partialeq".into()); + } + + if self.inputs.derive_eq { + output_vector.push("--with-derive-eq".into()); + } + + if self.inputs.time_phases { + output_vector.push("--time-phases".into()); + } + + if !self.inputs.generate_comments { + output_vector.push("--no-doc-comments".into()); + } + + if !self.inputs.allowlist_recursively { + output_vector.push("--no-recursive-allowlist".into()); + } + + if self.inputs.objc_extern_crate { + output_vector.push("--objc-extern-crate".into()); + } + + if self.inputs.generate_block { + output_vector.push("--generate-block".into()); + } + + if self.inputs.block_extern_crate { + output_vector.push("--block-extern-crate".into()); + } + + if self.inputs.builtins { + output_vector.push("--builtins".into()); + } + + if let Some(ref prefix) = self.inputs.ctypes_prefix { + output_vector.push("--ctypes-prefix".into()); + output_vector.push(prefix.clone()); + } + + if self.inputs.anon_fields_prefix != DEFAULT_ANON_FIELDS_PREFIX { + output_vector.push("--anon-fields-prefix".into()); + output_vector.push(self.inputs.anon_fields_prefix.clone()); + } + + if self.inputs.emit_ast { + output_vector.push("--emit-clang-ast".into()); + } + + if self.inputs.emit_ir { + output_vector.push("--emit-ir".into()); + } + if let Some(ref graph) = self.inputs.emit_ir_graphviz { + output_vector.push("--emit-ir-graphviz".into()); + output_vector.push(graph.clone()) + } + if self.inputs.enable_cxx_namespaces { + output_vector.push("--enable-cxx-namespaces".into()); + } + if self.inputs.enable_function_attribute_detection { + output_vector.push("--enable-function-attribute-detection".into()); + } + if !self.inputs.enable_name_namespacing { + output_vector.push("--disable-name-namespacing".into()); + } + if !self.inputs.enable_nested_struct_naming { + output_vector.push("--disable-nested-struct-naming".into()); + } + + if !self.inputs.enable_header_comment { + output_vector.push("--disable-header-comment".into()); + } + + if !self.inputs.codegen_config.functions() { + output_vector.push("--ignore-functions".into()); + } + + output_vector.push("--generate".into()); + + //Temporary placeholder for below 4 options + let mut options: Vec = Vec::new(); + if self.inputs.codegen_config.functions() { + options.push("functions".into()); + } + if self.inputs.codegen_config.types() { + options.push("types".into()); + } + if self.inputs.codegen_config.vars() { + options.push("vars".into()); + } + if self.inputs.codegen_config.methods() { + options.push("methods".into()); + } + if self.inputs.codegen_config.constructors() { + options.push("constructors".into()); + } + if self.inputs.codegen_config.destructors() { + options.push("destructors".into()); + } + + output_vector.push(options.join(",")); + + if !self.inputs.codegen_config.methods() { + output_vector.push("--ignore-methods".into()); + } + + if !self.inputs.convert_floats { + output_vector.push("--no-convert-floats".into()); + } + + if !self.inputs.prepend_enum_name { + output_vector.push("--no-prepend-enum-name".into()); + } + + if self.inputs.fit_macro_constants { + output_vector.push("--fit-macro-constant-types".into()); + } + + if self.inputs.array_pointers_in_arguments { + output_vector.push("--use-array-pointers-in-arguments".into()); + } + + if let Some(ref wasm_import_module_name) = + self.inputs.wasm_import_module_name + { + output_vector.push("--wasm-import-module-name".into()); + output_vector.push(wasm_import_module_name.clone()); + } + + for line in &self.inputs.raw_lines { + output_vector.push("--raw-line".into()); + output_vector.push(line.clone()); + } + + for (module, lines) in &self.inputs.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.inputs.use_core { + output_vector.push("--use-core".into()); + } + + if self.inputs.conservative_inline_namespaces { + output_vector.push("--conservative-inline-namespaces".into()); + } + + if self.inputs.generate_inline_functions { + output_vector.push("--generate-inline-functions".into()); + } + + if !self.inputs.record_matches { + output_vector.push("--no-record-matches".into()); + } + + if self.inputs.size_t_is_usize { + output_vector.push("--size_t-is-usize".into()); + } + + if !self.inputs.rustfmt_bindings { + output_vector.push("--no-rustfmt-bindings".into()); + } + + if let Some(path) = self + .inputs + .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.inputs.dynamic_library_name { + output_vector.push("--dynamic-loading".into()); + output_vector.push(name.clone()); + } + + if self.inputs.dynamic_link_require_all { + output_vector.push("--dynamic-link-require-all".into()); + } + + if self.inputs.respect_cxx_access_specs { + output_vector.push("--respect-cxx-access-specs".into()); + } + + if self.inputs.translate_enum_integer_types { + output_vector.push("--translate-enum-integer-types".into()); + } + + if self.inputs.c_naming { + output_vector.push("--c-naming".into()); + } + + if self.inputs.force_explicit_padding { + output_vector.push("--explicit-padding".into()); + } + + if self.inputs.vtable_generation { + output_vector.push("--vtable-generation".into()); + } + + if self.inputs.sort_semantically { + output_vector.push("--sort-semantically".into()); + } + + if self.inputs.merge_extern_blocks { + output_vector.push("--merge-extern-blocks".into()); + } + + // Add clang arguments + + output_vector.push("--".into()); + + if !self.inputs.clang_args.is_empty() { + output_vector.extend(self.inputs.clang_args.iter().cloned()); + } + + if self.inputs.input_headers.len() > 1 { + // To pass more than one header, we need to pass all but the last + // header via the `-include` clang arg + for header in &self.inputs.input_headers + [..self.inputs.input_headers.len() - 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>(mut self, header: T) -> Builder { + self.inputs.input_headers.push(header.into()); + self + } + + /// Add a depfile output which will be written alongside the generated bindings. + pub fn depfile, D: Into>( + mut self, + output_module: H, + depfile: D, + ) -> Builder { + self.inputs.depfile = Some(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.inputs + .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 { + self.inputs.set_rust_target(rust_target); + self + } + + /// Disable support for native Rust unions, if supported. + pub fn disable_untagged_union(mut self) -> Self { + self.inputs.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.inputs.enable_header_comment = false; + self + } + + /// Set the output graphviz file. + pub fn emit_ir_graphviz>(mut self, path: T) -> Builder { + let path = path.into(); + self.inputs.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.inputs.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.inputs.allowlist_recursively = doit; + self + } + + /// Deprecated alias for allowlist_recursively. + #[deprecated(note = "Use allowlist_recursively instead")] + pub fn whitelist_recursively(self, doit: bool) -> Self { + self.allowlist_recursively(doit) + } + + /// 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.inputs.objc_extern_crate = doit; + self + } + + /// Generate proper block signatures instead of void pointers. + pub fn generate_block(mut self, doit: bool) -> Self { + self.inputs.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.inputs.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.inputs.enable_mangling = doit; + self + } + + /// Hide the given type from the generated bindings. Regular expressions are + /// supported. + #[deprecated(note = "Use blocklist_type instead")] + pub fn hide_type>(self, arg: T) -> Builder { + self.blocklist_type(arg) + } + + /// Hide the given type from the generated bindings. Regular expressions are + /// supported. + #[deprecated(note = "Use blocklist_type instead")] + pub fn blacklist_type>(self, arg: T) -> Builder { + self.blocklist_type(arg) + } + + /// Hide the given type from the generated bindings. Regular expressions are + /// supported. + /// + /// To blocklist types prefixed with "mylib" use `"mylib_.*"`. + /// For more complicated expressions check + /// [regex](https://docs.rs/regex/*/regex/) docs + pub fn blocklist_type>(mut self, arg: T) -> Builder { + self.inputs.blocklisted_types.insert(arg); + self + } + + /// Hide the given function from the generated bindings. Regular expressions + /// are supported. + #[deprecated(note = "Use blocklist_function instead")] + pub fn blacklist_function>(self, arg: T) -> Builder { + self.blocklist_function(arg) + } + + /// Hide the given function from the generated bindings. Regular expressions + /// are supported. + /// + /// To blocklist functions prefixed with "mylib" use `"mylib_.*"`. + /// For more complicated expressions check + /// [regex](https://docs.rs/regex/*/regex/) docs + pub fn blocklist_function>(mut self, arg: T) -> Builder { + self.inputs.blocklisted_functions.insert(arg); + self + } + + /// Hide the given item from the generated bindings, regardless of + /// whether it's a type, function, module, etc. Regular + /// expressions are supported. + #[deprecated(note = "Use blocklist_item instead")] + pub fn blacklist_item>(mut self, arg: T) -> Builder { + self.inputs.blocklisted_items.insert(arg); + self + } + + /// 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_.*"`. + /// For more complicated expressions check + /// [regex](https://docs.rs/regex/*/regex/) docs + pub fn blocklist_item>(mut self, arg: T) -> Builder { + self.inputs.blocklisted_items.insert(arg); + self + } + + /// 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>(mut self, arg: T) -> Builder { + self.inputs.blocklisted_files.insert(arg); + self + } + + /// Treat the given type as opaque in the generated bindings. Regular + /// expressions are supported. + /// + /// To change types prefixed with "mylib" into opaque, use `"mylib_.*"`. + /// For more complicated expressions check + /// [regex](https://docs.rs/regex/*/regex/) docs + pub fn opaque_type>(mut self, arg: T) -> Builder { + self.inputs.opaque_types.insert(arg); + self + } + + /// Allowlist the given type so that it (and all types that it transitively + /// refers to) appears in the generated bindings. Regular expressions are + /// supported. + #[deprecated(note = "use allowlist_type instead")] + pub fn whitelisted_type>(self, arg: T) -> Builder { + self.allowlist_type(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. + #[deprecated(note = "use allowlist_type instead")] + pub fn whitelist_type>(self, arg: T) -> Builder { + self.allowlist_type(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_.*"`. + /// For more complicated expressions check + /// [regex](https://docs.rs/regex/*/regex/) docs + pub fn allowlist_type>(mut self, arg: T) -> Builder { + self.inputs.allowlisted_types.insert(arg); + self + } + + /// Allowlist the given function so that it (and all types that it + /// transitively refers to) appears in the generated bindings. Regular + /// expressions are supported. + /// + /// To allowlist functions prefixed with "mylib" use `"mylib_.*"`. + /// For more complicated expressions check + /// [regex](https://docs.rs/regex/*/regex/) docs + pub fn allowlist_function>(mut self, arg: T) -> Builder { + self.inputs.allowlisted_functions.insert(arg); + self + } + + /// Allowlist the given function. + /// + /// Deprecated: use allowlist_function instead. + #[deprecated(note = "use allowlist_function instead")] + pub fn whitelist_function>(self, arg: T) -> Builder { + self.allowlist_function(arg) + } + + /// Allowlist the given function. + /// + /// Deprecated: use allowlist_function instead. + #[deprecated(note = "use allowlist_function instead")] + pub fn whitelisted_function>(self, arg: T) -> Builder { + self.allowlist_function(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_.*"`. + /// For more complicated expressions check + /// [regex](https://docs.rs/regex/*/regex/) docs + pub fn allowlist_var>(mut self, arg: T) -> Builder { + self.inputs.allowlisted_vars.insert(arg); + self + } + + /// Allowlist the given file so that its contents appear in the generated bindings. + pub fn allowlist_file>(mut self, arg: T) -> Builder { + self.inputs.allowlisted_files.insert(arg); + self + } + + /// Deprecated: use allowlist_var instead. + #[deprecated(note = "use allowlist_var instead")] + pub fn whitelist_var>(self, arg: T) -> Builder { + self.allowlist_var(arg) + } + + /// Allowlist the given variable. + /// + /// Deprecated: use allowlist_var instead. + #[deprecated(note = "use allowlist_var instead")] + pub fn whitelisted_var>(self, arg: T) -> Builder { + self.allowlist_var(arg) + } + + /// Set the default style of code to generate for enums + pub fn default_enum_style(mut self, arg: EnumVariation) -> Builder { + self.inputs.default_enum_style = arg; + self + } + + /// 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>(mut self, arg: T) -> Builder { + self.inputs.bitfield_enums.insert(arg); + self + } + + /// 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>(mut self, arg: T) -> Builder { + self.inputs.newtype_enums.insert(arg); + self + } + + /// 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>(mut self, arg: T) -> Builder { + self.inputs.newtype_global_enums.insert(arg); + self + } + + /// 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>(mut self, arg: T) -> Builder { + self.inputs.rustified_enums.insert(arg); + self + } + + /// 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>( + mut self, + arg: T, + ) -> Builder { + self.inputs.rustified_non_exhaustive_enums.insert(arg); + self + } + + /// 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>(mut self, arg: T) -> Builder { + self.inputs.constified_enums.insert(arg); + self + } + + /// 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>(mut self, arg: T) -> Builder { + self.inputs.constified_enum_modules.insert(arg); + self + } + + /// Set the default type for macro constants + pub fn default_macro_constant_type( + mut self, + arg: MacroTypeVariation, + ) -> Builder { + self.inputs.default_macro_constant_type = arg; + self + } + + /// Set the default style of code to generate for typedefs + pub fn default_alias_style(mut self, arg: AliasVariation) -> Builder { + self.inputs.default_alias_style = arg; + self + } + + /// 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>(mut self, arg: T) -> Builder { + self.inputs.type_alias.insert(arg); + self + } + + /// 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>(mut self, arg: T) -> Builder { + self.inputs.new_type_alias.insert(arg); + self + } + + /// 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>(mut self, arg: T) -> Builder { + self.inputs.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: crate::codegen::NonCopyUnionStyle, + ) -> Self { + self.inputs.default_non_copy_union_style = arg; + self + } + + /// 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>(mut self, arg: T) -> Self { + self.inputs.bindgen_wrapper_union.insert(arg); + self + } + + /// 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>(mut self, arg: T) -> Self { + self.inputs.manually_drop_union.insert(arg); + self + } + + /// Add a string to prepend to the generated bindings. The string is passed + /// through without any modification. + pub fn raw_line>(mut self, arg: T) -> Self { + self.inputs.raw_lines.push(arg.into()); + self + } + + /// Add a given line to the beginning of module `mod`. + pub fn module_raw_line(mut self, mod_: T, line: U) -> Self + where + T: Into, + U: Into, + { + self.inputs + .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(mut self, mod_: T, lines: I) -> Self + where + T: Into, + I: IntoIterator, + I::Item: Into, + { + self.inputs + .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>(mut self, arg: T) -> Builder { + self.inputs.clang_args.push(arg.into()); + self + } + + /// Add arguments to be passed straight through to clang. + pub fn clang_args(mut self, iter: I) -> Builder + where + I: IntoIterator, + I::Item: AsRef, + { + 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.inputs.builtins = true; + self + } + + /// Avoid converting floats to `f32`/`f64` by default. + pub fn no_convert_floats(mut self) -> Self { + self.inputs.convert_floats = false; + self + } + + /// Set whether layout tests should be generated. + pub fn layout_tests(mut self, doit: bool) -> Self { + self.inputs.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.inputs.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.inputs.impl_partialeq = doit; + self + } + + /// Set whether `Copy` should be derived by default. + pub fn derive_copy(mut self, doit: bool) -> Self { + self.inputs.derive_copy = doit; + self + } + + /// Set whether `Debug` should be derived by default. + pub fn derive_debug(mut self, doit: bool) -> Self { + self.inputs.derive_debug = doit; + self + } + + /// Set whether `Default` should be derived by default. + pub fn derive_default(mut self, doit: bool) -> Self { + self.inputs.derive_default = doit; + self + } + + /// Set whether `Hash` should be derived by default. + pub fn derive_hash(mut self, doit: bool) -> Self { + self.inputs.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.inputs.derive_partialord = doit; + if !doit { + self.inputs.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.inputs.derive_ord = doit; + self.inputs.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.inputs.derive_partialeq = doit; + if !doit { + self.inputs.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.inputs.derive_eq = doit; + if doit { + self.inputs.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.inputs.time_phases = doit; + self + } + + /// Emit Clang AST. + pub fn emit_clang_ast(mut self) -> Builder { + self.inputs.emit_ast = true; + self + } + + /// Emit IR. + pub fn emit_ir(mut self) -> Builder { + self.inputs.emit_ir = true; + self + } + + /// Enable C++ namespaces. + pub fn enable_cxx_namespaces(mut self) -> Builder { + self.inputs.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.inputs.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.inputs.enable_name_namespacing = false; + 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.inputs.enable_nested_struct_naming = false; + 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.inputs.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.inputs.generate_inline_functions = doit; + self + } + + /// Ignore functions. + pub fn ignore_functions(mut self) -> Builder { + self.inputs.codegen_config.remove(CodegenConfig::FUNCTIONS); + self + } + + /// Ignore methods. + pub fn ignore_methods(mut self) -> Builder { + self.inputs.codegen_config.remove(CodegenConfig::METHODS); + self + } + + /// Avoid generating any unstable Rust, such as Rust unions, in the generated bindings. + #[deprecated(note = "please use `rust_target` instead")] + pub fn unstable_rust(self, doit: bool) -> Self { + let rust_target = if doit { + RustTarget::Nightly + } else { + LATEST_STABLE_RUST + }; + self.rust_target(rust_target) + } + + /// Use core instead of libstd in the generated bindings. + pub fn use_core(mut self) -> Builder { + self.inputs.use_core = true; + self + } + + /// Use the given prefix for the raw types instead of `::std::os::raw`. + pub fn ctypes_prefix>(mut self, prefix: T) -> Builder { + self.inputs.ctypes_prefix = Some(prefix.into()); + self + } + + /// Use the given prefix for the anon fields. + pub fn anon_fields_prefix>(mut self, prefix: T) -> Builder { + self.inputs.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) -> Self { + self.parse_callbacks = Some(cb); + self + } + + /// Choose what to generate using a + /// [`CodegenConfig`](./struct.CodegenConfig.html). + pub fn with_codegen_config(mut self, config: CodegenConfig) -> Self { + self.inputs.codegen_config = config; + self + } + + /// Whether to detect include paths using clang_sys. + pub fn detect_include_paths(mut self, doit: bool) -> Self { + self.inputs.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.inputs.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.inputs.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.inputs.size_t_is_usize = is; + self + } + + /// Set whether rustfmt should format the generated bindings. + pub fn rustfmt_bindings(mut self, doit: bool) -> Self { + self.inputs.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.inputs.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) -> Self { + self = self.rustfmt_bindings(true); + self.inputs.rustfmt_configuration_file = path; + self + } + + /// Sets an explicit path to rustfmt, to be used when rustfmt is enabled. + pub fn with_rustfmt>(mut self, path: P) -> Self { + self.inputs.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.inputs.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.inputs.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.inputs.sort_semantically = doit; + self + } + + /// If true, merges extern blocks. + pub fn merge_extern_blocks(mut self, doit: bool) -> Self { + self.inputs.merge_extern_blocks = doit; + self + } + + /// Generate the Rust bindings using the options built up thus far. + pub fn generate(self) -> Result { + Bindings::generate(BindgenOptions { + state: BindgenState::build(&self.inputs, self.parse_callbacks), + inputs: self.inputs, + }) + } + + /// 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.inputs.clang_args); + + // For each input header, add `#include "$header"`. + for header in &self.inputs.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 &(ref name, ref contents) in &self.inputs.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.inputs.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", + )) + } + } + + /// Don't derive `PartialEq` for a given type. Regular + /// expressions are supported. + pub fn no_partialeq>(mut self, arg: T) -> Builder { + self.inputs.no_partialeq_types.insert(arg.into()); + self + } + + /// Don't derive `Copy` for a given type. Regular + /// expressions are supported. + pub fn no_copy>(mut self, arg: T) -> Self { + self.inputs.no_copy_types.insert(arg.into()); + self + } + + /// Don't derive `Debug` for a given type. Regular + /// expressions are supported. + pub fn no_debug>(mut self, arg: T) -> Self { + self.inputs.no_debug_types.insert(arg.into()); + self + } + + /// Don't derive/impl `Default` for a given type. Regular + /// expressions are supported. + pub fn no_default>(mut self, arg: T) -> Self { + self.inputs.no_default_types.insert(arg.into()); + self + } + + /// Don't derive `Hash` for a given type. Regular + /// expressions are supported. + pub fn no_hash>(mut self, arg: T) -> Builder { + self.inputs.no_hash_types.insert(arg.into()); + self + } + + /// Add `#[must_use]` for the given type. Regular + /// expressions are supported. + pub fn must_use_type>(mut self, arg: T) -> Builder { + self.inputs.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.inputs.array_pointers_in_arguments = doit; + self + } + + /// Set the wasm import module name + pub fn wasm_import_module_name>( + mut self, + import_name: T, + ) -> Self { + self.inputs.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>( + mut self, + dynamic_library_name: T, + ) -> Self { + self.inputs.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.inputs.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.inputs.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.inputs.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.inputs.c_naming = doit; + self + } +} + +#[derive(Debug)] +pub(crate) struct BindgenOptions { + inputs: BindgenInputs, + state: BindgenState, +} + +impl BindgenOptions { + pub(crate) fn inputs(&self) -> &BindgenInputs { + &self.inputs + } + + pub(crate) fn state(&self) -> &BindgenState { + &self.state + } + + pub(crate) fn state_mut(&mut self) -> &mut BindgenState { + &mut self.state + } +} + +#[derive(Debug, Clone)] +pub(crate) struct BindgenInputs { + /// The set of types that have been blocklisted and should not appear + /// anywhere in the generated code. + blocklisted_types: RegexItems, + + /// The set of functions that have been blocklisted and should not appear + /// in the generated code. + blocklisted_functions: RegexItems, + + /// The set of items, regardless of item-type, that have been + /// blocklisted and should not appear in the generated code. + blocklisted_items: RegexItems, + + /// The set of files whose contents should be blocklisted and should not + /// appear in the generated code. + blocklisted_files: RegexItems, + + /// The set of types that should be treated as opaque structures in the + /// generated code. + opaque_types: RegexItems, + + /// The explicit rustfmt path. + pub(crate) rustfmt_path: Option, + + /// The path to which we should write a Makefile-syntax depfile (if any). + pub(crate) depfile: Option, + + /// 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: RegexItems, + + /// Allowlisted functions. See docs for `allowlisted_types` for more. + allowlisted_functions: RegexItems, + + /// Allowlisted variables. See docs for `allowlisted_types` for more. + allowlisted_vars: RegexItems, + + /// The set of files whose contents should be allowlisted. + allowlisted_files: RegexItems, + + /// The default style of code to generate for enums + pub(crate) default_enum_style: EnumVariation, + + /// The enum patterns to mark an enum as a bitfield + /// (newtype with bitwise operations). + bitfield_enums: RegexItems, + + /// The enum patterns to mark an enum as a newtype. + newtype_enums: RegexItems, + + /// The enum patterns to mark an enum as a global newtype. + newtype_global_enums: RegexItems, + + /// The enum patterns to mark an enum as a Rust enum. + rustified_enums: RegexItems, + + /// The enum patterns to mark an enum as a non-exhaustive Rust enum. + rustified_non_exhaustive_enums: RegexItems, + + /// The enum patterns to mark an enum as a module of constants. + constified_enum_modules: RegexItems, + + /// The enum patterns to mark an enum as a set of constants. + constified_enums: RegexItems, + + /// The default type for C macro constants. + pub(crate) default_macro_constant_type: MacroTypeVariation, + + /// The default style of code to generate for typedefs. + pub(crate) default_alias_style: AliasVariation, + + /// Typedef patterns that will use regular type aliasing. + type_alias: RegexItems, + + /// Typedef patterns that will be aliased by creating a new struct. + new_type_alias: RegexItems, + + /// Typedef patterns that will be wrapped in a new struct and have + /// Deref and Deref to their aliased type. + new_type_alias_deref: RegexItems, + + /// The default style of code to generate for union containing non-Copy + /// members. + pub(crate) default_non_copy_union_style: crate::codegen::NonCopyUnionStyle, + + /// The union patterns to mark an non-Copy union as using the bindgen + /// generated wrapper. + pub(crate) bindgen_wrapper_union: RegexItems, + + /// The union patterns to mark an non-Copy union as using the + /// `::core::mem::ManuallyDrop` wrapper. + manually_drop_union: RegexItems, + + /// Whether we should generate builtins or not. + pub(crate) builtins: bool, + + /// True if we should dump the Clang AST for debugging purposes. + pub(crate) emit_ast: bool, + + /// True if we should dump our internal IR for debugging purposes. + pub(crate) emit_ir: bool, + + /// Output graphviz dot file. + pub(crate) emit_ir_graphviz: Option, + + /// True if we should emulate C++ namespaces with Rust modules in the + /// generated bindings. + pub(crate) 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. + pub(crate) enable_function_attribute_detection: bool, + + /// False if we should avoid mangling names with namespaces. + pub(crate) enable_name_namespacing: bool, + + /// False if we should avoid generating nested struct names. + pub(crate) enable_nested_struct_naming: bool, + + /// False if we should avoid embedding version identifiers into source code. + pub(crate) enable_header_comment: bool, + + /// True if we should generate layout tests for generated structures. + pub(crate) layout_tests: bool, + + /// True if we should implement the Debug trait for C/C++ structures and types + /// that do not support automatically deriving Debug. + pub(crate) impl_debug: bool, + + /// True if we should implement the PartialEq trait for C/C++ structures and types + /// that do not support automatically deriving PartialEq. + pub(crate) impl_partialeq: bool, + + /// True if we should derive Copy trait implementations for C/C++ structures + /// and types. + pub(crate) derive_copy: bool, + + /// True if we should derive Debug trait implementations for C/C++ structures + /// and types. + pub(crate) derive_debug: bool, + + /// True if we should derive Default trait implementations for C/C++ structures + /// and types. + pub(crate) derive_default: bool, + + /// True if we should derive Hash trait implementations for C/C++ structures + /// and types. + pub(crate) derive_hash: bool, + + /// True if we should derive PartialOrd trait implementations for C/C++ structures + /// and types. + pub(crate) derive_partialord: bool, + + /// True if we should derive Ord trait implementations for C/C++ structures + /// and types. + pub(crate) derive_ord: bool, + + /// True if we should derive PartialEq trait implementations for C/C++ structures + /// and types. + pub(crate) derive_partialeq: bool, + + /// True if we should derive Eq trait implementations for C/C++ structures + /// and types. + pub(crate) derive_eq: bool, + + /// True if we should avoid using libstd to use libcore instead. + pub(crate) use_core: bool, + + /// An optional prefix for the "raw" types, like `c_int`, `c_void`... + pub(crate) ctypes_prefix: Option, + + /// The prefix for the anon fields. + pub(crate) anon_fields_prefix: String, + + /// Whether to time the bindgen phases. + pub(crate) time_phases: bool, + + /// Whether we should convert float types to f32/f64 types. + pub(crate) convert_floats: bool, + + /// The set of raw lines to prepend to the top-level module of generated + /// Rust code. + pub(crate) raw_lines: Vec, + + /// The set of raw lines to prepend to each of the modules. + /// + /// This only makes sense if the `enable_cxx_namespaces` option is set. + pub(crate) module_lines: HashMap>, + + /// The set of arguments to pass straight through to Clang. + clang_args: Vec, + + /// The input header files. + input_headers: Vec, + + /// Tuples of unsaved file contents of the form (name, contents). + input_header_contents: Vec<(String, String)>, + + /// Which kind of items should we generate? By default, we'll generate all + /// of them. + pub(crate) codegen_config: CodegenConfig, + + /// Whether to treat inline namespaces conservatively. + /// + /// See the builder method description for more details. + pub(crate) conservative_inline_namespaces: bool, + + /// Whether to keep documentation comments in the generated output. See the + /// documentation for more details. Defaults to true. + pub(crate) generate_comments: bool, + + /// Whether to generate inline functions. Defaults to false. + pub(crate) generate_inline_functions: bool, + + /// Whether to allowlist types recursively. Defaults to true. + pub(crate) allowlist_recursively: bool, + + /// Instead of emitting 'use objc;' to files generated from objective c files, + /// generate '#[macro_use] extern crate objc;' + pub(crate) objc_extern_crate: bool, + + /// Instead of emitting 'use block;' to files generated from objective c files, + /// generate '#[macro_use] extern crate block;' + pub(crate) generate_block: bool, + + /// Instead of emitting 'use block;' to files generated from objective c files, + /// generate '#[macro_use] extern crate block;' + pub(crate) 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 + pub(crate) enable_mangling: bool, + + /// Whether to detect include paths using clang_sys. + pub(crate) detect_include_paths: bool, + + /// Whether to try to fit macro constants into types smaller than u32/i32 + pub(crate) fit_macro_constants: bool, + + /// Whether to prepend the enum name to constant or newtype variants. + pub(crate) 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. + pub(crate) size_t_is_usize: bool, + + /// Whether rustfmt should format the generated bindings. + pub(crate) rustfmt_bindings: bool, + + /// The absolute path to the rustfmt configuration file, if None, the standard rustfmt + /// options are used. + pub(crate) rustfmt_configuration_file: Option, + + /// The set of types that we should not derive `PartialEq` for. + no_partialeq_types: RegexItems, + + /// The set of types that we should not derive `Copy` for. + no_copy_types: RegexItems, + + /// The set of types that we should not derive `Debug` for. + no_debug_types: RegexItems, + + /// The set of types that we should not derive/impl `Default` for. + no_default_types: RegexItems, + + /// The set of types that we should not derive `Hash` for. + no_hash_types: RegexItems, + + /// The set of types that we should be annotated with `#[must_use]`. + must_use_types: RegexItems, + + /// Decide if C arrays should be regular pointers in rust or array pointers + pub(crate) array_pointers_in_arguments: bool, + + /// Wasm import module name. + pub(crate) wasm_import_module_name: Option, + + /// The name of the dynamic library (if we are generating bindings for a shared library). If + /// this is None, no dynamic bindings are created. + pub(crate) dynamic_library_name: Option, + + /// 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. + pub(crate) dynamic_link_require_all: bool, + + /// Only make generated bindings `pub` if the items would be publically accessible + /// by C++. + pub(crate) respect_cxx_access_specs: bool, + + /// Always translate enum integer types to native Rust integer types. + pub(crate) translate_enum_integer_types: bool, + + /// Generate types with C style naming. + pub(crate) c_naming: bool, + + /// Always output explicit padding fields + pub(crate) force_explicit_padding: bool, + + /// Emit vtable functions. + pub(crate) vtable_generation: bool, + + /// Sort the code generation + pub(crate) sort_semantically: bool, + + /// Deduplicate `extern` blocks. + pub(crate) merge_extern_blocks: bool, +} + +impl Default for BindgenInputs { + fn default() -> Self { + let rust_target = RustTarget::default(); + + Self { + rust_target, + rust_features: rust_target.into(), + blocklisted_types: Default::default(), + blocklisted_functions: Default::default(), + blocklisted_items: Default::default(), + blocklisted_files: Default::default(), + opaque_types: Default::default(), + rustfmt_path: Default::default(), + depfile: Default::default(), + allowlisted_types: Default::default(), + allowlisted_functions: Default::default(), + allowlisted_vars: Default::default(), + allowlisted_files: Default::default(), + default_enum_style: Default::default(), + bitfield_enums: Default::default(), + newtype_enums: Default::default(), + newtype_global_enums: Default::default(), + rustified_enums: Default::default(), + rustified_non_exhaustive_enums: Default::default(), + constified_enums: Default::default(), + constified_enum_modules: Default::default(), + default_macro_constant_type: Default::default(), + default_alias_style: Default::default(), + type_alias: Default::default(), + new_type_alias: Default::default(), + new_type_alias_deref: Default::default(), + default_non_copy_union_style: Default::default(), + bindgen_wrapper_union: Default::default(), + manually_drop_union: Default::default(), + builtins: Default::default(), + emit_ast: Default::default(), + emit_ir: Default::default(), + emit_ir_graphviz: Default::default(), + layout_tests: true, + impl_debug: Default::default(), + impl_partialeq: Default::default(), + derive_copy: true, + derive_debug: true, + derive_default: Default::default(), + derive_hash: Default::default(), + derive_partialord: Default::default(), + derive_ord: Default::default(), + derive_partialeq: Default::default(), + derive_eq: Default::default(), + enable_cxx_namespaces: Default::default(), + enable_function_attribute_detection: Default::default(), + enable_name_namespacing: true, + enable_nested_struct_naming: true, + enable_header_comment: true, + use_core: Default::default(), + ctypes_prefix: Default::default(), + anon_fields_prefix: DEFAULT_ANON_FIELDS_PREFIX.into(), + convert_floats: true, + raw_lines: Default::default(), + module_lines: Default::default(), + clang_args: Default::default(), + input_headers: Default::default(), + input_header_contents: Default::default(), + codegen_config: CodegenConfig::all(), + conservative_inline_namespaces: Default::default(), + generate_comments: true, + generate_inline_functions: Default::default(), + allowlist_recursively: true, + generate_block: Default::default(), + objc_extern_crate: Default::default(), + block_extern_crate: Default::default(), + enable_mangling: true, + detect_include_paths: true, + fit_macro_constants: Default::default(), + prepend_enum_name: true, + time_phases: Default::default(), + record_matches: true, + rustfmt_bindings: true, + size_t_is_usize: Default::default(), + rustfmt_configuration_file: Default::default(), + no_partialeq_types: Default::default(), + no_copy_types: Default::default(), + no_debug_types: Default::default(), + no_default_types: Default::default(), + no_hash_types: Default::default(), + must_use_types: Default::default(), + array_pointers_in_arguments: Default::default(), + wasm_import_module_name: Default::default(), + dynamic_library_name: Default::default(), + dynamic_link_require_all: Default::default(), + respect_cxx_access_specs: Default::default(), + translate_enum_integer_types: Default::default(), + c_naming: Default::default(), + force_explicit_padding: Default::default(), + vtable_generation: Default::default(), + sort_semantically: Default::default(), + merge_extern_blocks: Default::default(), + } + } +} + +impl BindgenInputs { + /// Whether any of the enabled options requires `syn`. + pub fn require_syn(&self) -> bool { + self.sort_semantically || self.merge_extern_blocks + } + + /// 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 + } +} + +impl BindgenState { + fn build( + options: &BindgenInputs, + parse_callbacks: Option>, + ) -> Self { + let mut clang_args = options.clang_args.clone(); + + // Add any extra arguments from the environment to the clang command line. + clang_args.extend(get_extra_clang_args()); + + // Transform input headers to arguments on the clang command line. + let (input_header, extra_input_headers) = + if let Some((input_header, extra_input_headers)) = + options.input_headers.split_last() + { + (Some(input_header.clone()), extra_input_headers.to_vec()) + } else { + Default::default() + }; + + clang_args.extend( + extra_input_headers + .iter() + .flat_map(|header| ["-include".into(), header.to_string()]), + ); + + let input_unsaved_files = options + .input_header_contents + .iter() + .map(|(name, contents)| clang::UnsavedFile::new(&name, &contents)) + .collect(); + + Self { + allowlisted_vars: RegexSet::new( + options.allowlisted_vars.clone(), + options.record_matches, + ), + allowlisted_types: RegexSet::new( + options.allowlisted_types.clone(), + options.record_matches, + ), + allowlisted_functions: RegexSet::new( + options.allowlisted_functions.clone(), + options.record_matches, + ), + allowlisted_files: RegexSet::new( + options.allowlisted_files.clone(), + options.record_matches, + ), + blocklisted_types: RegexSet::new( + options.blocklisted_types.clone(), + options.record_matches, + ), + blocklisted_functions: RegexSet::new( + options.blocklisted_functions.clone(), + options.record_matches, + ), + blocklisted_items: RegexSet::new( + options.blocklisted_items.clone(), + options.record_matches, + ), + blocklisted_files: RegexSet::new( + options.blocklisted_files.clone(), + options.record_matches, + ), + opaque_types: RegexSet::new( + options.opaque_types.clone(), + options.record_matches, + ), + bitfield_enums: RegexSet::new( + options.bitfield_enums.clone(), + options.record_matches, + ), + constified_enums: RegexSet::new( + options.constified_enums.clone(), + options.record_matches, + ), + constified_enum_modules: RegexSet::new( + options.constified_enum_modules.clone(), + options.record_matches, + ), + newtype_enums: RegexSet::new( + options.newtype_enums.clone(), + options.record_matches, + ), + newtype_global_enums: RegexSet::new( + options.newtype_global_enums.clone(), + options.record_matches, + ), + rustified_enums: RegexSet::new( + options.rustified_enums.clone(), + options.record_matches, + ), + rustified_non_exhaustive_enums: RegexSet::new( + options.rustified_non_exhaustive_enums.clone(), + options.record_matches, + ), + type_alias: RegexSet::new( + options.type_alias.clone(), + options.record_matches, + ), + new_type_alias: RegexSet::new( + options.new_type_alias.clone(), + options.record_matches, + ), + new_type_alias_deref: RegexSet::new( + options.new_type_alias_deref.clone(), + options.record_matches, + ), + bindgen_wrapper_union: RegexSet::new( + options.bindgen_wrapper_union.clone(), + options.record_matches, + ), + manually_drop_union: RegexSet::new( + options.manually_drop_union.clone(), + options.record_matches, + ), + no_partialeq_types: RegexSet::new( + options.no_partialeq_types.clone(), + options.record_matches, + ), + no_copy_types: RegexSet::new( + options.no_copy_types.clone(), + options.record_matches, + ), + no_debug_types: RegexSet::new( + options.no_debug_types.clone(), + options.record_matches, + ), + no_default_types: RegexSet::new( + options.no_default_types.clone(), + options.record_matches, + ), + no_hash_types: RegexSet::new( + options.no_hash_types.clone(), + options.record_matches, + ), + must_use_types: RegexSet::new( + options.must_use_types.clone(), + options.record_matches, + ), + clang_args, + input_header, + extra_input_headers, + input_unsaved_files, + parse_callbacks, + } + } +} diff --git a/src/codegen/helpers.rs b/src/codegen/helpers.rs index 5bf36acb42..6cac962501 100644 --- a/src/codegen/helpers.rs +++ b/src/codegen/helpers.rs @@ -116,7 +116,7 @@ pub fn integer_type( pub fn bitfield_unit(ctx: &BindgenContext, layout: Layout) -> TokenStream { let mut tokens = quote! {}; - if ctx.options().enable_cxx_namespaces { + if ctx.inputs().enable_cxx_namespaces { tokens.append_all(quote! { root:: }); } @@ -138,7 +138,7 @@ pub mod ast_ty { pub fn c_void(ctx: &BindgenContext) -> TokenStream { // ctypes_prefix takes precedence - match ctx.options().ctypes_prefix { + match ctx.inputs().ctypes_prefix { Some(ref prefix) => { let prefix = TokenStream::from_str(prefix.as_str()).unwrap(); quote! { @@ -146,8 +146,8 @@ pub mod ast_ty { } } None => { - if ctx.options().use_core && - ctx.options().rust_features.core_ffi_c_void + if ctx.inputs().use_core && + ctx.inputs().rust_features().core_ffi_c_void { quote! { ::core::ffi::c_void } } else { @@ -159,7 +159,7 @@ pub mod ast_ty { pub fn raw_type(ctx: &BindgenContext, name: &str) -> TokenStream { let ident = ctx.rust_ident_raw(name); - match ctx.options().ctypes_prefix { + match ctx.inputs().ctypes_prefix { Some(ref prefix) => { let prefix = TokenStream::from_str(prefix.as_str()).unwrap(); quote! { @@ -167,8 +167,8 @@ pub mod ast_ty { } } None => { - if ctx.options().use_core && - ctx.options().rust_features().core_ffi_c + if ctx.inputs().use_core && + ctx.inputs().rust_features().core_ffi_c { quote! { ::core::ffi::#ident @@ -191,7 +191,7 @@ pub mod ast_ty { // often? // // Also, maybe this one shouldn't be the default? - match (fk, ctx.options().convert_floats) { + match (fk, ctx.inputs().convert_floats) { (FloatKind::Float, true) => quote! { f32 }, (FloatKind::Double, true) => quote! { f64 }, (FloatKind::Float, false) => raw_type(ctx, "c_float"), @@ -218,7 +218,7 @@ pub mod ast_ty { } } (FloatKind::Float128, _) => { - if ctx.options().rust_features.i128_and_u128 { + if ctx.inputs().rust_features().i128_and_u128 { quote! { u128 } } else { quote! { [u64; 2] } diff --git a/src/codegen/impl_debug.rs b/src/codegen/impl_debug.rs index 0e2cd33ad5..f4f720e41d 100644 --- a/src/codegen/impl_debug.rs +++ b/src/codegen/impl_debug.rs @@ -181,11 +181,11 @@ impl<'a> ImplDebug<'a> for Item { vec![], )) } else if len < RUST_DERIVE_IN_ARRAY_LIMIT || - ctx.options().rust_features().larger_arrays + ctx.inputs().rust_features().larger_arrays { // The simple case debug_print(name, quote! { #name_ident }) - } else if ctx.options().use_core { + } else if ctx.inputs().use_core { // There is no String in core; reducing field visibility to avoid breaking // no_std setups. Some((format!("{}: [...]", name), vec![])) @@ -204,7 +204,7 @@ impl<'a> ImplDebug<'a> for Item { } } TypeKind::Vector(_, len) => { - if ctx.options().use_core { + if ctx.inputs().use_core { // There is no format! in core; reducing field visibility to avoid breaking // no_std setups. Some((format!("{}(...)", name), vec![])) diff --git a/src/codegen/impl_partialeq.rs b/src/codegen/impl_partialeq.rs index 960306ffc6..6ac3a62ef1 100644 --- a/src/codegen/impl_partialeq.rs +++ b/src/codegen/impl_partialeq.rs @@ -18,7 +18,7 @@ pub fn gen_partialeq_impl( &self._bindgen_opaque_blob[..] == &other._bindgen_opaque_blob[..] }); } else if comp_info.kind() == CompKind::Union { - assert!(!ctx.options().rust_features().untagged_union); + assert!(!ctx.inputs().rust_features().untagged_union); tokens.push(quote! { &self.bindgen_union_field[..] == &other.bindgen_union_field[..] }); @@ -114,7 +114,7 @@ fn gen_field( TypeKind::Array(_, len) => { if len <= RUST_DERIVE_IN_ARRAY_LIMIT || - ctx.options().rust_features().larger_arrays + ctx.inputs().rust_features().larger_arrays { quote_equals(name_ident) } else { diff --git a/src/codegen/mod.rs b/src/codegen/mod.rs index 843d5111a1..c2a8429d76 100644 --- a/src/codegen/mod.rs +++ b/src/codegen/mod.rs @@ -15,8 +15,7 @@ use self::dyngen::DynamicItems; use self::helpers::attributes; use self::struct_layout::StructLayoutTracker; -use super::BindgenOptions; - +use crate::builder::BindgenOptions; use crate::ir::analysis::{HasVtable, Sizedness}; use crate::ir::annotations::FieldAccessorKind; use crate::ir::comment; @@ -65,7 +64,7 @@ fn top_level_path( ) -> Vec { let mut path = vec![quote! { self }]; - if ctx.options().enable_cxx_namespaces { + if ctx.inputs().enable_cxx_namespaces { for _ in 0..item.codegen_depth(ctx) { path.push(quote! { super }); } @@ -78,7 +77,7 @@ fn root_import( ctx: &BindgenContext, module: &Item, ) -> proc_macro2::TokenStream { - assert!(ctx.options().enable_cxx_namespaces, "Somebody messed it up"); + assert!(ctx.inputs().enable_cxx_namespaces, "Somebody messed it up"); assert!(module.is_module()); let mut path = top_level_path(ctx, module); @@ -122,7 +121,7 @@ fn derives_of_item( if item.can_derive_copy(ctx) && !item.annotations().disallow_copy() { derivable_traits |= DerivableTraits::COPY; - if ctx.options().rust_features().builtin_clone_impls || + if ctx.inputs().rust_features().builtin_clone_impls || !all_template_params.is_empty() { // FIXME: This requires extra logic if you have a big array in a @@ -546,9 +545,9 @@ impl CodeGenerator for Module { } }; - if !ctx.options().enable_cxx_namespaces || + if !ctx.inputs().enable_cxx_namespaces || (self.is_inline() && - !ctx.options().conservative_inline_namespaces) + !ctx.inputs().conservative_inline_namespaces) { codegen_self(result, &mut false); return; @@ -559,7 +558,7 @@ impl CodeGenerator for Module { result.push(root_import(ctx, item)); let path = item.namespace_aware_canonical_path(ctx).join("::"); - if let Some(raw_lines) = ctx.options().module_lines.get(&path) { + if let Some(raw_lines) = ctx.inputs().module_lines.get(&path) { for raw_line in raw_lines { found_any = true; result.push( @@ -674,8 +673,8 @@ impl CodeGenerator for Var { Ok(string) => { let cstr = helpers::ast_ty::cstr_expr(string); if ctx - .options() - .rust_features + .inputs() + .rust_features() .static_lifetime_elision { result.push(quote! { @@ -778,7 +777,7 @@ impl CodeGenerator for Type { inst.codegen(ctx, result, item) } TypeKind::BlockPointer(inner) => { - if !ctx.options().generate_block { + if !ctx.inputs().generate_block { return; } @@ -890,14 +889,14 @@ impl CodeGenerator for Type { quote! {} }; - let alias_style = if ctx.options().type_alias.matches(&name) { + let alias_style = if ctx.state().type_alias.matches(&name) { AliasVariation::TypeAlias - } else if ctx.options().new_type_alias.matches(&name) { + } else if ctx.state().new_type_alias.matches(&name) { AliasVariation::NewType - } else if ctx.options().new_type_alias_deref.matches(&name) { + } else if ctx.state().new_type_alias_deref.matches(&name) { AliasVariation::NewTypeDeref } else { - ctx.options().default_alias_style + ctx.inputs().default_alias_style }; // We prefer using `pub use` over `pub type` because of: @@ -927,7 +926,7 @@ impl CodeGenerator for Type { }, AliasVariation::NewType | AliasVariation::NewTypeDeref => { assert!( - ctx.options().rust_features().repr_transparent, + ctx.inputs().rust_features().repr_transparent, "repr_transparent feature is required to use {:?}", alias_style ); @@ -1055,7 +1054,7 @@ impl<'a> CodeGenerator for Vtable<'a> { // For now, we will only generate vtables for classes that: // - do not inherit from others (compilers merge VTable from primary parent class). // - do not contain a virtual destructor (requires ordering; platforms generate different vtables). - if ctx.options().vtable_generation && + if ctx.inputs().vtable_generation && self.comp_info.base_members().is_empty() && self.comp_info.destructor().is_none() { @@ -1155,7 +1154,7 @@ impl CodeGenerator for TemplateInstantiation { // instantiation is opaque, then its presumably because we don't // properly understand it (maybe because of specializations), and so we // shouldn't emit layout tests either. - if !ctx.options().layout_tests || self.is_opaque(ctx, item) { + if !ctx.inputs().layout_tests || self.is_opaque(ctx, item) { return; } @@ -1299,7 +1298,7 @@ fn wrap_union_field_if_needed( } } else { result.saw_bindgen_union(); - if ctx.options().enable_cxx_namespaces { + if ctx.inputs().enable_cxx_namespaces { quote! { root::__BindgenUnionField<#ty> } @@ -1348,7 +1347,7 @@ impl<'a> FieldCodegen<'a> for FieldData { let inner = item.to_rust_ty_or_opaque(ctx, &()); - if ctx.options().enable_cxx_namespaces { + if ctx.inputs().enable_cxx_namespaces { quote! { root::__IncompleteArrayField<#inner> } @@ -1362,7 +1361,7 @@ impl<'a> FieldCodegen<'a> for FieldData { }; let mut field = quote! {}; - if ctx.options().generate_comments { + if ctx.inputs().generate_comments { if let Some(raw_comment) = self.comment() { let comment = comment::preprocess(raw_comment, codegen_depth + 1); @@ -1383,7 +1382,7 @@ impl<'a> FieldCodegen<'a> for FieldData { } let is_private = (!self.is_public() && - ctx.options().respect_cxx_access_specs) || + ctx.inputs().respect_cxx_access_specs) || self.annotations() .private_fields() .unwrap_or(fields_should_be_private); @@ -1511,7 +1510,7 @@ fn access_specifier( ctx: &BindgenContext, is_pub: bool, ) -> proc_macro2::TokenStream { - if is_pub || !ctx.options().respect_cxx_access_specs { + if is_pub || !ctx.inputs().respect_cxx_access_specs { quote! { pub } } else { quote! {} @@ -1591,7 +1590,7 @@ impl<'a> FieldCodegen<'a> for BitfieldUnit { } if layout.size > RUST_DERIVE_IN_ARRAY_LIMIT && - !ctx.options().rust_features().larger_arrays + !ctx.inputs().rust_features().larger_arrays { continue; } @@ -1959,7 +1958,7 @@ impl CodeGenerator for CompInfo { packed = true; } else { explicit_align = Some(layout.align); - if !ctx.options().rust_features.repr_align { + if !ctx.inputs().rust_features().repr_align { let ty = helpers::blob( ctx, Layout::new(0, layout.align), @@ -2029,7 +2028,7 @@ impl CodeGenerator for CompInfo { } if packed && !is_opaque { let n = layout.map_or(1, |l| l.align); - assert!(ctx.options().rust_features().repr_packed_n || n == 1); + assert!(ctx.inputs().rust_features().repr_packed_n || n == 1); let packed_repr = if n == 1 { "packed".to_string() } else { @@ -2040,7 +2039,7 @@ impl CodeGenerator for CompInfo { attributes.push(attributes::repr("C")); } - if ctx.options().rust_features().repr_align { + if ctx.inputs().rust_features().repr_align { if let Some(explicit) = explicit_align { // Ensure that the struct has the correct alignment even in // presence of alignas. @@ -2053,14 +2052,14 @@ impl CodeGenerator for CompInfo { let derivable_traits = derives_of_item(item, ctx, packed); if !derivable_traits.contains(DerivableTraits::DEBUG) { - needs_debug_impl = ctx.options().derive_debug && - ctx.options().impl_debug && + needs_debug_impl = ctx.inputs().derive_debug && + ctx.inputs().impl_debug && !ctx.no_debug_by_name(item) && !item.annotations().disallow_debug(); } if !derivable_traits.contains(DerivableTraits::DEFAULT) { - needs_default_impl = ctx.options().derive_default && + needs_default_impl = ctx.inputs().derive_default && !self.is_forward_declaration() && !ctx.no_default_by_name(item) && !item.annotations().disallow_default(); @@ -2075,8 +2074,8 @@ impl CodeGenerator for CompInfo { } if !derivable_traits.contains(DerivableTraits::PARTIAL_EQ) { - needs_partialeq_impl = ctx.options().derive_partialeq && - ctx.options().impl_partialeq && + needs_partialeq_impl = ctx.inputs().derive_partialeq && + ctx.inputs().impl_partialeq && ctx.lookup_can_derive_partialeq_or_partialord(item.id()) == CanDerive::Manually; } @@ -2087,7 +2086,7 @@ impl CodeGenerator for CompInfo { // The custom derives callback may return a list of derive attributes; // add them to the end of the list. let custom_derives; - if let Some(cb) = &ctx.options().parse_callbacks { + if let Some(cb) = &ctx.state().parse_callbacks { custom_derives = cb.add_derives(&canonical_name); // In most cases this will be a no-op, since custom_derives will be empty. derives.extend(custom_derives.iter().map(|s| s.as_str())); @@ -2147,7 +2146,7 @@ impl CodeGenerator for CompInfo { } } - if ctx.options().layout_tests && !self.is_forward_declaration() { + if ctx.inputs().layout_tests && !self.is_forward_declaration() { if let Some(layout) = layout { let fn_name = format!("bindgen_test_layout_{}", canonical_ident); @@ -2164,7 +2163,7 @@ impl CodeGenerator for CompInfo { let check_struct_align = if align > ctx.target_pointer_size() && - !ctx.options().rust_features().repr_align + !ctx.inputs().rust_features().repr_align { None } else { @@ -2246,7 +2245,7 @@ impl CodeGenerator for CompInfo { } let mut method_names = Default::default(); - if ctx.options().codegen_config.methods() { + if ctx.inputs().codegen_config.methods() { for method in self.methods() { assert!(method.kind() != MethodKind::Constructor); method.codegen_method( @@ -2259,7 +2258,7 @@ impl CodeGenerator for CompInfo { } } - if ctx.options().codegen_config.constructors() { + if ctx.inputs().codegen_config.constructors() { for sig in self.constructors() { Method::new( MethodKind::Constructor, @@ -2277,7 +2276,7 @@ impl CodeGenerator for CompInfo { } } - if ctx.options().codegen_config.destructors() { + if ctx.inputs().codegen_config.destructors() { if let Some((kind, destructor)) = self.destructor() { debug_assert!(kind.is_destructor()); Method::new(kind, destructor, false).codegen_method( @@ -2307,7 +2306,7 @@ impl CodeGenerator for CompInfo { if needs_default_impl { let prefix = ctx.trait_prefix(); - let body = if ctx.options().rust_features().maybe_uninit { + let body = if ctx.inputs().rust_features().maybe_uninit { quote! { let mut s = ::#prefix::mem::MaybeUninit::::uninit(); unsafe { @@ -2410,7 +2409,7 @@ impl MethodCodegen for Method { _parent: &CompInfo, ) { assert!({ - let cc = &ctx.options().codegen_config; + let cc = &ctx.inputs().codegen_config; match self.kind() { MethodKind::Constructor => cc.constructors(), MethodKind::Destructor => cc.destructors(), @@ -2450,8 +2449,8 @@ impl MethodCodegen for Method { }; let supported_abi = match signature.abi() { - Abi::ThisCall => ctx.options().rust_features().thiscall_abi, - Abi::Vectorcall => ctx.options().rust_features().vectorcall_abi, + Abi::ThisCall => ctx.inputs().rust_features().thiscall_abi, + Abi::Vectorcall => ctx.inputs().rust_features().vectorcall_abi, _ => true, }; @@ -2510,10 +2509,7 @@ impl MethodCodegen for Method { // variable called `__bindgen_tmp` we're going to create. if self.is_constructor() { let prefix = ctx.trait_prefix(); - let tmp_variable_decl = if ctx - .options() - .rust_features() - .maybe_uninit + let tmp_variable_decl = if ctx.inputs().rust_features().maybe_uninit { exprs[0] = quote! { __bindgen_tmp.as_mut_ptr() @@ -2544,7 +2540,7 @@ impl MethodCodegen for Method { stmts.push(call); if self.is_constructor() { - stmts.push(if ctx.options().rust_features().maybe_uninit { + stmts.push(if ctx.inputs().rust_features().maybe_uninit { quote! { __bindgen_tmp.assume_init() } @@ -2562,7 +2558,7 @@ impl MethodCodegen for Method { let mut attrs = vec![attributes::inline()]; if signature.must_use() && - ctx.options().rust_features().must_use_function + ctx.inputs().rust_features().must_use_function { attrs.push(attributes::must_use()); } @@ -2793,7 +2789,7 @@ impl<'a> EnumBuilder<'a> { }; let mut doc = quote! {}; - if ctx.options().generate_comments { + if ctx.inputs().generate_comments { if let Some(raw_comment) = variant.comment() { let comment = comment::preprocess(raw_comment, self.codegen_depth()); @@ -2828,7 +2824,7 @@ impl<'a> EnumBuilder<'a> { is_global, .. } => { - if ctx.options().rust_features().associated_const && + if ctx.inputs().rust_features().associated_const && is_ty_named && !is_global { @@ -3015,7 +3011,7 @@ impl CodeGenerator for Enum { let repr_translated; let repr = match self.repr().map(|repr| ctx.resolve_type(repr)) { Some(repr) - if !ctx.options().translate_enum_integer_types && + if !ctx.inputs().translate_enum_integer_types && !variation.is_rust() => { repr @@ -3077,18 +3073,17 @@ impl CodeGenerator for Enum { // TODO(emilio): Delegate this to the builders? match variation { EnumVariation::Rust { non_exhaustive } => { - if non_exhaustive && - ctx.options().rust_features().non_exhaustive + if non_exhaustive && ctx.inputs().rust_features().non_exhaustive { attrs.push(attributes::non_exhaustive()); } else if non_exhaustive && - !ctx.options().rust_features().non_exhaustive + !ctx.inputs().rust_features().non_exhaustive { panic!("The rust target you're using doesn't seem to support non_exhaustive enums"); } } EnumVariation::NewType { .. } => { - if ctx.options().rust_features.repr_transparent { + if ctx.inputs().rust_features().repr_transparent { attrs.push(attributes::repr("transparent")); } else { attrs.push(attributes::repr("C")); @@ -3127,7 +3122,7 @@ impl CodeGenerator for Enum { // The custom derives callback may return a list of derive attributes; // add them to the end of the list. let custom_derives; - if let Some(cb) = &ctx.options().parse_callbacks { + if let Some(cb) = &ctx.state().parse_callbacks { custom_derives = cb.add_derives(&name); // In most cases this will be a no-op, since custom_derives will be empty. derives.extend(custom_derives.iter().map(|s| s.as_str())); @@ -3150,7 +3145,7 @@ impl CodeGenerator for Enum { result: &mut CodegenResult<'a>, ) { let constant_name = if enum_.name().is_some() { - if ctx.options().prepend_enum_name { + if ctx.inputs().prepend_enum_name { format!("{}_{}", enum_canonical_name, variant_name) } else { format!("{}", variant_name) @@ -3188,7 +3183,7 @@ impl CodeGenerator for Enum { Some(item.parent_id().canonical_name(ctx)) }; - let constant_mangling_prefix = if ctx.options().prepend_enum_name { + let constant_mangling_prefix = if ctx.inputs().prepend_enum_name { if enum_ty.name().is_none() { parent_canonical_name.as_deref() } else { @@ -3236,7 +3231,7 @@ impl CodeGenerator for Enum { let existing_variant_name = entry.get(); // Use associated constants for named enums. if enum_ty.name().is_some() && - ctx.options().rust_features().associated_const + ctx.inputs().rust_features().associated_const { let enum_canonical_name = &ident; let variant_name = @@ -3725,7 +3720,7 @@ impl TryToRustTy for Type { Ok(proc_macro2::TokenStream::from_str(name).unwrap()) } IntKind::U128 => { - Ok(if ctx.options().rust_features.i128_and_u128 { + Ok(if ctx.inputs().rust_features().i128_and_u128 { quote! { u128 } } else { // Best effort thing, but wrong alignment @@ -3734,7 +3729,7 @@ impl TryToRustTy for Type { }) } IntKind::I128 => { - Ok(if ctx.options().rust_features.i128_and_u128 { + Ok(if ctx.inputs().rust_features().i128_and_u128 { quote! { i128 } } else { quote! { [u64; 2] } @@ -3750,7 +3745,7 @@ impl TryToRustTy for Type { float_kind_rust_type(ctx, fk, self.layout(ctx)); ctx.generated_bindgen_complex(); - Ok(if ctx.options().enable_cxx_namespaces { + Ok(if ctx.inputs().enable_cxx_namespaces { quote! { root::__BindgenComplex<#float_path> } @@ -3791,7 +3786,7 @@ impl TryToRustTy for Type { TypeKind::TemplateAlias(..) | TypeKind::Alias(..) | TypeKind::BlockPointer(..) => { - if self.is_block_pointer() && !ctx.options().generate_block { + if self.is_block_pointer() && !ctx.inputs().generate_block { let void = c_void(ctx); return Ok(void.to_ptr(/* is_const = */ false)); } @@ -3968,13 +3963,11 @@ impl TryToRustTy for FunctionSig { let abi = self.abi(); match abi { - Abi::ThisCall if !ctx.options().rust_features().thiscall_abi => { + Abi::ThisCall if !ctx.inputs().rust_features().thiscall_abi => { warn!("Skipping function with thiscall ABI that isn't supported by the configured Rust target"); Ok(proc_macro2::TokenStream::new()) } - Abi::Vectorcall - if !ctx.options().rust_features().vectorcall_abi => - { + Abi::Vectorcall if !ctx.inputs().rust_features().vectorcall_abi => { warn!("Skipping function with vectorcall ABI that isn't supported by the configured Rust target"); Ok(proc_macro2::TokenStream::new()) } @@ -4017,7 +4010,7 @@ impl CodeGenerator for Function { return None; } FunctionKind::Function => { - ctx.options().dynamic_library_name.is_some() + ctx.inputs().dynamic_library_name.is_some() } _ => false, }; @@ -4057,7 +4050,7 @@ impl CodeGenerator for Function { let mut attributes = vec![]; - if ctx.options().rust_features().must_use_function { + if ctx.inputs().rust_features().must_use_function { let must_use = signature.must_use() || { let ret_ty = signature .return_type() @@ -4077,13 +4070,11 @@ impl CodeGenerator for Function { } let abi = match signature.abi() { - Abi::ThisCall if !ctx.options().rust_features().thiscall_abi => { + Abi::ThisCall if !ctx.inputs().rust_features().thiscall_abi => { warn!("Skipping function with thiscall ABI that isn't supported by the configured Rust target"); return None; } - Abi::Vectorcall - if !ctx.options().rust_features().vectorcall_abi => - { + Abi::Vectorcall if !ctx.inputs().rust_features().vectorcall_abi => { warn!("Skipping function with vectorcall ABI that isn't supported by the configured Rust target"); return None; } @@ -4122,7 +4113,7 @@ impl CodeGenerator for Function { // the #[link(wasm_import_module)] needs to happen before the `extern // "C"` block. It doesn't get picked up properly otherwise let wasm_link_attribute = - ctx.options().wasm_import_module_name.as_ref().map(|name| { + ctx.inputs().wasm_import_module_name.as_ref().map(|name| { quote! { #[link(wasm_import_module = #name)] } }); @@ -4148,7 +4139,7 @@ impl CodeGenerator for Function { ident, abi, signature.is_variadic(), - ctx.options().dynamic_link_require_all, + ctx.inputs().dynamic_link_require_all, args, args_identifiers, ret, @@ -4420,9 +4411,9 @@ pub(crate) fn codegen( let counter = Cell::new(0); let mut result = CodegenResult::new(&counter); - debug!("codegen: {:?}", context.options()); + debug!("codegen: {:?}", context.inputs()); - if context.options().emit_ir { + if context.inputs().emit_ir { let codegen_items = context.codegen_items(); for (id, item) in context.items() { if codegen_items.contains(&id) { @@ -4431,7 +4422,7 @@ pub(crate) fn codegen( } } - if let Some(path) = context.options().emit_ir_graphviz.as_ref() { + if let Some(path) = context.inputs().emit_ir_graphviz.as_ref() { match dot::write_dot_file(context, path) { Ok(()) => info!( "Your dot file was generated successfully into: {}", @@ -4441,7 +4432,7 @@ pub(crate) fn codegen( } } - if let Some(spec) = context.options().depfile.as_ref() { + if let Some(spec) = context.inputs().depfile.as_ref() { match spec.write(context.deps()) { Ok(()) => info!( "Your depfile was generated successfully into: {}", @@ -4457,7 +4448,7 @@ pub(crate) fn codegen( &(), ); - if let Some(ref lib_name) = context.options().dynamic_library_name { + if let Some(ref lib_name) = context.inputs().dynamic_library_name { let lib_ident = context.rust_ident(lib_name); let dynamic_items_tokens = result.dynamic_items().get_tokens(lib_ident); @@ -4484,7 +4475,7 @@ pub mod utils { result: &mut Vec, ) { let bitfield_unit_src = include_str!("./bitfield_unit.rs"); - let bitfield_unit_src = if ctx.options().rust_features().min_const_fn { + let bitfield_unit_src = if ctx.inputs().rust_features().min_const_fn { Cow::Borrowed(bitfield_unit_src) } else { Cow::Owned(bitfield_unit_src.replace("const fn ", "fn ")) @@ -4502,7 +4493,7 @@ pub mod utils { ctx: &BindgenContext, result: &mut Vec, ) { - let use_objc = if ctx.options().objc_extern_crate { + let use_objc = if ctx.inputs().objc_extern_crate { quote! { #[macro_use] extern crate objc; @@ -4527,7 +4518,7 @@ pub mod utils { ctx: &BindgenContext, result: &mut Vec, ) { - let use_block = if ctx.options().block_extern_crate { + let use_block = if ctx.inputs().block_extern_crate { quote! { extern crate block; } @@ -4550,7 +4541,7 @@ pub mod utils { // If the target supports `const fn`, declare eligible functions // as `const fn` else just `fn`. - let const_fn = if ctx.options().rust_features().min_const_fn { + let const_fn = if ctx.inputs().rust_features().min_const_fn { quote! { const fn } } else { quote! { fn } @@ -4659,7 +4650,7 @@ pub mod utils { // If the target supports `const fn`, declare eligible functions // as `const fn` else just `fn`. - let const_fn = if ctx.options().rust_features().min_const_fn { + let const_fn = if ctx.inputs().rust_features().min_const_fn { quote! { const fn } } else { quote! { fn } @@ -4772,12 +4763,12 @@ pub mod utils { "int64_t" => primitive_ty(ctx, "i64"), "uint64_t" => primitive_ty(ctx, "u64"), - "size_t" if ctx.options().size_t_is_usize => { + "size_t" if ctx.inputs().size_t_is_usize => { primitive_ty(ctx, "usize") } "uintptr_t" => primitive_ty(ctx, "usize"), - "ssize_t" if ctx.options().size_t_is_usize => { + "ssize_t" if ctx.inputs().size_t_is_usize => { primitive_ty(ctx, "isize") } "intptr_t" | "ptrdiff_t" => primitive_ty(ctx, "isize"), @@ -4828,12 +4819,12 @@ pub mod utils { // [1]: http://c0x.coding-guidelines.com/6.7.5.3.html let arg_ty = match *arg_ty.canonical_type(ctx).kind() { TypeKind::Array(t, _) => { - let stream = - if ctx.options().array_pointers_in_arguments { - arg_ty.to_rust_ty_or_opaque(ctx, arg_item) - } else { - t.to_rust_ty_or_opaque(ctx, &()) - }; + let stream = if ctx.inputs().array_pointers_in_arguments + { + arg_ty.to_rust_ty_or_opaque(ctx, arg_item) + } else { + t.to_rust_ty_or_opaque(ctx, &()) + }; stream.to_ptr(ctx.resolve_type(t).is_const()) } TypeKind::Pointer(inner) => { diff --git a/src/codegen/struct_layout.rs b/src/codegen/struct_layout.rs index ddac1b0abb..43066f14cc 100644 --- a/src/codegen/struct_layout.rs +++ b/src/codegen/struct_layout.rs @@ -223,7 +223,7 @@ impl<'a> StructLayoutTracker<'a> { let padding_layout = if self.is_packed || is_union { None } else { - let force_padding = self.ctx.options().force_explicit_padding; + let force_padding = self.ctx.inputs().force_explicit_padding; // Otherwise the padding is useless. let need_padding = force_padding || @@ -281,7 +281,7 @@ impl<'a> StructLayoutTracker<'a> { ) -> Option { // Only emit an padding field at the end of a struct if the // user configures explicit padding. - if !self.ctx.options().force_explicit_padding { + if !self.ctx.inputs().force_explicit_padding { return None; } @@ -328,7 +328,7 @@ impl<'a> StructLayoutTracker<'a> { return None; } - let repr_align = self.ctx.options().rust_features().repr_align; + let repr_align = self.ctx.inputs().rust_features().repr_align; // We always pad to get to the correct size if the struct is one of // those we can't align properly. @@ -361,7 +361,7 @@ impl<'a> StructLayoutTracker<'a> { } pub fn requires_explicit_align(&self, layout: Layout) -> bool { - let repr_align = self.ctx.options().rust_features().repr_align; + let repr_align = self.ctx.inputs().rust_features().repr_align; // Always force explicit repr(align) for stuff more than 16-byte aligned // to work-around https://github.com/rust-lang/rust/issues/54341. diff --git a/src/deps.rs b/src/deps.rs index 479c396cbb..cc404fd668 100644 --- a/src/deps.rs +++ b/src/deps.rs @@ -1,7 +1,7 @@ /// Generating build depfiles from parsed bindings. use std::{collections::BTreeSet, path::PathBuf}; -#[derive(Debug)] +#[derive(Debug, Clone)] pub(crate) struct DepfileSpec { pub output_module: String, pub depfile_path: PathBuf, diff --git a/src/ir/analysis/derive.rs b/src/ir/analysis/derive.rs index d888cd558b..55ff400013 100644 --- a/src/ir/analysis/derive.rs +++ b/src/ir/analysis/derive.rs @@ -172,7 +172,7 @@ impl<'ctx> CannotDerive<'ctx> { if item.is_opaque(self.ctx, &()) { if !self.derive_trait.can_derive_union() && ty.is_union() && - self.ctx.options().rust_features().untagged_union + self.ctx.inputs().rust_features().untagged_union { trace!( " cannot derive {} for Rust unions", @@ -322,7 +322,7 @@ impl<'ctx> CannotDerive<'ctx> { if info.kind() == CompKind::Union { if self.derive_trait.can_derive_union() { - if self.ctx.options().rust_features().untagged_union && + if self.ctx.inputs().rust_features().untagged_union && // https://github.com/rust-lang/rust/issues/36640 (!info.self_template_params(self.ctx).is_empty() || !item.all_template_params(self.ctx).is_empty()) @@ -334,7 +334,7 @@ impl<'ctx> CannotDerive<'ctx> { } // fall through to be same as non-union handling } else { - if self.ctx.options().rust_features().untagged_union { + if self.ctx.inputs().rust_features().untagged_union { trace!( " cannot derive {} for Rust unions", self.derive_trait @@ -495,7 +495,7 @@ impl DeriveTrait { } fn can_derive_large_array(&self, ctx: &BindgenContext) -> bool { - if ctx.options().rust_features().larger_arrays { + if ctx.inputs().rust_features().larger_arrays { !matches!(self, DeriveTrait::Default) } else { matches!(self, DeriveTrait::Copy) diff --git a/src/ir/comp.rs b/src/ir/comp.rs index f44c5d6725..96e29f9a1d 100644 --- a/src/ir/comp.rs +++ b/src/ir/comp.rs @@ -818,7 +818,7 @@ impl CompFields { anon_field_counter += 1; *name = Some(format!( "{}{}", - ctx.options().anon_fields_prefix, + ctx.inputs().anon_fields_prefix, anon_field_counter )); } @@ -1696,7 +1696,7 @@ impl CompInfo { return (false, false); } - if !ctx.options().rust_features().untagged_union { + if !ctx.inputs().rust_features().untagged_union { return (false, false); } @@ -1704,12 +1704,12 @@ impl CompInfo { return (false, false); } - let union_style = if ctx.options().bindgen_wrapper_union.matches(name) { + let union_style = if ctx.state().bindgen_wrapper_union.matches(name) { NonCopyUnionStyle::BindgenWrapper - } else if ctx.options().manually_drop_union.matches(name) { + } else if ctx.state().manually_drop_union.matches(name) { NonCopyUnionStyle::ManuallyDrop } else { - ctx.options().default_non_copy_union_style + ctx.inputs().default_non_copy_union_style }; let all_can_copy = self.fields().iter().all(|f| match *f { @@ -1818,7 +1818,7 @@ impl IsOpaque for CompInfo { return true; } - if !ctx.options().rust_features().repr_packed_n { + if !ctx.inputs().rust_features().repr_packed_n { // If we don't have `#[repr(packed(N)]`, the best we can // do is make this struct opaque. // diff --git a/src/ir/context.rs b/src/ir/context.rs index 7837e59491..3c4bec7599 100644 --- a/src/ir/context.rs +++ b/src/ir/context.rs @@ -19,10 +19,11 @@ use super::module::{Module, ModuleKind}; use super::template::{TemplateInstantiation, TemplateParameters}; use super::traversal::{self, Edge, ItemTraversal}; use super::ty::{FloatKind, Type, TypeKind}; +use crate::builder::BindgenOptions; use crate::callbacks::ParseCallbacks; use crate::clang::{self, Cursor}; use crate::parse::ClangItemParser; -use crate::BindgenOptions; +use crate::{BindgenInputs, BindgenState}; use crate::{Entry, HashMap, HashSet}; use cexpr; use clang_sys; @@ -214,7 +215,7 @@ where T: Copy + Into, { fn can_derive_debug(&self, ctx: &BindgenContext) -> bool { - ctx.options().derive_debug && ctx.lookup_can_derive_debug(*self) + ctx.inputs().derive_debug && ctx.lookup_can_derive_debug(*self) } } @@ -223,7 +224,7 @@ where T: Copy + Into, { fn can_derive_default(&self, ctx: &BindgenContext) -> bool { - ctx.options().derive_default && ctx.lookup_can_derive_default(*self) + ctx.inputs().derive_default && ctx.lookup_can_derive_default(*self) } } @@ -232,7 +233,7 @@ where T: Copy + Into, { fn can_derive_copy(&self, ctx: &BindgenContext) -> bool { - ctx.options().derive_copy && ctx.lookup_can_derive_copy(*self) + ctx.inputs().derive_copy && ctx.lookup_can_derive_copy(*self) } } @@ -241,7 +242,7 @@ where T: Copy + Into, { fn can_derive_hash(&self, ctx: &BindgenContext) -> bool { - ctx.options().derive_hash && ctx.lookup_can_derive_hash(*self) + ctx.inputs().derive_hash && ctx.lookup_can_derive_hash(*self) } } @@ -250,7 +251,7 @@ where T: Copy + Into, { fn can_derive_partialord(&self, ctx: &BindgenContext) -> bool { - ctx.options().derive_partialord && + ctx.inputs().derive_partialord && ctx.lookup_can_derive_partialeq_or_partialord(*self) == CanDerive::Yes } @@ -261,7 +262,7 @@ where T: Copy + Into, { fn can_derive_partialeq(&self, ctx: &BindgenContext) -> bool { - ctx.options().derive_partialeq && + ctx.inputs().derive_partialeq && ctx.lookup_can_derive_partialeq_or_partialord(*self) == CanDerive::Yes } @@ -272,7 +273,7 @@ where T: Copy + Into, { fn can_derive_eq(&self, ctx: &BindgenContext) -> bool { - ctx.options().derive_eq && + ctx.inputs().derive_eq && ctx.lookup_can_derive_partialeq_or_partialord(*self) == CanDerive::Yes && !ctx.lookup_has_float(*self) @@ -284,7 +285,7 @@ where T: Copy + Into, { fn can_derive_ord(&self, ctx: &BindgenContext) -> bool { - ctx.options().derive_ord && + ctx.inputs().derive_ord && ctx.lookup_can_derive_partialeq_or_partialord(*self) == CanDerive::Yes && !ctx.lookup_has_float(*self) @@ -506,6 +507,8 @@ impl<'ctx> AllowlistedItemsTraversal<'ctx> { impl BindgenContext { /// Construct the context for the given `options`. pub(crate) fn new(options: BindgenOptions) -> Self { + let state = options.state(); + // TODO(emilio): Use the CXTargetInfo here when available. // // see: https://reviews.llvm.org/D32389 @@ -515,14 +518,14 @@ impl BindgenContext { clang_sys::CXTranslationUnit_DetailedPreprocessingRecord; let translation_unit = { - let _t = - Timer::new("translation_unit").with_output(options.time_phases); + let _t = Timer::new("translation_unit") + .with_output(options.inputs().time_phases); clang::TranslationUnit::parse( &index, "", - &options.clang_args, - &options.input_unsaved_files, + &state.clang_args, + &state.input_unsaved_files, parse_options, ).expect("libclang error; possible causes include: - Invalid flag syntax @@ -539,10 +542,10 @@ If you encounter an error missing from this list, please file an issue or a PR!" // depfiles need to include the explicitly listed headers too let mut deps = BTreeSet::default(); - if let Some(filename) = &options.input_header { + if let Some(filename) = &state.input_header { deps.insert(filename.clone()); } - deps.extend(options.extra_input_headers.iter().cloned()); + deps.extend(state.extra_input_headers.iter().cloned()); BindgenContext { items: vec![Some(root_module)], @@ -590,7 +593,7 @@ If you encounter an error missing from this list, please file an issue or a PR!" /// the timer will print to stderr when it is dropped, otherwise it will do /// nothing. pub fn timer<'a>(&self, name: &'a str) -> Timer<'a> { - Timer::new(name).with_output(self.options.time_phases) + Timer::new(name).with_output(self.inputs().time_phases) } /// Returns the pointer width to use for the target for the current @@ -622,7 +625,7 @@ If you encounter an error missing from this list, please file an issue or a PR!" /// Get the user-provided callbacks by reference, if any. pub fn parse_callbacks(&self) -> Option<&dyn ParseCallbacks> { - self.options().parse_callbacks.as_deref() + self.state().parse_callbacks.as_deref() } /// Add another path to the set of included files. @@ -1309,7 +1312,7 @@ If you encounter an error missing from this list, please file an issue or a PR!" fn find_used_template_parameters(&mut self) { let _t = self.timer("find_used_template_parameters"); - if self.options.allowlist_recursively { + if self.inputs().allowlist_recursively { let used_params = analyze::(self); self.used_template_parameters = Some(used_params); } else { @@ -2077,12 +2080,16 @@ If you encounter an error missing from this list, please file an issue or a PR!" self.in_codegen_phase(), "You're not supposed to call this yet" ); - self.options.opaque_types.matches(&path[1..].join("::")) + self.state().opaque_types.matches(&path[1..].join("::")) } /// Get the options used to configure this bindgen context. - pub(crate) fn options(&self) -> &BindgenOptions { - &self.options + pub(crate) fn inputs(&self) -> &BindgenInputs { + self.options.inputs() + } + + pub(crate) fn state(&self) -> &BindgenState { + self.options.state() } /// Tokenizes a namespace cursor in order to get the name and kind of the @@ -2242,7 +2249,7 @@ If you encounter an error missing from this list, please file an issue or a PR!" .or_insert_with(|| { item.expect_type() .name() - .and_then(|name| match self.options.parse_callbacks { + .and_then(|name| match self.state().parse_callbacks { Some(ref cb) => cb.blocklisted_type_implements_trait( name, derive_trait, @@ -2255,10 +2262,10 @@ If you encounter an error missing from this list, please file an issue or a PR!" "int32_t" | "uint32_t" | "int64_t" | "uint64_t" | "uintptr_t" | "intptr_t" | "ptrdiff_t" => Some(CanDerive::Yes), - "size_t" if self.options.size_t_is_usize => { + "size_t" if self.inputs().size_t_is_usize => { Some(CanDerive::Yes) } - "ssize_t" if self.options.size_t_is_usize => { + "ssize_t" if self.inputs().size_t_is_usize => { Some(CanDerive::Yes) } _ => Some(CanDerive::No), @@ -2290,10 +2297,10 @@ If you encounter an error missing from this list, please file an issue or a PR!" .filter(|&(_, item)| { // If nothing is explicitly allowlisted, then everything is fair // game. - if self.options().allowlisted_types.is_empty() && - self.options().allowlisted_functions.is_empty() && - self.options().allowlisted_vars.is_empty() && - self.options().allowlisted_files.is_empty() + if self.state().allowlisted_types.is_empty() && + self.state().allowlisted_functions.is_empty() && + self.state().allowlisted_vars.is_empty() && + self.state().allowlisted_files.is_empty() { return true; } @@ -2306,12 +2313,12 @@ If you encounter an error missing from this list, please file an issue or a PR!" // Items with a source location in an explicitly allowlisted file // are always included. - if !self.options().allowlisted_files.is_empty() { + if !self.state().allowlisted_files.is_empty() { if let Some(location) = item.location() { let (file, _, _, _) = location.location(); if let Some(filename) = file.name() { if self - .options() + .state() .allowlisted_files .matches(&filename) { @@ -2326,20 +2333,20 @@ If you encounter an error missing from this list, please file an issue or a PR!" match *item.kind() { ItemKind::Module(..) => true, ItemKind::Function(_) => { - self.options().allowlisted_functions.matches(&name) + self.state().allowlisted_functions.matches(&name) } ItemKind::Var(_) => { - self.options().allowlisted_vars.matches(&name) + self.state().allowlisted_vars.matches(&name) } ItemKind::Type(ref ty) => { - if self.options().allowlisted_types.matches(&name) { + if self.state().allowlisted_types.matches(&name) { return true; } // Auto-allowlist types that don't need code // generation if not allowlisting recursively, to // make the #[derive] analysis not be lame. - if !self.options().allowlist_recursively { + if !self.inputs().allowlist_recursively { match *ty.kind() { TypeKind::Void | TypeKind::NullPtr | @@ -2385,7 +2392,7 @@ If you encounter an error missing from this list, please file an issue or a PR!" ); let name = prefix_path[1..].join("::"); prefix_path.pop().unwrap(); - self.options().allowlisted_vars.matches(&name) + self.state().allowlisted_vars.matches(&name) }) } } @@ -2400,16 +2407,16 @@ If you encounter an error missing from this list, please file an issue or a PR!" roots }; - let allowlisted_items_predicate = - if self.options().allowlist_recursively { - traversal::all_edges - } else { - // Only follow InnerType edges from the allowlisted roots. - // Such inner types (e.g. anonymous structs/unions) are - // always emitted by codegen, and they need to be allowlisted - // to make sure they are processed by e.g. the derive analysis. - traversal::only_inner_type_edges - }; + let allowlisted_items_predicate = if self.inputs().allowlist_recursively + { + traversal::all_edges + } else { + // Only follow InnerType edges from the allowlisted roots. + // Such inner types (e.g. anonymous structs/unions) are + // always emitted by codegen, and they need to be allowlisted + // to make sure they are processed by e.g. the derive analysis. + traversal::only_inner_type_edges + }; let allowlisted = AllowlistedItemsTraversal::new( self, @@ -2418,7 +2425,7 @@ If you encounter an error missing from this list, please file an issue or a PR!" ) .collect::(); - let codegen_items = if self.options().allowlist_recursively { + let codegen_items = if self.inputs().allowlist_recursively { AllowlistedItemsTraversal::new( self, roots, @@ -2434,16 +2441,16 @@ If you encounter an error missing from this list, please file an issue or a PR!" let mut warnings = Vec::new(); - for item in self.options().allowlisted_functions.unmatched_items() { + for item in self.state().allowlisted_functions.unmatched_items() { warnings .push(format!("unused option: --allowlist-function {}", item)); } - for item in self.options().allowlisted_vars.unmatched_items() { + for item in self.state().allowlisted_vars.unmatched_items() { warnings.push(format!("unused option: --allowlist-var {}", item)); } - for item in self.options().allowlisted_types.unmatched_items() { + for item in self.state().allowlisted_types.unmatched_items() { warnings.push(format!("unused option: --allowlist-type {}", item)); } @@ -2456,7 +2463,7 @@ If you encounter an error missing from this list, please file an issue or a PR!" /// Convenient method for getting the prefix to use for most traits in /// codegen depending on the `use_core` option. pub fn trait_prefix(&self) -> Ident { - if self.options().use_core { + if self.inputs().use_core { self.rust_ident_raw("core") } else { self.rust_ident_raw("std") @@ -2477,7 +2484,7 @@ If you encounter an error missing from this list, please file an issue or a PR!" fn compute_cannot_derive_debug(&mut self) { let _t = self.timer("compute_cannot_derive_debug"); assert!(self.cannot_derive_debug.is_none()); - if self.options.derive_debug { + if self.inputs().derive_debug { self.cannot_derive_debug = Some(as_cannot_derive_set(analyze::(( self, @@ -2504,7 +2511,7 @@ If you encounter an error missing from this list, please file an issue or a PR!" fn compute_cannot_derive_default(&mut self) { let _t = self.timer("compute_cannot_derive_default"); assert!(self.cannot_derive_default.is_none()); - if self.options.derive_default { + if self.inputs().derive_default { self.cannot_derive_default = Some(as_cannot_derive_set(analyze::(( self, @@ -2542,7 +2549,7 @@ If you encounter an error missing from this list, please file an issue or a PR!" fn compute_cannot_derive_hash(&mut self) { let _t = self.timer("compute_cannot_derive_hash"); assert!(self.cannot_derive_hash.is_none()); - if self.options.derive_hash { + if self.inputs().derive_hash { self.cannot_derive_hash = Some(as_cannot_derive_set(analyze::(( self, @@ -2569,9 +2576,9 @@ If you encounter an error missing from this list, please file an issue or a PR!" fn compute_cannot_derive_partialord_partialeq_or_eq(&mut self) { let _t = self.timer("compute_cannot_derive_partialord_partialeq_or_eq"); assert!(self.cannot_derive_partialeq_or_partialord.is_none()); - if self.options.derive_partialord || - self.options.derive_partialeq || - self.options.derive_eq + if self.inputs().derive_partialord || + self.inputs().derive_partialeq || + self.inputs().derive_eq { self.cannot_derive_partialeq_or_partialord = Some(analyze::(( @@ -2647,7 +2654,7 @@ If you encounter an error missing from this list, please file an issue or a PR!" fn compute_has_float(&mut self) { let _t = self.timer("compute_has_float"); assert!(self.has_float.is_none()); - if self.options.derive_eq || self.options.derive_ord { + if self.inputs().derive_eq || self.inputs().derive_ord { self.has_float = Some(analyze::(self)); } } @@ -2667,37 +2674,37 @@ If you encounter an error missing from this list, please file an issue or a PR!" /// Check if `--no-partialeq` flag is enabled for this item. pub fn no_partialeq_by_name(&self, item: &Item) -> bool { let name = item.path_for_allowlisting(self)[1..].join("::"); - self.options().no_partialeq_types.matches(&name) + self.state().no_partialeq_types.matches(&name) } /// Check if `--no-copy` flag is enabled for this item. pub fn no_copy_by_name(&self, item: &Item) -> bool { let name = item.path_for_allowlisting(self)[1..].join("::"); - self.options().no_copy_types.matches(&name) + self.state().no_copy_types.matches(&name) } /// Check if `--no-debug` flag is enabled for this item. pub fn no_debug_by_name(&self, item: &Item) -> bool { let name = item.path_for_allowlisting(self)[1..].join("::"); - self.options().no_debug_types.matches(&name) + self.state().no_debug_types.matches(&name) } /// Check if `--no-default` flag is enabled for this item. pub fn no_default_by_name(&self, item: &Item) -> bool { let name = item.path_for_allowlisting(self)[1..].join("::"); - self.options().no_default_types.matches(&name) + self.state().no_default_types.matches(&name) } /// Check if `--no-hash` flag is enabled for this item. pub fn no_hash_by_name(&self, item: &Item) -> bool { let name = item.path_for_allowlisting(self)[1..].join("::"); - self.options().no_hash_types.matches(&name) + self.state().no_hash_types.matches(&name) } /// Check if `--must-use-type` flag is enabled for this item. pub fn must_use_type_by_name(&self, item: &Item) -> bool { let name = item.path_for_allowlisting(self)[1..].join("::"); - self.options().must_use_types.matches(&name) + self.state().must_use_types.matches(&name) } } diff --git a/src/ir/enum_ty.rs b/src/ir/enum_ty.rs index 2b039a4fac..5cdd430ab8 100644 --- a/src/ir/enum_ty.rs +++ b/src/ir/enum_ty.rs @@ -178,45 +178,38 @@ impl Enum { // problems with overlapping match patterns. if self.is_matching_enum( ctx, - &ctx.options().constified_enum_modules, + &ctx.state().constified_enum_modules, item, ) { EnumVariation::ModuleConsts - } else if self.is_matching_enum( - ctx, - &ctx.options().bitfield_enums, - item, - ) { + } else if self.is_matching_enum(ctx, &ctx.state().bitfield_enums, item) + { EnumVariation::NewType { is_bitfield: true, is_global: false, } - } else if self.is_matching_enum(ctx, &ctx.options().newtype_enums, item) - { + } else if self.is_matching_enum(ctx, &ctx.state().newtype_enums, item) { EnumVariation::NewType { is_bitfield: false, is_global: false, } } else if self.is_matching_enum( ctx, - &ctx.options().newtype_global_enums, + &ctx.state().newtype_global_enums, item, ) { EnumVariation::NewType { is_bitfield: false, is_global: true, } - } else if self.is_matching_enum( - ctx, - &ctx.options().rustified_enums, - item, - ) { + } else if self.is_matching_enum(ctx, &ctx.state().rustified_enums, item) + { EnumVariation::Rust { non_exhaustive: false, } } else if self.is_matching_enum( ctx, - &ctx.options().rustified_non_exhaustive_enums, + &ctx.state().rustified_non_exhaustive_enums, item, ) { EnumVariation::Rust { @@ -224,12 +217,12 @@ impl Enum { } } else if self.is_matching_enum( ctx, - &ctx.options().constified_enums, + &ctx.state().constified_enums, item, ) { EnumVariation::Consts } else { - ctx.options().default_enum_style + ctx.inputs().default_enum_style } } } diff --git a/src/ir/function.rs b/src/ir/function.rs index 928b5aad37..7b8ddc7989 100644 --- a/src/ir/function.rs +++ b/src/ir/function.rs @@ -257,7 +257,7 @@ pub fn cursor_mangling( ctx: &BindgenContext, cursor: &clang::Cursor, ) -> Option { - if !ctx.options().enable_mangling { + if !ctx.inputs().enable_mangling { return None; } @@ -451,7 +451,7 @@ impl FunctionSig { }; let (must_use, mut is_divergent) = - if ctx.options().enable_function_attribute_detection { + if ctx.inputs().enable_function_attribute_detection { let [must_use, no_return, no_return_cpp] = cursor.has_attrs(&[ Attribute::MUST_USE, Attribute::NO_RETURN, @@ -630,7 +630,7 @@ impl ClangSubItemParser for Function { } if cursor.is_inlined_function() { - if !context.options().generate_inline_functions { + if !context.inputs().generate_inline_functions { return Err(ParseError::Continue); } if cursor.is_deleted_function() { diff --git a/src/ir/item.rs b/src/ir/item.rs index 3b15cd6ed6..7135535bdf 100644 --- a/src/ir/item.rs +++ b/src/ir/item.rs @@ -493,7 +493,7 @@ impl Item { /// /// FIXME(emilio): This may need fixes for the enums within modules stuff. pub fn codegen_depth(&self, ctx: &BindgenContext) -> usize { - if !ctx.options().enable_cxx_namespaces { + if !ctx.inputs().enable_cxx_namespaces { return 0; } @@ -501,7 +501,7 @@ impl Item { .filter(|id| { ctx.resolve_item(*id).as_module().map_or(false, |module| { !module.is_inline() || - ctx.options().conservative_inline_namespaces + ctx.inputs().conservative_inline_namespaces }) }) .count() + @@ -511,7 +511,7 @@ impl Item { /// Get this `Item`'s comment, if it has any, already preprocessed and with /// the right indentation. pub fn comment(&self, ctx: &BindgenContext) -> Option { - if !ctx.options().generate_comments { + if !ctx.inputs().generate_comments { return None; } @@ -580,7 +580,7 @@ impl Item { pub fn is_toplevel(&self, ctx: &BindgenContext) -> bool { // FIXME: Workaround for some types falling behind when parsing weird // stl classes, for example. - if ctx.options().enable_cxx_namespaces && + if ctx.inputs().enable_cxx_namespaces && self.kind().is_module() && self.id() != ctx.root_module() { @@ -596,7 +596,7 @@ impl Item { if parent_item.id() == ctx.root_module() { return true; - } else if ctx.options().enable_cxx_namespaces || + } else if ctx.inputs().enable_cxx_namespaces || !parent_item.kind().is_module() { return false; @@ -646,11 +646,11 @@ impl Item { return true; } - if !ctx.options().blocklisted_files.is_empty() { + if !ctx.state().blocklisted_files.is_empty() { if let Some(location) = &self.location { let (file, _, _, _) = location.location(); if let Some(filename) = file.name() { - if ctx.options().blocklisted_files.matches(&filename) { + if ctx.state().blocklisted_files.matches(&filename) { return true; } } @@ -659,14 +659,14 @@ impl Item { let path = self.path_for_allowlisting(ctx); let name = path[1..].join("::"); - ctx.options().blocklisted_items.matches(&name) || + ctx.state().blocklisted_items.matches(&name) || match self.kind { ItemKind::Type(..) => { - ctx.options().blocklisted_types.matches(&name) || + ctx.state().blocklisted_types.matches(&name) || ctx.is_replaced_type(path, self.id) } ItemKind::Function(..) => { - ctx.options().blocklisted_functions.matches(&name) + ctx.state().blocklisted_functions.matches(&name) } // TODO: Add constant / namespace blocklisting? ItemKind::Var(..) | ItemKind::Module(..) => false, @@ -851,7 +851,7 @@ impl Item { // Short-circuit if the target has an override, and just use that. if let Some(path) = target.annotations.use_instead_of() { - if ctx.options().enable_cxx_namespaces { + if ctx.inputs().enable_cxx_namespaces { return path.last().unwrap().clone(); } return path.join("_"); @@ -876,7 +876,7 @@ impl Item { !opt.within_namespaces || !ctx.resolve_item(*id).is_module() }) .filter(|id| { - if !ctx.options().conservative_inline_namespaces { + if !ctx.inputs().conservative_inline_namespaces { if let ItemKind::Module(ref module) = *ctx.resolve_item(*id).kind() { @@ -887,7 +887,9 @@ impl Item { true }); - let ids: Vec<_> = if ctx.options().disable_nested_struct_naming { + let ids: Vec<_> = if ctx.inputs().enable_nested_struct_naming { + ids_iter.collect() + } else { let mut ids = Vec::new(); // If target is anonymous we need find its first named ancestor. @@ -902,8 +904,6 @@ impl Item { } ids - } else { - ids_iter.collect() }; // Concatenate this item's ancestors' names together. @@ -923,7 +923,7 @@ impl Item { names.push(base_name); } - if ctx.options().c_naming { + if ctx.inputs().c_naming { if let Some(prefix) = self.c_naming_prefix() { names.insert(0, prefix.to_string()); } @@ -1014,7 +1014,7 @@ impl Item { /// Is this item of a kind that is enabled for code generation? pub fn is_enabled_for_codegen(&self, ctx: &BindgenContext) -> bool { - let cc = &ctx.options().codegen_config; + let cc = &ctx.inputs().codegen_config; match *self.kind() { ItemKind::Module(..) => true, ItemKind::Var(_) => cc.vars(), @@ -1065,7 +1065,7 @@ impl Item { item.id() == target.id() || item.as_module().map_or(false, |module| { !module.is_inline() || - ctx.options().conservative_inline_namespaces + ctx.inputs().conservative_inline_namespaces }) }) .map(|item| { @@ -1923,8 +1923,8 @@ impl ItemCanonicalName for Item { ); self.canonical_name .borrow_with(|| { - let in_namespace = ctx.options().enable_cxx_namespaces || - ctx.options().disable_name_namespacing; + let in_namespace = ctx.inputs().enable_cxx_namespaces || + !ctx.inputs().enable_name_namespacing; if in_namespace { self.name(ctx).within_namespaces().get() @@ -1946,11 +1946,11 @@ impl ItemCanonicalPath for Item { // ASSUMPTION: (disable_name_namespacing && cxx_namespaces) // is equivalent to // disable_name_namespacing - if ctx.options().disable_name_namespacing { + if !ctx.inputs().enable_name_namespacing { // Only keep the last item in path let split_idx = path.len() - 1; path = path.split_off(split_idx); - } else if !ctx.options().enable_cxx_namespaces { + } else if !ctx.inputs().enable_cxx_namespaces { // Ignore first item "root" path = vec![path[1..].join("_")]; } diff --git a/src/ir/layout.rs b/src/ir/layout.rs index 6f4503070a..ebabe7e8e5 100644 --- a/src/ir/layout.rs +++ b/src/ir/layout.rs @@ -39,7 +39,7 @@ impl Layout { size: usize, ) -> Option<&'static str> { Some(match size { - 16 if ctx.options().rust_features.i128_and_u128 => "u128", + 16 if ctx.inputs().rust_features().i128_and_u128 => "u128", 8 => "u64", 4 => "u32", 2 => "u16", diff --git a/src/ir/traversal.rs b/src/ir/traversal.rs index f14483f295..776e1b3e57 100644 --- a/src/ir/traversal.rs +++ b/src/ir/traversal.rs @@ -204,7 +204,7 @@ pub fn only_inner_type_edges(_: &BindgenContext, edge: Edge) -> bool { /// are enabled for code generation. This lets us skip considering items for /// which are not reachable from code generation. pub fn codegen_edges(ctx: &BindgenContext, edge: Edge) -> bool { - let cc = &ctx.options().codegen_config; + let cc = &ctx.inputs().codegen_config; match edge.kind { EdgeKind::Generic => { ctx.resolve_item(edge.to).is_enabled_for_codegen(ctx) diff --git a/src/ir/var.rs b/src/ir/var.rs index e44d57afe4..f9fc58d223 100644 --- a/src/ir/var.rs +++ b/src/ir/var.rs @@ -119,12 +119,12 @@ impl DotAttributes for Var { fn default_macro_constant_type(ctx: &BindgenContext, value: i64) -> IntKind { if value < 0 || - ctx.options().default_macro_constant_type == + ctx.inputs().default_macro_constant_type == MacroTypeVariation::Signed { if value < i32::min_value() as i64 || value > i32::max_value() as i64 { IntKind::I64 - } else if !ctx.options().fit_macro_constants || + } else if !ctx.inputs().fit_macro_constants || value < i16::min_value() as i64 || value > i16::max_value() as i64 { @@ -138,7 +138,7 @@ fn default_macro_constant_type(ctx: &BindgenContext, value: i64) -> IntKind { } } else if value > u32::max_value() as i64 { IntKind::U64 - } else if !ctx.options().fit_macro_constants || + } else if !ctx.inputs().fit_macro_constants || value > u16::max_value() as i64 { IntKind::U32 diff --git a/src/lib.rs b/src/lib.rs index 3c89368f11..4b29f4a6ae 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -49,6 +49,7 @@ macro_rules! doc_mod { }; } +mod builder; mod clang; mod codegen; mod deps; @@ -66,10 +67,11 @@ doc_mod!(ir, ir_docs); doc_mod!(parse, parse_docs); doc_mod!(regex_set, regex_set_docs); +use crate::builder::BindgenInputs; +pub use crate::builder::Builder; pub use crate::codegen::{ AliasVariation, EnumVariation, MacroTypeVariation, NonCopyUnionStyle, }; -use crate::features::RustFeatures; pub use crate::features::{ RustTarget, LATEST_STABLE_RUST, RUST_TARGET_STRINGS, }; @@ -79,15 +81,16 @@ use crate::parse::{ClangItemParser, ParseError}; use crate::regex_set::RegexSet; use std::borrow::Cow; -use std::fs::{File, OpenOptions}; +use std::env; +use std::fs::OpenOptions; use std::io::{self, Write}; use std::path::{Path, PathBuf}; use std::process::{Command, Stdio}; -use std::{env, iter}; // Some convenient typedefs for a fast hash map and hash set. type HashMap = ::rustc_hash::FxHashMap; type HashSet = ::rustc_hash::FxHashSet; +use builder::BindgenOptions; use quote::ToTokens; pub(crate) use std::collections::hash_map::Entry; @@ -172,1611 +175,28 @@ impl Default for CodegenConfig { } } -/// 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`. -#[derive(Debug, Default)] -pub struct Builder { - options: BindgenOptions, - input_headers: Vec, - // Tuples of unsaved file contents of the form (name, contents). - input_header_contents: Vec<(String, String)>, -} - -/// Construct a new [`Builder`](./struct.Builder.html). -pub fn builder() -> Builder { - Default::default() -} - -fn get_extra_clang_args() -> Vec { - // 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 { - let mut output_vector: Vec = Vec::new(); - - if let Some(header) = self.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()); - } - } - - 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 = 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("--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()); - } - - // Add clang arguments - - output_vector.push("--".into()); - - if !self.options.clang_args.is_empty() { - output_vector.extend(self.options.clang_args.iter().cloned()); - } - - if self.input_headers.len() > 1 { - // To pass more than one header, we need to pass all but the last - // header via the `-include` clang arg - for header in &self.input_headers[..self.input_headers.len() - 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>(mut self, header: T) -> Builder { - self.input_headers.push(header.into()); - self - } - - /// Add a depfile output which will be written alongside the generated bindings. - pub fn depfile, D: Into>( - 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.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 { - 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>(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 - } - - /// Deprecated alias for allowlist_recursively. - #[deprecated(note = "Use allowlist_recursively instead")] - pub fn whitelist_recursively(self, doit: bool) -> Self { - self.allowlist_recursively(doit) - } - - /// 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 - } - - /// Hide the given type from the generated bindings. Regular expressions are - /// supported. - #[deprecated(note = "Use blocklist_type instead")] - pub fn hide_type>(self, arg: T) -> Builder { - self.blocklist_type(arg) - } - - /// Hide the given type from the generated bindings. Regular expressions are - /// supported. - #[deprecated(note = "Use blocklist_type instead")] - pub fn blacklist_type>(self, arg: T) -> Builder { - self.blocklist_type(arg) - } - - /// Hide the given type from the generated bindings. Regular expressions are - /// supported. - /// - /// To blocklist types prefixed with "mylib" use `"mylib_.*"`. - /// For more complicated expressions check - /// [regex](https://docs.rs/regex/*/regex/) docs - pub fn blocklist_type>(mut self, arg: T) -> Builder { - self.options.blocklisted_types.insert(arg); - self - } - - /// Hide the given function from the generated bindings. Regular expressions - /// are supported. - #[deprecated(note = "Use blocklist_function instead")] - pub fn blacklist_function>(self, arg: T) -> Builder { - self.blocklist_function(arg) - } - - /// Hide the given function from the generated bindings. Regular expressions - /// are supported. - /// - /// To blocklist functions prefixed with "mylib" use `"mylib_.*"`. - /// For more complicated expressions check - /// [regex](https://docs.rs/regex/*/regex/) docs - pub fn blocklist_function>(mut self, arg: T) -> Builder { - self.options.blocklisted_functions.insert(arg); - self - } - - /// Hide the given item from the generated bindings, regardless of - /// whether it's a type, function, module, etc. Regular - /// expressions are supported. - #[deprecated(note = "Use blocklist_item instead")] - pub fn blacklist_item>(mut self, arg: T) -> Builder { - self.options.blocklisted_items.insert(arg); - self - } - - /// 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_.*"`. - /// For more complicated expressions check - /// [regex](https://docs.rs/regex/*/regex/) docs - pub fn blocklist_item>(mut self, arg: T) -> Builder { - self.options.blocklisted_items.insert(arg); - self - } - - /// 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>(mut self, arg: T) -> Builder { - self.options.blocklisted_files.insert(arg); - self - } - - /// Treat the given type as opaque in the generated bindings. Regular - /// expressions are supported. - /// - /// To change types prefixed with "mylib" into opaque, use `"mylib_.*"`. - /// For more complicated expressions check - /// [regex](https://docs.rs/regex/*/regex/) docs - pub fn opaque_type>(mut self, arg: T) -> Builder { - self.options.opaque_types.insert(arg); - self - } - - /// Allowlist the given type so that it (and all types that it transitively - /// refers to) appears in the generated bindings. Regular expressions are - /// supported. - #[deprecated(note = "use allowlist_type instead")] - pub fn whitelisted_type>(self, arg: T) -> Builder { - self.allowlist_type(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. - #[deprecated(note = "use allowlist_type instead")] - pub fn whitelist_type>(self, arg: T) -> Builder { - self.allowlist_type(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_.*"`. - /// For more complicated expressions check - /// [regex](https://docs.rs/regex/*/regex/) docs - pub fn allowlist_type>(mut self, arg: T) -> Builder { - self.options.allowlisted_types.insert(arg); - self - } - - /// Allowlist the given function so that it (and all types that it - /// transitively refers to) appears in the generated bindings. Regular - /// expressions are supported. - /// - /// To allowlist functions prefixed with "mylib" use `"mylib_.*"`. - /// For more complicated expressions check - /// [regex](https://docs.rs/regex/*/regex/) docs - pub fn allowlist_function>(mut self, arg: T) -> Builder { - self.options.allowlisted_functions.insert(arg); - self - } - - /// Allowlist the given function. - /// - /// Deprecated: use allowlist_function instead. - #[deprecated(note = "use allowlist_function instead")] - pub fn whitelist_function>(self, arg: T) -> Builder { - self.allowlist_function(arg) - } - - /// Allowlist the given function. - /// - /// Deprecated: use allowlist_function instead. - #[deprecated(note = "use allowlist_function instead")] - pub fn whitelisted_function>(self, arg: T) -> Builder { - self.allowlist_function(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_.*"`. - /// For more complicated expressions check - /// [regex](https://docs.rs/regex/*/regex/) docs - pub fn allowlist_var>(mut self, arg: T) -> Builder { - self.options.allowlisted_vars.insert(arg); - self - } - - /// Allowlist the given file so that its contents appear in the generated bindings. - pub fn allowlist_file>(mut self, arg: T) -> Builder { - self.options.allowlisted_files.insert(arg); - self - } - - /// Deprecated: use allowlist_var instead. - #[deprecated(note = "use allowlist_var instead")] - pub fn whitelist_var>(self, arg: T) -> Builder { - self.allowlist_var(arg) - } - - /// Allowlist the given variable. - /// - /// Deprecated: use allowlist_var instead. - #[deprecated(note = "use allowlist_var instead")] - pub fn whitelisted_var>(self, arg: T) -> Builder { - self.allowlist_var(arg) - } - - /// 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 - } - - /// 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>(mut self, arg: T) -> Builder { - self.options.bitfield_enums.insert(arg); - self - } - - /// 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>(mut self, arg: T) -> Builder { - self.options.newtype_enums.insert(arg); - self - } - - /// 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>(mut self, arg: T) -> Builder { - self.options.newtype_global_enums.insert(arg); - self - } - - /// 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>(mut self, arg: T) -> Builder { - self.options.rustified_enums.insert(arg); - self - } - - /// 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>( - mut self, - arg: T, - ) -> Builder { - self.options.rustified_non_exhaustive_enums.insert(arg); - self - } - - /// 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>(mut self, arg: T) -> Builder { - self.options.constified_enums.insert(arg); - self - } - - /// 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>(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 - } - - /// 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>(mut self, arg: T) -> Builder { - self.options.type_alias.insert(arg); - self - } - - /// 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>(mut self, arg: T) -> Builder { - self.options.new_type_alias.insert(arg); - self - } - - /// 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>(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 - } - - /// 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>(mut self, arg: T) -> Self { - self.options.bindgen_wrapper_union.insert(arg); - self - } - - /// 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>(mut self, arg: T) -> Self { - self.options.manually_drop_union.insert(arg); - self - } - - /// Add a string to prepend to the generated bindings. The string is passed - /// through without any modification. - pub fn raw_line>(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(mut self, mod_: T, line: U) -> Self - where - T: Into, - U: Into, - { - 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(mut self, mod_: T, lines: I) -> Self - where - T: Into, - I: IntoIterator, - I::Item: Into, - { - 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>(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(mut self, iter: I) -> Builder - where - I: IntoIterator, - I::Item: AsRef, - { - 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 - } +/// Construct a new [`Builder`](./struct.Builder.html). +pub fn builder() -> Builder { + Default::default() +} - /// Avoid generating any unstable Rust, such as Rust unions, in the generated bindings. - #[deprecated(note = "please use `rust_target` instead")] - pub fn unstable_rust(self, doit: bool) -> Self { - let rust_target = if doit { - RustTarget::Nightly - } else { - LATEST_STABLE_RUST +fn get_extra_clang_args() -> Vec { + // 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, }; - self.rust_target(rust_target) - } - - /// 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>(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>(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, - ) -> Self { - self.options.parse_callbacks = Some(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) -> 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>(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 { - // 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.input_header = self.input_headers.pop(); - self.options.extra_input_headers = self.input_headers; - self.options.clang_args.extend( - self.options.extra_input_headers.iter().flat_map(|header| { - iter::once("-include".into()) - .chain(iter::once(header.to_string())) - }), - ); - - self.options.input_unsaved_files.extend( - self.input_header_contents - .drain(..) - .map(|(name, contents)| { - clang::UnsavedFile::new(&name, &contents) - }), - ); - - Bindings::generate(self.options) - } - - /// 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.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 &(ref name, ref contents) in &self.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", - )) - } - } - - /// Don't derive `PartialEq` for a given type. Regular - /// expressions are supported. - pub fn no_partialeq>(mut self, arg: T) -> Builder { - self.options.no_partialeq_types.insert(arg.into()); - self - } - - /// Don't derive `Copy` for a given type. Regular - /// expressions are supported. - pub fn no_copy>(mut self, arg: T) -> Self { - self.options.no_copy_types.insert(arg.into()); - self - } - - /// Don't derive `Debug` for a given type. Regular - /// expressions are supported. - pub fn no_debug>(mut self, arg: T) -> Self { - self.options.no_debug_types.insert(arg.into()); - self - } - - /// Don't derive/impl `Default` for a given type. Regular - /// expressions are supported. - pub fn no_default>(mut self, arg: T) -> Self { - self.options.no_default_types.insert(arg.into()); - self - } - - /// Don't derive `Hash` for a given type. Regular - /// expressions are supported. - pub fn no_hash>(mut self, arg: T) -> Builder { - self.options.no_hash_types.insert(arg.into()); - self - } - - /// Add `#[must_use]` for the given type. Regular - /// expressions are supported. - pub fn must_use_type>(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>( - 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>( - 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 + // 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] } /// Configuration options for generated bindings. #[derive(Debug)] -struct BindgenOptions { +struct BindgenState { /// The set of types that have been blocklisted and should not appear /// anywhere in the generated code. blocklisted_types: RegexSet, @@ -1797,12 +217,6 @@ struct BindgenOptions { /// generated code. opaque_types: RegexSet, - /// The explicit rustfmt path. - rustfmt_path: Option, - - /// The path to which we should write a Makefile-syntax depfile (if any). - depfile: Option, - /// The set of types that we should have bindings for in the generated /// code. /// @@ -1820,9 +234,6 @@ struct BindgenOptions { /// 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, @@ -1845,12 +256,6 @@ struct BindgenOptions { /// 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, @@ -1861,10 +266,6 @@ struct BindgenOptions { /// 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, @@ -1873,101 +274,8 @@ struct BindgenOptions { /// `::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, - - /// 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, - - /// 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, - - /// 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>, + /// The set of types that we should not derive `PartialEq` for. + no_partialeq_types: RegexSet, /// The set of arguments to pass straight through to Clang. clang_args: Vec, @@ -1978,87 +286,6 @@ struct BindgenOptions { /// Any additional input header files. extra_input_headers: Vec, - /// Unsaved files for input. - input_unsaved_files: Vec, - - /// A user-provided visitor to allow customizing different kinds of - /// situations. - parse_callbacks: Option>, - - /// 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, - - /// 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, @@ -2074,207 +301,18 @@ struct BindgenOptions { /// 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, - - /// 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, - - /// 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, + /// Unsaved files for input. + input_unsaved_files: Vec, - /// Deduplicate `extern` blocks. - merge_extern_blocks: bool, + /// A user-provided visitor to allow customizing different kinds of + /// situations. + parse_callbacks: Option>, } /// TODO(emilio): This is sort of a lie (see the error message that results from /// removing this), but since we don't share references across panic boundaries /// it's ok. -impl ::std::panic::UnwindSafe for BindgenOptions {} - -impl BindgenOptions { - /// Whether any of the enabled options requires `syn`. - fn require_syn(&self) -> bool { - self.sort_semantically || self.merge_extern_blocks - } - - fn build(&mut self) { - let mut 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 &mut 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 - } -} - -impl Default for BindgenOptions { - fn default() -> BindgenOptions { - let rust_target = RustTarget::default(); - - BindgenOptions { - rust_target, - rust_features: rust_target.into(), - blocklisted_types: Default::default(), - blocklisted_functions: Default::default(), - blocklisted_items: Default::default(), - blocklisted_files: Default::default(), - opaque_types: Default::default(), - rustfmt_path: Default::default(), - depfile: Default::default(), - allowlisted_types: Default::default(), - allowlisted_functions: Default::default(), - allowlisted_vars: Default::default(), - allowlisted_files: Default::default(), - default_enum_style: Default::default(), - bitfield_enums: Default::default(), - newtype_enums: Default::default(), - newtype_global_enums: Default::default(), - rustified_enums: Default::default(), - rustified_non_exhaustive_enums: Default::default(), - constified_enums: Default::default(), - constified_enum_modules: Default::default(), - default_macro_constant_type: Default::default(), - default_alias_style: Default::default(), - type_alias: Default::default(), - new_type_alias: Default::default(), - new_type_alias_deref: Default::default(), - default_non_copy_union_style: Default::default(), - bindgen_wrapper_union: Default::default(), - manually_drop_union: Default::default(), - builtins: false, - emit_ast: false, - emit_ir: false, - emit_ir_graphviz: None, - layout_tests: true, - impl_debug: false, - impl_partialeq: false, - derive_copy: true, - derive_debug: true, - derive_default: false, - derive_hash: false, - derive_partialord: false, - derive_ord: false, - derive_partialeq: false, - derive_eq: false, - enable_cxx_namespaces: false, - enable_function_attribute_detection: false, - disable_name_namespacing: false, - disable_nested_struct_naming: false, - disable_header_comment: false, - use_core: false, - ctypes_prefix: None, - anon_fields_prefix: DEFAULT_ANON_FIELDS_PREFIX.into(), - convert_floats: true, - raw_lines: vec![], - module_lines: HashMap::default(), - clang_args: vec![], - input_header: None, - extra_input_headers: vec![], - input_unsaved_files: vec![], - parse_callbacks: None, - codegen_config: CodegenConfig::all(), - conservative_inline_namespaces: false, - generate_comments: true, - generate_inline_functions: false, - allowlist_recursively: true, - generate_block: false, - objc_extern_crate: false, - block_extern_crate: false, - enable_mangling: true, - detect_include_paths: true, - fit_macro_constants: false, - prepend_enum_name: true, - time_phases: false, - record_matches: true, - rustfmt_bindings: true, - size_t_is_usize: false, - rustfmt_configuration_file: None, - no_partialeq_types: Default::default(), - no_copy_types: Default::default(), - no_debug_types: Default::default(), - no_default_types: Default::default(), - no_hash_types: Default::default(), - must_use_types: Default::default(), - array_pointers_in_arguments: false, - wasm_import_module_name: None, - dynamic_library_name: None, - dynamic_link_require_all: false, - respect_cxx_access_specs: false, - translate_enum_integer_types: false, - c_naming: false, - force_explicit_padding: false, - vtable_generation: false, - sort_semantically: false, - merge_extern_blocks: false, - } - } -} +impl ::std::panic::UnwindSafe for BindgenState {} #[cfg(feature = "runtime")] fn ensure_libclang_is_loaded() { @@ -2394,7 +432,7 @@ impl Bindings { /// Generate bindings for the given options. pub(crate) fn generate( mut options: BindgenOptions, - ) -> Result { + ) -> Result { ensure_libclang_is_loaded(); #[cfg(feature = "runtime")] @@ -2405,10 +443,8 @@ impl Bindings { #[cfg(not(feature = "runtime"))] debug!("Generating bindings, libclang linked"); - options.build(); - let (effective_target, explicit_target) = - find_effective_target(&options.clang_args); + find_effective_target(&options.state().clang_args); let is_host_build = rust_to_clang_target(HOST_TARGET) == effective_target; @@ -2420,20 +456,23 @@ impl Bindings { // check is fine. if !explicit_target && !is_host_build { options + .state_mut() .clang_args .insert(0, format!("--target={}", effective_target)); }; fn detect_include_paths(options: &mut BindgenOptions) { - if !options.detect_include_paths { + if !options.inputs().detect_include_paths { return; } + let state = options.state_mut(); + // 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 + state .clang_args .iter() .filter(|arg| { @@ -2479,8 +518,8 @@ impl Bindings { debug!("Found clang: {:?}", clang); // Whether we are working with C or C++ inputs. - let is_cpp = args_are_cpp(&options.clang_args) || - options.input_header.as_deref().map_or(false, file_is_cpp); + let is_cpp = args_are_cpp(&state.clang_args) || + state.input_header.as_deref().map_or(false, file_is_cpp); let search_paths = if is_cpp { clang.cpp_search_paths @@ -2491,8 +530,8 @@ impl Bindings { 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); + state.clang_args.push("-isystem".to_owned()); + state.clang_args.push(path); } } } @@ -2511,7 +550,9 @@ impl Bindings { true } - if let Some(h) = options.input_header.as_ref() { + let state = options.state_mut(); + + if let Some(h) = state.input_header.as_ref() { let path = Path::new(h); if let Ok(md) = std::fs::metadata(path) { if md.is_dir() { @@ -2522,22 +563,22 @@ impl Bindings { path.into(), )); } - options.clang_args.push(h.clone()) + state.clang_args.push(h.clone()) } else { return Err(BindgenError::NotExist(path.into())); } } - for (idx, f) in options.input_unsaved_files.iter().enumerate() { - if idx != 0 || options.input_header.is_some() { - options.clang_args.push("-include".to_owned()); + for (idx, f) in state.input_unsaved_files.iter().enumerate() { + if idx != 0 || state.input_header.is_some() { + state.clang_args.push("-include".to_owned()); } - options.clang_args.push(f.name.to_str().unwrap().to_owned()) + state.clang_args.push(f.name.to_str().unwrap().to_owned()) } debug!("Fixed-up options: {:?}", options); - let time_phases = options.time_phases; + let time_phases = options.inputs().time_phases; let mut context = BindgenContext::new(options); if is_host_build { @@ -2557,7 +598,7 @@ impl Bindings { let (items, options, warnings) = codegen::codegen(context); - let module = if options.require_syn() { + let module = if options.inputs().require_syn() { let module_wrapped_tokens = quote!(mod wrapper_for_sorting_hack { #( #items )* }); @@ -2577,7 +618,7 @@ impl Bindings { .unwrap() .1; - if options.merge_extern_blocks { + if options.inputs().merge_extern_blocks { // Here we will store all the items after deduplication. let mut items = Vec::new(); @@ -2630,7 +671,7 @@ impl Bindings { syn_parsed_items = items; } - if options.sort_semantically { + if options.inputs().sort_semantically { syn_parsed_items.sort_by_key(|item| match item { syn::Item::Type(_) => 0, syn::Item::Struct(_) => 1, @@ -2682,7 +723,7 @@ impl Bindings { /// Write these bindings as source text to the given `Write`able. pub fn write<'a>(&self, mut writer: Box) -> io::Result<()> { - if !self.options.disable_header_comment { + if self.options.inputs().enable_header_comment { let version = option_env!("CARGO_PKG_VERSION"); let header = format!( "/* automatically generated by rust-bindgen {} */\n\n", @@ -2691,12 +732,12 @@ impl Bindings { writer.write_all(header.as_bytes())?; } - for line in self.options.raw_lines.iter() { + for line in self.options.inputs().raw_lines.iter() { writer.write_all(line.as_bytes())?; writer.write_all("\n".as_bytes())?; } - if !self.options.raw_lines.is_empty() { + if !self.options.inputs().raw_lines.is_empty() { writer.write_all("\n".as_bytes())?; } @@ -2719,8 +760,8 @@ impl Bindings { /// Gets the rustfmt path to rustfmt the generated bindings. fn rustfmt_path(&self) -> io::Result> { - debug_assert!(self.options.rustfmt_bindings); - if let Some(ref p) = self.options.rustfmt_path { + debug_assert!(self.options.inputs().rustfmt_bindings); + if let Some(ref p) = self.options.inputs().rustfmt_path { return Ok(Cow::Borrowed(p)); } if let Ok(rustfmt) = env::var("RUSTFMT") { @@ -2745,9 +786,9 @@ impl Bindings { source: &'a str, ) -> io::Result> { let _t = time::Timer::new("rustfmt_generated_string") - .with_output(self.options.time_phases); + .with_output(self.options.inputs().time_phases); - if !self.options.rustfmt_bindings { + if !self.options.inputs().rustfmt_bindings { return Ok(Cow::Borrowed(source)); } @@ -2758,6 +799,7 @@ impl Bindings { if let Some(path) = self .options + .inputs() .rustfmt_configuration_file .as_ref() .and_then(|f| f.to_str()) @@ -2841,7 +883,7 @@ impl std::fmt::Display for Bindings { /// 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() + ctx.inputs().builtins || !cursor.is_builtin() } /// Parse one `Item` from the Clang cursor. @@ -2888,7 +930,7 @@ fn parse(context: &mut BindgenContext) -> Result<(), BindgenError> { let cursor = context.translation_unit().cursor(); - if context.options().emit_ast { + if context.inputs().emit_ast { fn dump_if_not_builtin(cur: &clang::Cursor) -> CXChildVisitResult { if !cur.is_builtin() { clang::ast_dump(cur, 0) diff --git a/src/regex_set.rs b/src/regex_set.rs index 127c001829..205b8ec4f6 100644 --- a/src/regex_set.rs +++ b/src/regex_set.rs @@ -3,8 +3,26 @@ use regex::RegexSet as RxSet; use std::cell::Cell; +/// A static list of regular expressions. +#[derive(Debug, Default, Clone)] +pub struct RegexItems { + inner: Vec, +} + +impl RegexItems { + /// Returns slice of String from its field 'items' + pub fn get_items(&self) -> &[String] { + &self.inner + } + + /// Insert a new regex into this list. + pub fn insert(&mut self, item: impl AsRef) { + self.inner.push(item.as_ref().to_owned()); + } +} + /// A dynamic set of regular expressions. -#[derive(Debug, Default)] +#[derive(Debug)] pub struct RegexSet { items: Vec, /// Whether any of the items in the set was ever matched. The length of this @@ -16,24 +34,29 @@ pub struct RegexSet { } impl RegexSet { - /// Is this set empty? - pub fn is_empty(&self) -> bool { - self.items.is_empty() - } + /// Construct a RegexSet from the set of entries we've accumulated. + pub fn new(items: RegexItems, record_matches: bool) -> Self { + let set = match RxSet::new( + items.inner.iter().map(|item| format!("^{}$", item)), + ) { + Ok(x) => Some(x), + Err(e) => { + warn!("Invalid regex in {:?}: {:?}", items.inner, e); + None + } + }; - /// Insert a new regex into this set. - pub fn insert(&mut self, string: S) - where - S: AsRef, - { - self.items.push(string.as_ref().to_owned()); - self.matched.push(Cell::new(false)); - self.set = None; + Self { + matched: vec![Cell::new(false); items.inner.len()], + items: items.inner, + set, + record_matches, + } } - /// Returns slice of String from its field 'items' - pub fn get_items(&self) -> &[String] { - &self.items[..] + /// Is this set empty? + pub fn is_empty(&self) -> bool { + self.items.is_empty() } /// Returns an iterator over regexes in the set which didn't match any @@ -48,22 +71,6 @@ impl RegexSet { }) } - /// Construct a RegexSet from the set of entries we've accumulated. - /// - /// Must be called before calling `matches()`, or it will always return - /// false. - pub fn build(&mut self, record_matches: bool) { - let items = self.items.iter().map(|item| format!("^{}$", item)); - self.record_matches = record_matches; - self.set = match RxSet::new(items) { - Ok(x) => Some(x), - Err(e) => { - warn!("Invalid regex in {:?}: {:?}", self.items, e); - None - } - } - } - /// Does the given `string` match any of the regexes in this set? pub fn matches(&self, string: S) -> bool where