| //! Generate Rust bindings for C and C++ libraries. |
| //! |
| //! Provide a C/C++ header file, receive Rust FFI code to call into C/C++ |
| //! functions and use types defined in the header. |
| //! |
| //! See the [`Builder`](./struct.Builder.html) struct for usage. |
| //! |
| //! See the [Users Guide](https://rust-lang.github.io/rust-bindgen/) for |
| //! additional documentation. |
| #![deny(missing_docs)] |
| #![deny(unused_extern_crates)] |
| // To avoid rather annoying warnings when matching with CXCursor_xxx as a |
| // constant. |
| #![allow(non_upper_case_globals)] |
| // `quote!` nests quite deeply. |
| #![recursion_limit = "128"] |
| |
| #[macro_use] |
| extern crate bitflags; |
| #[macro_use] |
| #[allow(unused_extern_crates)] |
| extern crate cfg_if; |
| #[macro_use] |
| extern crate lazy_static; |
| #[macro_use] |
| extern crate quote; |
| |
| #[cfg(feature = "logging")] |
| #[macro_use] |
| extern crate log; |
| |
| #[cfg(not(feature = "logging"))] |
| #[macro_use] |
| mod log_stubs; |
| |
| #[macro_use] |
| mod extra_assertions; |
| |
| // A macro to declare an internal module for which we *must* provide |
| // documentation for. If we are building with the "testing_only_docs" feature, |
| // then the module is declared public, and our `#![deny(missing_docs)]` pragma |
| // applies to it. This feature is used in CI, so we won't let anything slip by |
| // undocumented. Normal builds, however, will leave the module private, so that |
| // we don't expose internals to library consumers. |
| macro_rules! doc_mod { |
| ($m:ident, $doc_mod_name:ident) => { |
| cfg_if! { |
| if #[cfg(feature = "testing_only_docs")] { |
| pub mod $doc_mod_name { |
| //! Autogenerated documentation module. |
| pub use super::$m::*; |
| } |
| } else { |
| } |
| } |
| }; |
| } |
| |
| mod clang; |
| mod codegen; |
| mod features; |
| mod ir; |
| mod parse; |
| mod regex_set; |
| mod time; |
| |
| pub mod callbacks; |
| |
| doc_mod!(clang, clang_docs); |
| doc_mod!(features, features_docs); |
| doc_mod!(ir, ir_docs); |
| doc_mod!(parse, parse_docs); |
| doc_mod!(regex_set, regex_set_docs); |
| |
| pub use crate::codegen::{AliasVariation, EnumVariation, MacroTypeVariation}; |
| use crate::features::RustFeatures; |
| pub use crate::features::{ |
| RustTarget, LATEST_STABLE_RUST, RUST_TARGET_STRINGS, |
| }; |
| use crate::ir::context::{BindgenContext, ItemId}; |
| use crate::ir::item::Item; |
| use crate::parse::{ClangItemParser, ParseError}; |
| use crate::regex_set::RegexSet; |
| |
| use std::borrow::Cow; |
| use std::fs::{File, 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<K, V> = ::rustc_hash::FxHashMap<K, V>; |
| type HashSet<K> = ::rustc_hash::FxHashSet<K>; |
| pub(crate) use std::collections::hash_map::Entry; |
| |
| /// Default prefix for the anon fields. |
| pub const DEFAULT_ANON_FIELDS_PREFIX: &'static str = "__bindgen_anon_"; |
| |
| fn args_are_cpp(clang_args: &[String]) -> bool { |
| return clang_args |
| .windows(2) |
| .any(|w| w[0] == "-xc++" || w[1] == "-xc++" || w == &["-x", "c++"]); |
| } |
| |
| bitflags! { |
| /// A type used to indicate which kind of items we have to generate. |
| pub struct CodegenConfig: u32 { |
| /// Whether to generate functions. |
| const FUNCTIONS = 1 << 0; |
| /// Whether to generate types. |
| const TYPES = 1 << 1; |
| /// Whether to generate constants. |
| const VARS = 1 << 2; |
| /// Whether to generate methods. |
| const METHODS = 1 << 3; |
| /// Whether to generate constructors |
| const CONSTRUCTORS = 1 << 4; |
| /// Whether to generate destructors. |
| const DESTRUCTORS = 1 << 5; |
| } |
| } |
| |
| impl CodegenConfig { |
| /// Returns true if functions should be generated. |
| pub fn functions(self) -> bool { |
| self.contains(CodegenConfig::FUNCTIONS) |
| } |
| |
| /// Returns true if types should be generated. |
| pub fn types(self) -> bool { |
| self.contains(CodegenConfig::TYPES) |
| } |
| |
| /// Returns true if constants should be generated. |
| pub fn vars(self) -> bool { |
| self.contains(CodegenConfig::VARS) |
| } |
| |
| /// Returns true if methds should be generated. |
| pub fn methods(self) -> bool { |
| self.contains(CodegenConfig::METHODS) |
| } |
| |
| /// Returns true if constructors should be generated. |
| pub fn constructors(self) -> bool { |
| self.contains(CodegenConfig::CONSTRUCTORS) |
| } |
| |
| /// Returns true if destructors should be generated. |
| pub fn destructors(self) -> bool { |
| self.contains(CodegenConfig::DESTRUCTORS) |
| } |
| } |
| |
| impl Default for CodegenConfig { |
| fn default() -> Self { |
| CodegenConfig::all() |
| } |
| } |
| |
| /// Configure and generate Rust bindings for a C/C++ header. |
| /// |
| /// This is the main entry point to the library. |
| /// |
| /// ```ignore |
| /// use bindgen::builder; |
| /// |
| /// // Configure and generate bindings. |
| /// let bindings = builder().header("path/to/input/header") |
| /// .whitelist_type("SomeCoolClass") |
| /// .whitelist_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<String>, |
| // 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() |
| } |
| |
| impl Builder { |
| /// Generates the command line flags use for creating `Builder`. |
| pub fn command_line_flags(&self) -> Vec<String> { |
| let mut output_vector: Vec<String> = Vec::new(); |
| |
| if let Some(header) = self.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 } => { |
| "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()); |
| } |
| |
| let regex_sets = &[ |
| (&self.options.bitfield_enums, "--bitfield-enum"), |
| (&self.options.newtype_enums, "--newtype-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.blacklisted_types, "--blacklist-type"), |
| (&self.options.blacklisted_functions, "--blacklist-function"), |
| (&self.options.blacklisted_items, "--blacklist-item"), |
| (&self.options.opaque_types, "--opaque-type"), |
| (&self.options.whitelisted_functions, "--whitelist-function"), |
| (&self.options.whitelisted_types, "--whitelist-type"), |
| (&self.options.whitelisted_vars, "--whitelist-var"), |
| (&self.options.no_partialeq_types, "--no-partialeq"), |
| (&self.options.no_copy_types, "--no-copy"), |
| (&self.options.no_debug_types, "--no-debug"), |
| (&self.options.no_hash_types, "--no-hash"), |
| ]; |
| |
| 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.whitelist_recursively { |
| output_vector.push("--no-recursive-whitelist".into()); |
| } |
| |
| if self.options.objc_extern_crate { |
| output_vector.push("--objc-extern-crate".into()); |
| } |
| |
| if self.options.generate_block { |
| output_vector.push("--generate-block".into()); |
| } |
| |
| if self.options.block_extern_crate { |
| output_vector.push("--block-extern-crate".into()); |
| } |
| |
| if self.options.builtins { |
| output_vector.push("--builtins".into()); |
| } |
| |
| if let Some(ref prefix) = self.options.ctypes_prefix { |
| output_vector.push("--ctypes-prefix".into()); |
| output_vector.push(prefix.clone()); |
| } |
| |
| if self.options.anon_fields_prefix != DEFAULT_ANON_FIELDS_PREFIX { |
| output_vector.push("--anon-fields-prefix".into()); |
| output_vector.push(self.options.anon_fields_prefix.clone()); |
| } |
| |
| if self.options.emit_ast { |
| output_vector.push("--emit-clang-ast".into()); |
| } |
| |
| if self.options.emit_ir { |
| output_vector.push("--emit-ir".into()); |
| } |
| if let Some(ref graph) = self.options.emit_ir_graphviz { |
| output_vector.push("--emit-ir-graphviz".into()); |
| output_vector.push(graph.clone()) |
| } |
| if self.options.enable_cxx_namespaces { |
| output_vector.push("--enable-cxx-namespaces".into()); |
| } |
| if self.options.enable_function_attribute_detection { |
| output_vector.push("--enable-function-attribute-detection".into()); |
| } |
| if self.options.disable_name_namespacing { |
| output_vector.push("--disable-name-namespacing".into()); |
| } |
| if self.options.disable_nested_struct_naming { |
| output_vector.push("--disable-nested-struct-naming".into()); |
| } |
| |
| if self.options.disable_header_comment { |
| output_vector.push("--disable-header-comment".into()); |
| } |
| |
| if !self.options.codegen_config.functions() { |
| output_vector.push("--ignore-functions".into()); |
| } |
| |
| output_vector.push("--generate".into()); |
| |
| //Temporary placeholder for below 4 options |
| let mut options: Vec<String> = Vec::new(); |
| if self.options.codegen_config.functions() { |
| options.push("functions".into()); |
| } |
| if self.options.codegen_config.types() { |
| options.push("types".into()); |
| } |
| if self.options.codegen_config.vars() { |
| options.push("vars".into()); |
| } |
| if self.options.codegen_config.methods() { |
| options.push("methods".into()); |
| } |
| if self.options.codegen_config.constructors() { |
| options.push("constructors".into()); |
| } |
| if self.options.codegen_config.destructors() { |
| options.push("destructors".into()); |
| } |
| |
| output_vector.push(options.join(",")); |
| |
| if !self.options.codegen_config.methods() { |
| output_vector.push("--ignore-methods".into()); |
| } |
| |
| if !self.options.convert_floats { |
| output_vector.push("--no-convert-floats".into()); |
| } |
| |
| if !self.options.prepend_enum_name { |
| output_vector.push("--no-prepend-enum-name".into()); |
| } |
| |
| if self.options.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()); |
| } |
| |
| 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()); |
| } |
| |
| // 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<T: Into<String>>(mut self, header: T) -> Builder { |
| self.input_headers.push(header.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 { |
| self.input_header_contents |
| .push((name.into(), 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<T: Into<String>>(mut self, path: T) -> Builder { |
| let path = path.into(); |
| self.options.emit_ir_graphviz = Some(path); |
| self |
| } |
| |
| /// Whether the generated bindings should contain documentation comments |
| /// (docstrings) or not. |
| /// |
| /// This ideally will always be true, but it may need to be false until we |
| /// implement some processing on comments to work around issues as described |
| /// in [rust-bindgen issue |
| /// #426](https://github.com/rust-lang/rust-bindgen/issues/426). |
| /// |
| /// 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 whitelist recursively or not. Defaults to true. |
| /// |
| /// Given that we have explicitly whitelisted 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 `whitelist_recursively(false)`, `bindgen` will not emit |
| /// bindings for anything except the explicitly whitelisted 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 whitelisted 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 whitelist_recursively(mut self, doit: bool) -> Self { |
| self.options.whitelist_recursively = doit; |
| self |
| } |
| |
| /// Generate `#[macro_use] extern crate objc;` instead of `use objc;` |
| /// in the prologue of the files generated from objective-c files |
| pub fn objc_extern_crate(mut self, doit: bool) -> Self { |
| self.options.objc_extern_crate = doit; |
| self |
| } |
| |
| /// Generate proper block signatures instead of void pointers. |
| pub fn generate_block(mut self, doit: bool) -> Self { |
| self.options.generate_block = doit; |
| self |
| } |
| |
| /// Generate `#[macro_use] extern crate block;` instead of `use block;` |
| /// in the prologue of the files generated from apple block files |
| pub fn block_extern_crate(mut self, doit: bool) -> Self { |
| self.options.block_extern_crate = doit; |
| self |
| } |
| |
| /// Whether to use the clang-provided name mangling. This is true by default |
| /// and probably needed for C++ features. |
| /// |
| /// However, some old libclang versions seem to return incorrect results in |
| /// some cases for non-mangled functions, see [1], so we allow disabling it. |
| /// |
| /// [1]: https://github.com/rust-lang/rust-bindgen/issues/528 |
| pub fn trust_clang_mangling(mut self, doit: bool) -> Self { |
| self.options.enable_mangling = doit; |
| self |
| } |
| |
| /// Hide the given type from the generated bindings. Regular expressions are |
| /// supported. |
| #[deprecated(note = "Use blacklist_type instead")] |
| pub fn hide_type<T: AsRef<str>>(self, arg: T) -> Builder { |
| self.blacklist_type(arg) |
| } |
| |
| /// Hide the given type from the generated bindings. Regular expressions are |
| /// supported. |
| /// |
| /// To blacklist types prefixed with "mylib" use `"mylib_.*"`. |
| /// For more complicated expressions check |
| /// [regex](https://docs.rs/regex/*/regex/) docs |
| pub fn blacklist_type<T: AsRef<str>>(mut self, arg: T) -> Builder { |
| self.options.blacklisted_types.insert(arg); |
| self |
| } |
| |
| /// Hide the given function from the generated bindings. Regular expressions |
| /// are supported. |
| /// |
| /// To blacklist functions prefixed with "mylib" use `"mylib_.*"`. |
| /// For more complicated expressions check |
| /// [regex](https://docs.rs/regex/*/regex/) docs |
| pub fn blacklist_function<T: AsRef<str>>(mut self, arg: T) -> Builder { |
| self.options.blacklisted_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. |
| /// |
| /// To blacklist items prefixed with "mylib" use `"mylib_.*"`. |
| /// For more complicated expressions check |
| /// [regex](https://docs.rs/regex/*/regex/) docs |
| pub fn blacklist_item<T: AsRef<str>>(mut self, arg: T) -> Builder { |
| self.options.blacklisted_items.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<T: AsRef<str>>(mut self, arg: T) -> Builder { |
| self.options.opaque_types.insert(arg); |
| self |
| } |
| |
| /// Whitelist 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 whitelist_type instead")] |
| pub fn whitelisted_type<T: AsRef<str>>(self, arg: T) -> Builder { |
| self.whitelist_type(arg) |
| } |
| |
| /// Whitelist the given type so that it (and all types that it transitively |
| /// refers to) appears in the generated bindings. Regular expressions are |
| /// supported. |
| /// |
| /// To whitelist types prefixed with "mylib" use `"mylib_.*"`. |
| /// For more complicated expressions check |
| /// [regex](https://docs.rs/regex/*/regex/) docs |
| pub fn whitelist_type<T: AsRef<str>>(mut self, arg: T) -> Builder { |
| self.options.whitelisted_types.insert(arg); |
| self |
| } |
| |
| /// Whitelist the given function so that it (and all types that it |
| /// transitively refers to) appears in the generated bindings. Regular |
| /// expressions are supported. |
| /// |
| /// To whitelist functions prefixed with "mylib" use `"mylib_.*"`. |
| /// For more complicated expressions check |
| /// [regex](https://docs.rs/regex/*/regex/) docs |
| pub fn whitelist_function<T: AsRef<str>>(mut self, arg: T) -> Builder { |
| self.options.whitelisted_functions.insert(arg); |
| self |
| } |
| |
| /// Whitelist the given function. |
| /// |
| /// Deprecated: use whitelist_function instead. |
| #[deprecated(note = "use whitelist_function instead")] |
| pub fn whitelisted_function<T: AsRef<str>>(self, arg: T) -> Builder { |
| self.whitelist_function(arg) |
| } |
| |
| /// Whitelist the given variable so that it (and all types that it |
| /// transitively refers to) appears in the generated bindings. Regular |
| /// expressions are supported. |
| /// |
| /// To whitelist variables prefixed with "mylib" use `"mylib_.*"`. |
| /// For more complicated expressions check |
| /// [regex](https://docs.rs/regex/*/regex/) docs |
| pub fn whitelist_var<T: AsRef<str>>(mut self, arg: T) -> Builder { |
| self.options.whitelisted_vars.insert(arg); |
| self |
| } |
| |
| /// Whitelist the given variable. |
| /// |
| /// Deprecated: use whitelist_var instead. |
| #[deprecated(note = "use whitelist_var instead")] |
| pub fn whitelisted_var<T: AsRef<str>>(self, arg: T) -> Builder { |
| self.whitelist_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<T: AsRef<str>>(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<T: AsRef<str>>(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 Rust |
| /// enum. |
| /// |
| /// This makes bindgen generate enums instead of constants. Regular |
| /// expressions are supported. |
| /// |
| /// **Use this with caution**, creating this in unsafe code |
| /// (including FFI) with an invalid value will invoke undefined behaviour. |
| /// You may want to use the newtype enum style instead. |
| pub fn rustified_enum<T: AsRef<str>>(mut self, arg: T) -> Builder { |
| self.options.rustified_enums.insert(arg); |
| self |
| } |
| |
| /// Mark the given enum (or set of enums, if using a pattern) as a Rust |
| /// enum with the `#[non_exhaustive]` attribute. |
| /// |
| /// This makes bindgen generate enums instead of constants. Regular |
| /// expressions are supported. |
| /// |
| /// **Use this with caution**, creating this in unsafe code |
| /// (including FFI) with an invalid value will invoke undefined behaviour. |
| /// You may want to use the newtype enum style instead. |
| pub fn rustified_non_exhaustive_enum<T: AsRef<str>>( |
| mut self, |
| arg: T, |
| ) -> Builder { |
| self.options.rustified_non_exhaustive_enums.insert(arg); |
| self |
| } |
| |
| /// Mark the given enum (or set of enums, if using a pattern) as a set of |
| /// constants that are not to be put into a module. |
| pub fn constified_enum<T: AsRef<str>>(mut self, arg: T) -> Builder { |
| self.options.constified_enums.insert(arg); |
| self |
| } |
| |
| /// Mark the given enum (or set of enums, if using a pattern) as a set of |
| /// constants that should be put into a module. |
| /// |
| /// This makes bindgen generate modules containing constants instead of |
| /// just constants. Regular expressions are supported. |
| pub fn constified_enum_module<T: AsRef<str>>(mut self, arg: T) -> Builder { |
| self.options.constified_enum_modules.insert(arg); |
| self |
| } |
| |
| /// Set the default type for macro constants |
| pub fn default_macro_constant_type( |
| mut self, |
| arg: codegen::MacroTypeVariation, |
| ) -> Builder { |
| self.options.default_macro_constant_type = arg; |
| self |
| } |
| |
| /// Set the default style of code to generate for typedefs |
| pub fn default_alias_style( |
| mut self, |
| arg: codegen::AliasVariation, |
| ) -> Builder { |
| self.options.default_alias_style = arg; |
| self |
| } |
| |
| /// Mark the given typedef alias (or set of aliases, if using a pattern) to |
| /// use regular Rust type aliasing. |
| /// |
| /// This is the default behavior and should be used if `default_alias_style` |
| /// was set to NewType or NewTypeDeref and you want to override it for a |
| /// set of typedefs. |
| pub fn type_alias<T: AsRef<str>>(mut self, arg: T) -> Builder { |
| self.options.type_alias.insert(arg); |
| self |
| } |
| |
| /// Mark the given typedef alias (or set of aliases, if using a pattern) to |
| /// be generated as a new type by having the aliased type be wrapped in a |
| /// #[repr(transparent)] struct. |
| /// |
| /// Used to enforce stricter type checking. |
| pub fn new_type_alias<T: AsRef<str>>(mut self, arg: T) -> Builder { |
| self.options.new_type_alias.insert(arg); |
| self |
| } |
| |
| /// Mark the given typedef alias (or set of aliases, if using a pattern) to |
| /// be generated as a new type by having the aliased type be wrapped in a |
| /// #[repr(transparent)] struct and also have an automatically generated |
| /// impl's of `Deref` and `DerefMut` to their aliased type. |
| pub fn new_type_alias_deref<T: AsRef<str>>(mut self, arg: T) -> Builder { |
| self.options.new_type_alias_deref.insert(arg); |
| self |
| } |
| |
| /// Add a string to prepend to the generated bindings. The string is passed |
| /// through without any modification. |
| pub fn raw_line<T: Into<String>>(mut self, arg: T) -> Self { |
| self.options.raw_lines.push(arg.into()); |
| self |
| } |
| |
| /// Add a given line to the beginning of module `mod`. |
| pub fn module_raw_line<T, U>(mut self, mod_: T, line: U) -> Self |
| where |
| T: Into<String>, |
| U: Into<String>, |
| { |
| self.options |
| .module_lines |
| .entry(mod_.into()) |
| .or_insert_with(Vec::new) |
| .push(line.into()); |
| self |
| } |
| |
| /// Add a given set of lines to the beginning of module `mod`. |
| pub fn module_raw_lines<T, I>(mut self, mod_: T, lines: I) -> Self |
| where |
| T: Into<String>, |
| I: IntoIterator, |
| I::Item: Into<String>, |
| { |
| self.options |
| .module_lines |
| .entry(mod_.into()) |
| .or_insert_with(Vec::new) |
| .extend(lines.into_iter().map(Into::into)); |
| self |
| } |
| |
| /// Add an argument to be passed straight through to clang. |
| pub fn clang_arg<T: Into<String>>(mut self, arg: T) -> Builder { |
| self.options.clang_args.push(arg.into()); |
| self |
| } |
| |
| /// Add arguments to be passed straight through to clang. |
| pub fn clang_args<I>(mut self, iter: I) -> Builder |
| where |
| I: IntoIterator, |
| I::Item: AsRef<str>, |
| { |
| for arg in iter { |
| self = self.clang_arg(arg.as_ref()) |
| } |
| self |
| } |
| |
| /// Emit bindings for builtin definitions (for example `__builtin_va_list`) |
| /// in the generated Rust. |
| pub fn emit_builtins(mut self) -> Builder { |
| self.options.builtins = true; |
| self |
| } |
| |
| /// Avoid converting floats to `f32`/`f64` by default. |
| pub fn no_convert_floats(mut self) -> Self { |
| self.options.convert_floats = false; |
| self |
| } |
| |
| /// Set whether layout tests should be generated. |
| pub fn layout_tests(mut self, doit: bool) -> Self { |
| self.options.layout_tests = doit; |
| self |
| } |
| |
| /// Set whether `Debug` should be implemented, if it can not be derived automatically. |
| pub fn impl_debug(mut self, doit: bool) -> Self { |
| self.options.impl_debug = doit; |
| self |
| } |
| |
| /// Set whether `PartialEq` should be implemented, if it can not be derived automatically. |
| pub fn impl_partialeq(mut self, doit: bool) -> Self { |
| self.options.impl_partialeq = doit; |
| self |
| } |
| |
| /// Set whether `Copy` should be derived by default. |
| pub fn derive_copy(mut self, doit: bool) -> Self { |
| self.options.derive_copy = doit; |
| self |
| } |
| |
| /// Set whether `Debug` should be derived by default. |
| pub fn derive_debug(mut self, doit: bool) -> Self { |
| self.options.derive_debug = doit; |
| self |
| } |
| |
| /// Set whether `Default` should be derived by default. |
| pub fn derive_default(mut self, doit: bool) -> Self { |
| self.options.derive_default = doit; |
| self |
| } |
| |
| /// Set whether `Hash` should be derived by default. |
| pub fn derive_hash(mut self, doit: bool) -> Self { |
| self.options.derive_hash = doit; |
| self |
| } |
| |
| /// Set whether `PartialOrd` should be derived by default. |
| /// If we don't compute partialord, we also cannot compute |
| /// ord. Set the derive_ord to `false` when doit is `false`. |
| pub fn derive_partialord(mut self, doit: bool) -> Self { |
| self.options.derive_partialord = doit; |
| if !doit { |
| self.options.derive_ord = false; |
| } |
| self |
| } |
| |
| /// Set whether `Ord` should be derived by default. |
| /// We can't compute `Ord` without computing `PartialOrd`, |
| /// so we set the same option to derive_partialord. |
| pub fn derive_ord(mut self, doit: bool) -> Self { |
| self.options.derive_ord = doit; |
| self.options.derive_partialord = doit; |
| self |
| } |
| |
| /// Set whether `PartialEq` should be derived by default. |
| /// |
| /// If we don't derive `PartialEq`, we also cannot derive `Eq`, so deriving |
| /// `Eq` is also disabled when `doit` is `false`. |
| pub fn derive_partialeq(mut self, doit: bool) -> Self { |
| self.options.derive_partialeq = doit; |
| if !doit { |
| self.options.derive_eq = false; |
| } |
| self |
| } |
| |
| /// Set whether `Eq` should be derived by default. |
| /// |
| /// We can't derive `Eq` without also deriving `PartialEq`, so we also |
| /// enable deriving `PartialEq` when `doit` is `true`. |
| pub fn derive_eq(mut self, doit: bool) -> Self { |
| self.options.derive_eq = doit; |
| if doit { |
| self.options.derive_partialeq = doit; |
| } |
| self |
| } |
| |
| /// Set whether or not to time bindgen phases, and print information to |
| /// stderr. |
| pub fn time_phases(mut self, doit: bool) -> Self { |
| self.options.time_phases = doit; |
| self |
| } |
| |
| /// Emit Clang AST. |
| pub fn emit_clang_ast(mut self) -> Builder { |
| self.options.emit_ast = true; |
| self |
| } |
| |
| /// Emit IR. |
| pub fn emit_ir(mut self) -> Builder { |
| self.options.emit_ir = true; |
| self |
| } |
| |
| /// Enable C++ namespaces. |
| pub fn enable_cxx_namespaces(mut self) -> Builder { |
| self.options.enable_cxx_namespaces = true; |
| self |
| } |
| |
| /// Enable detecting must_use attributes on C functions. |
| /// |
| /// This is quite slow in some cases (see #1465), so it's disabled by |
| /// default. |
| /// |
| /// Note that for this to do something meaningful for now at least, the rust |
| /// target version has to have support for `#[must_use]`. |
| pub fn enable_function_attribute_detection(mut self) -> Self { |
| self.options.enable_function_attribute_detection = true; |
| self |
| } |
| |
| /// Disable name auto-namespacing. |
| /// |
| /// By default, bindgen mangles names like `foo::bar::Baz` to look like |
| /// `foo_bar_Baz` instead of just `Baz`. |
| /// |
| /// This method disables that behavior. |
| /// |
| /// Note that this intentionally does not change the names used for |
| /// whitelisting and blacklisting, 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 |
| } |
| |
| /// 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.options.use_core = true; |
| self |
| } |
| |
| /// Use the given prefix for the raw types instead of `::std::os::raw`. |
| pub fn ctypes_prefix<T: Into<String>>(mut self, prefix: T) -> Builder { |
| self.options.ctypes_prefix = Some(prefix.into()); |
| self |
| } |
| |
| /// Use the given prefix for the anon fields. |
| pub fn anon_fields_prefix<T: Into<String>>(mut self, prefix: T) -> Builder { |
| self.options.anon_fields_prefix = prefix.into(); |
| self |
| } |
| |
| /// Allows configuring types in different situations, see the |
| /// [`ParseCallbacks`](./callbacks/trait.ParseCallbacks.html) documentation. |
| pub fn parse_callbacks( |
| mut self, |
| cb: Box<dyn callbacks::ParseCallbacks>, |
| ) -> Self { |
| self.options.parse_callbacks = 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 |
| } |
| |
| /// Prepend the enum name to constant or newtype variants. |
| pub fn prepend_enum_name(mut self, doit: bool) -> Self { |
| self.options.prepend_enum_name = doit; |
| self |
| } |
| |
| /// Set whether `size_t` should be translated to `usize` automatically. |
| pub fn size_t_is_usize(mut self, is: bool) -> Self { |
| self.options.size_t_is_usize = is; |
| self |
| } |
| |
| /// Set whether rustfmt should format the generated bindings. |
| pub fn rustfmt_bindings(mut self, doit: bool) -> Self { |
| self.options.rustfmt_bindings = doit; |
| self |
| } |
| |
| /// Set whether we should record matched items in our regex sets. |
| pub fn record_matches(mut self, doit: bool) -> Self { |
| self.options.record_matches = doit; |
| self |
| } |
| |
| /// Set the absolute path to the rustfmt configuration file, if None, the standard rustfmt |
| /// options are used. |
| pub fn rustfmt_configuration_file(mut self, path: Option<PathBuf>) -> Self { |
| self = self.rustfmt_bindings(true); |
| self.options.rustfmt_configuration_file = path; |
| self |
| } |
| |
| /// Sets an explicit path to rustfmt, to be used when rustfmt is enabled. |
| pub fn with_rustfmt<P: Into<PathBuf>>(mut self, path: P) -> Self { |
| self.options.rustfmt_path = Some(path.into()); |
| self |
| } |
| |
| /// Generate the Rust bindings using the options built up thus far. |
| pub fn generate(mut self) -> Result<Bindings, ()> { |
| // Add any extra arguments from the environment to the clang command line. |
| if let Some(extra_clang_args) = |
| env::var("BINDGEN_EXTRA_CLANG_ARGS").ok() |
| { |
| // 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) { |
| self.options.clang_args.extend(strings); |
| } else { |
| self.options.clang_args.push(extra_clang_args); |
| }; |
| } |
| |
| // Transform input headers to arguments on the clang command line. |
| self.options.input_header = self.input_headers.pop(); |
| self.options |
| .clang_args |
| .extend(self.input_headers.drain(..).flat_map(|header| { |
| iter::once("-include".into()).chain(iter::once(header)) |
| })); |
| |
| 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<()> { |
| fn check_is_cpp(name_file: &str) -> bool { |
| name_file.ends_with(".hpp") || |
| name_file.ends_with(".hxx") || |
| name_file.ends_with(".hh") || |
| name_file.ends_with(".h++") |
| } |
| |
| 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 |= check_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 |= check_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); |
| } |
| |
| 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<T: Into<String>>(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<T: Into<String>>(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<T: Into<String>>(mut self, arg: T) -> Self { |
| self.options.no_debug_types.insert(arg.into()); |
| self |
| } |
| |
| /// Don't derive `Hash` for a given type. Regular |
| /// expressions are supported. |
| pub fn no_hash<T: Into<String>>(mut self, arg: T) -> Builder { |
| self.options.no_hash_types.insert(arg.into()); |
| self |
| } |
| |
| /// Set whether `arr[size]` should be treated as `*mut T` or `*mut [T; size]` (same for mut) |
| pub fn array_pointers_in_arguments(mut self, doit: bool) -> Self { |
| self.options.array_pointers_in_arguments = doit; |
| self |
| } |
| |
| /// Set the wasm import module name |
| pub fn wasm_import_module_name<T: Into<String>>( |
| mut self, |
| import_name: T, |
| ) -> Self { |
| self.options.wasm_import_module_name = Some(import_name.into()); |
| self |
| } |
| } |
| |
| /// Configuration options for generated bindings. |
| #[derive(Debug)] |
| struct BindgenOptions { |
| /// The set of types that have been blacklisted and should not appear |
| /// anywhere in the generated code. |
| blacklisted_types: RegexSet, |
| |
| /// The set of functions that have been blacklisted and should not appear |
| /// in the generated code. |
| blacklisted_functions: RegexSet, |
| |
| /// The set of items, regardless of item-type, that have been |
| /// blacklisted and should not appear in the generated code. |
| blacklisted_items: RegexSet, |
| |
| /// The set of types that should be treated as opaque structures in the |
| /// generated code. |
| opaque_types: RegexSet, |
| |
| /// The explicit rustfmt path. |
| rustfmt_path: Option<PathBuf>, |
| |
| /// The 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 whitelisted types/vars/functions as GC roots, |
| /// and the generated Rust code as including everything that gets marked. |
| whitelisted_types: RegexSet, |
| |
| /// Whitelisted functions. See docs for `whitelisted_types` for more. |
| whitelisted_functions: RegexSet, |
| |
| /// Whitelisted variables. See docs for `whitelisted_types` for more. |
| whitelisted_vars: RegexSet, |
| |
| /// The default style of code to generate for enums |
| default_enum_style: codegen::EnumVariation, |
| |
| /// The enum patterns to mark an enum as a bitfield |
| /// (newtype with bitwise operations). |
| bitfield_enums: RegexSet, |
| |
| /// The enum patterns to mark an enum as a newtype. |
| newtype_enums: RegexSet, |
| |
| /// The enum patterns to mark an enum as a Rust enum. |
| rustified_enums: RegexSet, |
| |
| /// The enum patterns to mark an enum as a non-exhaustive Rust enum. |
| rustified_non_exhaustive_enums: RegexSet, |
| |
| /// The enum patterns to mark an enum as a module of constants. |
| constified_enum_modules: RegexSet, |
| |
| /// The enum patterns to mark an enum as a set of constants. |
| constified_enums: RegexSet, |
| |
| /// The default type for C macro constants. |
| default_macro_constant_type: codegen::MacroTypeVariation, |
| |
| /// The default style of code to generate for typedefs. |
| default_alias_style: codegen::AliasVariation, |
| |
| /// Typedef patterns that will use regular type aliasing. |
| type_alias: RegexSet, |
| |
| /// Typedef patterns that will be aliased by creating a new struct. |
| new_type_alias: RegexSet, |
| |
| /// Typedef patterns that will be wrapped in a new struct and have |
| /// Deref and Deref to their aliased type. |
| new_type_alias_deref: RegexSet, |
| |
| /// Whether we should generate builtins or not. |
| builtins: bool, |
| |
| /// True if we should dump the Clang AST for debugging purposes. |
| emit_ast: bool, |
| |
| /// True if we should dump our internal IR for debugging purposes. |
| emit_ir: bool, |
| |
| /// Output graphviz dot file. |
| emit_ir_graphviz: Option<String>, |
| |
| /// True if we should emulate C++ namespaces with Rust modules in the |
| /// generated bindings. |
| enable_cxx_namespaces: bool, |
| |
| /// True if we should try to find unexposed attributes in functions, in |
| /// order to be able to generate #[must_use] attributes in Rust. |
| enable_function_attribute_detection: bool, |
| |
| /// True if we should avoid mangling names with namespaces. |
| disable_name_namespacing: bool, |
| |
| /// True if we should avoid generating nested struct names. |
| disable_nested_struct_naming: bool, |
| |
| /// True if we should avoid embedding version identifiers into source code. |
| disable_header_comment: bool, |
| |
| /// True if we should generate layout tests for generated structures. |
| layout_tests: bool, |
| |
| /// True if we should implement the Debug trait for C/C++ structures and types |
| /// that do not support automatically deriving Debug. |
| impl_debug: bool, |
| |
| /// True if we should implement the PartialEq trait for C/C++ structures and types |
| /// that do not support automatically deriving PartialEq. |
| impl_partialeq: bool, |
| |
| /// True if we should derive Copy trait implementations for C/C++ structures |
| /// and types. |
| derive_copy: bool, |
| |
| /// True if we should derive Debug trait implementations for C/C++ structures |
| /// and types. |
| derive_debug: bool, |
| |
| /// True if we should derive Default trait implementations for C/C++ structures |
| /// and types. |
| derive_default: bool, |
| |
| /// True if we should derive Hash trait implementations for C/C++ structures |
| /// and types. |
| derive_hash: bool, |
| |
| /// True if we should derive PartialOrd trait implementations for C/C++ structures |
| /// and types. |
| derive_partialord: bool, |
| |
| /// True if we should derive Ord trait implementations for C/C++ structures |
| /// and types. |
| derive_ord: bool, |
| |
| /// True if we should derive PartialEq trait implementations for C/C++ structures |
| /// and types. |
| derive_partialeq: bool, |
| |
| /// True if we should derive Eq trait implementations for C/C++ structures |
| /// and types. |
| derive_eq: bool, |
| |
| /// True if we should avoid using libstd to use libcore instead. |
| use_core: bool, |
| |
| /// An optional prefix for the "raw" types, like `c_int`, `c_void`... |
| ctypes_prefix: Option<String>, |
| |
| /// The prefix for the anon fields. |
| anon_fields_prefix: String, |
| |
| /// Whether to time the bindgen phases. |
| time_phases: bool, |
| |
| /// True if we should generate constant names that are **directly** under |
| /// namespaces. |
| namespaced_constants: bool, |
| |
| /// True if we should use MSVC name mangling rules. |
| msvc_mangling: bool, |
| |
| /// Whether we should convert float types to f32/f64 types. |
| convert_floats: bool, |
| |
| /// The set of raw lines to prepend to the top-level module of generated |
| /// Rust code. |
| raw_lines: Vec<String>, |
| |
| /// The set of raw lines to prepend to each of the modules. |
| /// |
| /// This only makes sense if the `enable_cxx_namespaces` option is set. |
| module_lines: HashMap<String, Vec<String>>, |
| |
| /// The set of arguments to pass straight through to Clang. |
| clang_args: Vec<String>, |
| |
| /// The input header file. |
| input_header: Option<String>, |
| |
| /// Unsaved files for input. |
| input_unsaved_files: Vec<clang::UnsavedFile>, |
| |
| /// A user-provided visitor to allow customizing different kinds of |
| /// situations. |
| parse_callbacks: Option<Box<dyn callbacks::ParseCallbacks>>, |
| |
| /// Which kind of items should we generate? By default, we'll generate all |
| /// of them. |
| codegen_config: CodegenConfig, |
| |
| /// Whether to treat inline namespaces conservatively. |
| /// |
| /// See the builder method description for more details. |
| conservative_inline_namespaces: bool, |
| |
| /// Whether to keep documentation comments in the generated output. See the |
| /// documentation for more details. |
| generate_comments: bool, |
| |
| /// Whether to generate inline functions. Defaults to false. |
| generate_inline_functions: bool, |
| |
| /// Whether to whitelist types recursively. Defaults to true. |
| whitelist_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 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 whitelist |
| /// items via the `error!` log. |
| record_matches: bool, |
| |
| /// Whether `size_t` should be translated to `usize` automatically. |
| size_t_is_usize: bool, |
| |
| /// Whether rustfmt should format the generated bindings. |
| rustfmt_bindings: bool, |
| |
| /// The absolute path to the rustfmt configuration file, if None, the standard rustfmt |
| /// options are used. |
| rustfmt_configuration_file: Option<PathBuf>, |
| |
| /// The set of types that we should not derive `PartialEq` for. |
| no_partialeq_types: RegexSet, |
| |
| /// The set of types that we should not derive `Copy` for. |
| no_copy_types: RegexSet, |
| |
| /// The set of types that we should not derive `Debug` for. |
| no_debug_types: RegexSet, |
| |
| /// The set of types that we should not derive `Hash` for. |
| no_hash_types: RegexSet, |
| |
| /// Decide if C arrays should be regular pointers in rust or array pointers |
| array_pointers_in_arguments: bool, |
| |
| /// Wasm import module name. |
| wasm_import_module_name: Option<String>, |
| } |
| |
| /// 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 { |
| fn build(&mut self) { |
| let mut regex_sets = [ |
| &mut self.whitelisted_vars, |
| &mut self.whitelisted_types, |
| &mut self.whitelisted_functions, |
| &mut self.blacklisted_types, |
| &mut self.blacklisted_functions, |
| &mut self.blacklisted_items, |
| &mut self.opaque_types, |
| &mut self.bitfield_enums, |
| &mut self.constified_enums, |
| &mut self.constified_enum_modules, |
| &mut self.newtype_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.no_partialeq_types, |
| &mut self.no_copy_types, |
| &mut self.no_debug_types, |
| &mut self.no_hash_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(), |
| blacklisted_types: Default::default(), |
| blacklisted_functions: Default::default(), |
| blacklisted_items: Default::default(), |
| opaque_types: Default::default(), |
| rustfmt_path: Default::default(), |
| whitelisted_types: Default::default(), |
| whitelisted_functions: Default::default(), |
| whitelisted_vars: Default::default(), |
| default_enum_style: Default::default(), |
| bitfield_enums: Default::default(), |
| newtype_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(), |
| 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(), |
| namespaced_constants: true, |
| msvc_mangling: false, |
| convert_floats: true, |
| raw_lines: vec![], |
| module_lines: HashMap::default(), |
| clang_args: vec![], |
| input_header: None, |
| input_unsaved_files: vec![], |
| parse_callbacks: None, |
| codegen_config: CodegenConfig::all(), |
| conservative_inline_namespaces: false, |
| generate_comments: true, |
| generate_inline_functions: false, |
| whitelist_recursively: true, |
| generate_block: false, |
| objc_extern_crate: false, |
| block_extern_crate: false, |
| enable_mangling: true, |
| detect_include_paths: true, |
| 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_hash_types: Default::default(), |
| array_pointers_in_arguments: false, |
| wasm_import_module_name: None, |
| } |
| } |
| } |
| |
| #[cfg(feature = "runtime")] |
| fn ensure_libclang_is_loaded() { |
| if clang_sys::is_loaded() { |
| return; |
| } |
| |
| // XXX (issue #350): Ensure that our dynamically loaded `libclang` |
| // doesn't get dropped prematurely, nor is loaded multiple times |
| // across different threads. |
| |
| lazy_static! { |
| static ref LIBCLANG: std::sync::Arc<clang_sys::SharedLibrary> = { |
| clang_sys::load().expect("Unable to find libclang"); |
| clang_sys::get_library().expect( |
| "We just loaded libclang and it had better still be \ |
| here!", |
| ) |
| }; |
| } |
| |
| clang_sys::set_library(Some(LIBCLANG.clone())); |
| } |
| |
| #[cfg(not(feature = "runtime"))] |
| fn ensure_libclang_is_loaded() {} |
| |
| /// Generated Rust bindings. |
| #[derive(Debug)] |
| pub struct Bindings { |
| options: BindgenOptions, |
| module: proc_macro2::TokenStream, |
| } |
| |
| pub(crate) const HOST_TARGET: &'static str = |
| include_str!(concat!(env!("OUT_DIR"), "/host-target.txt")); |
| |
| // Some architecture triplets are different between rust and libclang, see #1211 |
| // and duplicates. |
| fn rust_to_clang_target(rust_target: &str) -> String { |
| if rust_target.starts_with("aarch64-apple-") { |
| let mut clang_target = "arm64-apple-".to_owned(); |
| clang_target.push_str(&rust_target["aarch64-apple-".len()..]); |
| return clang_target; |
| } |
| rust_target.to_owned() |
| } |
| |
| /// Returns the effective target, and whether it was explicitly specified on the |
| /// clang flags. |
| fn find_effective_target(clang_args: &[String]) -> (String, bool) { |
| let mut args = clang_args.iter(); |
| while let Some(opt) = args.next() { |
| if opt.starts_with("--target=") { |
| let mut split = opt.split('='); |
| split.next(); |
| return (split.next().unwrap().to_owned(), true); |
| } |
| |
| if opt == "-target" { |
| if let Some(target) = args.next() { |
| return (target.clone(), true); |
| } |
| } |
| } |
| |
| // If we're running from a build script, try to find the cargo target. |
| if let Ok(t) = env::var("TARGET") { |
| return (rust_to_clang_target(&t), false); |
| } |
| |
| (rust_to_clang_target(HOST_TARGET), false) |
| } |
| |
| impl Bindings { |
| /// Generate bindings for the given options. |
| pub(crate) fn generate( |
| mut options: BindgenOptions, |
| ) -> Result<Bindings, ()> { |
| ensure_libclang_is_loaded(); |
| |
| #[cfg(feature = "runtime")] |
| debug!( |
| "Generating bindings, libclang at {}", |
| clang_sys::get_library().unwrap().path().display() |
| ); |
| #[cfg(not(feature = "runtime"))] |
| debug!("Generating bindings, libclang linked"); |
| |
| options.build(); |
| |
| let (effective_target, explicit_target) = |
| find_effective_target(&options.clang_args); |
| |
| let is_host_build = |
| rust_to_clang_target(HOST_TARGET) == effective_target; |
| |
| // NOTE: The is_host_build check wouldn't be sound normally in some |
| // cases if we were to call a binary (if you have a 32-bit clang and are |
| // building on a 64-bit system for example). But since we rely on |
| // opening libclang.so, it has to be the same architecture and thus the |
| // check is fine. |
| if !explicit_target && !is_host_build { |
| options |
| .clang_args |
| .insert(0, format!("--target={}", effective_target)); |
| }; |
| |
| fn detect_include_paths(options: &mut BindgenOptions) { |
| if !options.detect_include_paths { |
| return; |
| } |
| |
| // Filter out include paths and similar stuff, so we don't incorrectly |
| // promote them to `-isystem`. |
| let clang_args_for_clang_sys = { |
| let mut last_was_include_prefix = false; |
| options |
| .clang_args |
| .iter() |
| .filter(|arg| { |
| if last_was_include_prefix { |
| last_was_include_prefix = false; |
| return false; |
| } |
| |
| let arg = &**arg; |
| |
| // https://clang.llvm.org/docs/ClangCommandLineReference.html |
| // -isystem and -isystem-after are harmless. |
| if arg == "-I" || arg == "--include-directory" { |
| last_was_include_prefix = true; |
| return false; |
| } |
| |
| if arg.starts_with("-I") || |
| arg.starts_with("--include-directory=") |
| { |
| return false; |
| } |
| |
| true |
| }) |
| .cloned() |
| .collect::<Vec<_>>() |
| }; |
| |
| debug!( |
| "Trying to find clang with flags: {:?}", |
| clang_args_for_clang_sys |
| ); |
| |
| let clang = match clang_sys::support::Clang::find( |
| None, |
| &clang_args_for_clang_sys, |
| ) { |
| None => return, |
| Some(clang) => clang, |
| }; |
| |
| debug!("Found clang: {:?}", clang); |
| |
| // Whether we are working with C or C++ inputs. |
| let is_cpp = args_are_cpp(&options.clang_args); |
| let search_paths = if is_cpp { |
| clang.cpp_search_paths |
| } else { |
| clang.c_search_paths |
| }; |
| |
| if let Some(search_paths) = search_paths { |
| for path in search_paths.into_iter() { |
| if let Ok(path) = path.into_os_string().into_string() { |
| options.clang_args.push("-isystem".to_owned()); |
| options.clang_args.push(path); |
| } |
| } |
| } |
| } |
| |
| detect_include_paths(&mut options); |
| |
| #[cfg(unix)] |
| fn can_read(perms: &std::fs::Permissions) -> bool { |
| use std::os::unix::fs::PermissionsExt; |
| perms.mode() & 0o444 > 0 |
| } |
| |
| #[cfg(not(unix))] |
| fn can_read(_: &std::fs::Permissions) -> bool { |
| true |
| } |
| |
| if let Some(h) = options.input_header.as_ref() { |
| if let Ok(md) = std::fs::metadata(h) { |
| if md.is_dir() { |
| eprintln!("error: '{}' is a folder", h); |
| return Err(()); |
| } |
| if !can_read(&md.permissions()) { |
| eprintln!( |
| "error: insufficient permissions to read '{}'", |
| h |
| ); |
| return Err(()); |
| } |
| options.clang_args.push(h.clone()) |
| } else { |
| eprintln!("error: header '{}' does not exist.", h); |
| return Err(()); |
| } |
| } |
| |
| for f in options.input_unsaved_files.iter() { |
| options.clang_args.push(f.name.to_str().unwrap().to_owned()) |
| } |
| |
| debug!("Fixed-up options: {:?}", options); |
| |
| let time_phases = options.time_phases; |
| let mut context = BindgenContext::new(options); |
| |
| if is_host_build { |
| debug_assert_eq!( |
| context.target_pointer_size(), |
| std::mem::size_of::<*mut ()>(), |
| "{:?} {:?}", |
| effective_target, |
| HOST_TARGET |
| ); |
| } |
| |
| { |
| let _t = time::Timer::new("parse").with_output(time_phases); |
| parse(&mut context)?; |
| } |
| |
| let (items, options) = codegen::codegen(context); |
| |
| Ok(Bindings { |
| options, |
| module: quote! { |
| #( #items )* |
| }, |
| }) |
| } |
| |
| /// Convert these bindings into source text (with raw lines prepended). |
| pub fn to_string(&self) -> String { |
| let mut bytes = vec![]; |
| self.write(Box::new(&mut bytes) as Box<dyn Write>) |
| .expect("writing to a vec cannot fail"); |
| String::from_utf8(bytes) |
| .expect("we should only write bindings that are valid utf-8") |
| } |
| |
| /// Write these bindings as source text to a file. |
| pub fn write_to_file<P: AsRef<Path>>(&self, path: P) -> io::Result<()> { |
| let file = OpenOptions::new() |
| .write(true) |
| .truncate(true) |
| .create(true) |
| .open(path.as_ref())?; |
| self.write(Box::new(file))?; |
| Ok(()) |
| } |
| |
| /// Write these bindings as source text to the given `Write`able. |
| pub fn write<'a>(&self, mut writer: Box<dyn Write + 'a>) -> io::Result<()> { |
| if !self.options.disable_header_comment { |
| let version = Some("0.55.1"); |
| let header = format!( |
| "/* automatically generated by rust-bindgen {} */\n\n", |
| version.unwrap_or("(unknown version)") |
| ); |
| writer.write_all(header.as_bytes())?; |
| } |
| |
| for line in self.options.raw_lines.iter() { |
| writer.write_all(line.as_bytes())?; |
| writer.write_all("\n".as_bytes())?; |
| } |
| |
| if !self.options.raw_lines.is_empty() { |
| writer.write_all("\n".as_bytes())?; |
| } |
| |
| let bindings = self.module.to_string(); |
| |
| match self.rustfmt_generated_string(&bindings) { |
| Ok(rustfmt_bindings) => { |
| writer.write_all(rustfmt_bindings.as_bytes())?; |
| } |
| Err(err) => { |
| eprintln!( |
| "Failed to run rustfmt: {} (non-fatal, continuing)", |
| err |
| ); |
| writer.write_all(bindings.as_bytes())?; |
| } |
| } |
| Ok(()) |
| } |
| |
| /// Gets the rustfmt path to rustfmt the generated bindings. |
| fn rustfmt_path<'a>(&'a self) -> io::Result<Cow<'a, PathBuf>> { |
| debug_assert!(self.options.rustfmt_bindings); |
| if let Some(ref p) = self.options.rustfmt_path { |
| return Ok(Cow::Borrowed(p)); |
| } |
| if let Ok(rustfmt) = env::var("RUSTFMT") { |
| return Ok(Cow::Owned(rustfmt.into())); |
| } |
| #[cfg(feature = "which-rustfmt")] |
| match which::which("rustfmt") { |
| Ok(p) => Ok(Cow::Owned(p)), |
| Err(e) => { |
| Err(io::Error::new(io::ErrorKind::Other, format!("{}", e))) |
| } |
| } |
| #[cfg(not(feature = "which-rustfmt"))] |
| // No rustfmt binary was specified, so assume that the binary is called |
| // "rustfmt" and that it is in the user's PATH. |
| Ok(Cow::Owned("rustfmt".into())) |
| } |
| |
| /// Checks if rustfmt_bindings is set and runs rustfmt on the string |
| fn rustfmt_generated_string<'a>( |
| &self, |
| source: &'a str, |
| ) -> io::Result<Cow<'a, str>> { |
| let _t = time::Timer::new("rustfmt_generated_string") |
| .with_output(self.options.time_phases); |
| |
| if !self.options.rustfmt_bindings { |
| return Ok(Cow::Borrowed(source)); |
| } |
| |
| let rustfmt = self.rustfmt_path()?; |
| let mut cmd = Command::new(&*rustfmt); |
| |
| cmd.stdin(Stdio::piped()).stdout(Stdio::piped()); |
| |
| if let Some(path) = self |
| .options |
| .rustfmt_configuration_file |
| .as_ref() |
| .and_then(|f| f.to_str()) |
| { |
| cmd.args(&["--config-path", path]); |
| } |
| |
| let mut child = cmd.spawn()?; |
| let mut child_stdin = child.stdin.take().unwrap(); |
| let mut child_stdout = child.stdout.take().unwrap(); |
| |
| let source = source.to_owned(); |
| |
| // Write to stdin in a new thread, so that we can read from stdout on this |
| // thread. This keeps the child from blocking on writing to its stdout which |
| // might block us from writing to its stdin. |
| let stdin_handle = ::std::thread::spawn(move || { |
| let _ = child_stdin.write_all(source.as_bytes()); |
| source |
| }); |
| |
| let mut output = vec![]; |
| io::copy(&mut child_stdout, &mut output)?; |
| |
| let status = child.wait()?; |
| let source = stdin_handle.join().expect( |
| "The thread writing to rustfmt's stdin doesn't do \ |
| anything that could panic", |
| ); |
| |
| match String::from_utf8(output) { |
| Ok(bindings) => match status.code() { |
| Some(0) => Ok(Cow::Owned(bindings)), |
| Some(2) => Err(io::Error::new( |
| io::ErrorKind::Other, |
| "Rustfmt parsing errors.".to_string(), |
| )), |
| Some(3) => { |
| warn!("Rustfmt could not format some lines."); |
| Ok(Cow::Owned(bindings)) |
| } |
| _ => Err(io::Error::new( |
| io::ErrorKind::Other, |
| "Internal rustfmt error".to_string(), |
| )), |
| }, |
| _ => Ok(Cow::Owned(source)), |
| } |
| } |
| } |
| |
| /// Determines whether the given cursor is in any of the files matched by the |
| /// options. |
| fn filter_builtins(ctx: &BindgenContext, cursor: &clang::Cursor) -> bool { |
| ctx.options().builtins || !cursor.is_builtin() |
| } |
| |
| /// Parse one `Item` from the Clang cursor. |
| fn parse_one( |
| ctx: &mut BindgenContext, |
| cursor: clang::Cursor, |
| parent: Option<ItemId>, |
| ) -> clang_sys::CXChildVisitResult { |
| if !filter_builtins(ctx, &cursor) { |
| return CXChildVisit_Continue; |
| } |
| |
| use clang_sys::CXChildVisit_Continue; |
| match Item::parse(cursor, parent, ctx) { |
| Ok(..) => {} |
| Err(ParseError::Continue) => {} |
| Err(ParseError::Recurse) => { |
| cursor.visit(|child| parse_one(ctx, child, parent)); |
| } |
| } |
| CXChildVisit_Continue |
| } |
| |
| /// Parse the Clang AST into our `Item` internal representation. |
| fn parse(context: &mut BindgenContext) -> Result<(), ()> { |
| use clang_sys::*; |
| |
| let mut any_error = false; |
| for d in context.translation_unit().diags().iter() { |
| let msg = d.format(); |
| let is_err = d.severity() >= CXDiagnostic_Error; |
| eprintln!("{}, err: {}", msg, is_err); |
| any_error |= is_err; |
| } |
| |
| if any_error { |
| return Err(()); |
| } |
| |
| let cursor = context.translation_unit().cursor(); |
| |
| if context.options().emit_ast { |
| fn dump_if_not_builtin(cur: &clang::Cursor) -> CXChildVisitResult { |
| if !cur.is_builtin() { |
| clang::ast_dump(&cur, 0) |
| } else { |
| CXChildVisit_Continue |
| } |
| } |
| cursor.visit(|cur| dump_if_not_builtin(&cur)); |
| } |
| |
| let root = context.root_module(); |
| context.with_module(root, |context| { |
| cursor.visit(|cursor| parse_one(context, cursor, None)) |
| }); |
| |
| assert!( |
| context.current_module() == context.root_module(), |
| "How did this happen?" |
| ); |
| Ok(()) |
| } |
| |
| /// Extracted Clang version data |
| #[derive(Debug)] |
| pub struct ClangVersion { |
| /// Major and minor semver, if parsing was successful |
| pub parsed: Option<(u32, u32)>, |
| /// full version string |
| pub full: String, |
| } |
| |
| /// Get the major and the minor semver numbers of Clang's version |
| pub fn clang_version() -> ClangVersion { |
| ensure_libclang_is_loaded(); |
| |
| let raw_v: String = clang::extract_clang_version(); |
| let split_v: Option<Vec<&str>> = raw_v |
| .split_whitespace() |
| .nth(2) |
| .map(|v| v.split('.').collect()); |
| match split_v { |
| Some(v) => { |
| if v.len() >= 2 { |
| let maybe_major = v[0].parse::<u32>(); |
| let maybe_minor = v[1].parse::<u32>(); |
| match (maybe_major, maybe_minor) { |
| (Ok(major), Ok(minor)) => { |
| return ClangVersion { |
| parsed: Some((major, minor)), |
| full: raw_v.clone(), |
| } |
| } |
| _ => {} |
| } |
| } |
| } |
| None => {} |
| }; |
| ClangVersion { |
| parsed: None, |
| full: raw_v.clone(), |
| } |
| } |
| |
| /// A ParseCallbacks implementation that will act on file includes by echoing a rerun-if-changed |
| /// line |
| /// |
| /// When running in side a `build.rs` script, this can be used to make cargo invalidate the |
| /// generated bindings whenever any of the files included from the header change: |
| /// ``` |
| /// use bindgen::builder; |
| /// let bindings = builder() |
| /// .header("path/to/input/header") |
| /// .parse_callbacks(Box::new(bindgen::CargoCallbacks)) |
| /// .generate(); |
| /// ``` |
| #[derive(Debug)] |
| pub struct CargoCallbacks; |
| |
| impl callbacks::ParseCallbacks for CargoCallbacks { |
| fn include_file(&self, filename: &str) { |
| println!("cargo:rerun-if-changed={}", filename); |
| } |
| } |
| |
| /// Test command_line_flag function. |
| #[test] |
| fn commandline_flag_unit_test_function() { |
| //Test 1 |
| let bindings = crate::builder(); |
| let command_line_flags = bindings.command_line_flags(); |
| |
| let test_cases = vec![ |
| "--rust-target", |
| "--no-derive-default", |
| "--generate", |
| "functions,types,vars,methods,constructors,destructors", |
| ] |
| .iter() |
| .map(|&x| x.into()) |
| .collect::<Vec<String>>(); |
| |
| assert!(test_cases |
| .iter() |
| .all(|ref x| command_line_flags.contains(x),)); |
| |
| //Test 2 |
| let bindings = crate::builder() |
| .header("input_header") |
| .whitelist_type("Distinct_Type") |
| .whitelist_function("safe_function"); |
| |
| let command_line_flags = bindings.command_line_flags(); |
| let test_cases = vec![ |
| "--rust-target", |
| "input_header", |
| "--no-derive-default", |
| "--generate", |
| "functions,types,vars,methods,constructors,destructors", |
| "--whitelist-type", |
| "Distinct_Type", |
| "--whitelist-function", |
| "safe_function", |
| ] |
| .iter() |
| .map(|&x| x.into()) |
| .collect::<Vec<String>>(); |
| println!("{:?}", command_line_flags); |
| |
| assert!(test_cases |
| .iter() |
| .all(|ref x| command_line_flags.contains(x),)); |
| } |
| |
| #[test] |
| fn test_rust_to_clang_target() { |
| assert_eq!(rust_to_clang_target("aarch64-apple-ios"), "arm64-apple-ios"); |
| } |