| //! 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(warnings)] |
| #![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; |
| extern crate cexpr; |
| #[macro_use] |
| #[allow(unused_extern_crates)] |
| extern crate cfg_if; |
| extern crate clang_sys; |
| extern crate hashbrown; |
| #[macro_use] |
| extern crate lazy_static; |
| extern crate peeking_take_while; |
| #[macro_use] |
| extern crate quote; |
| extern crate proc_macro2; |
| extern crate regex; |
| extern crate which; |
| |
| #[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 features::{LATEST_STABLE_RUST, RUST_TARGET_STRINGS, RustTarget}; |
| use features::RustFeatures; |
| use ir::context::{BindgenContext, ItemId}; |
| use ir::item::Item; |
| use parse::{ClangItemParser, ParseError}; |
| use regex_set::RegexSet; |
| pub use codegen::EnumVariation; |
| |
| use std::borrow::Cow; |
| use std::fs::{File, OpenOptions}; |
| use std::io::{self, Write}; |
| use std::iter; |
| use std::path::{Path, PathBuf}; |
| use std::process::{Command, Stdio}; |
| use std::sync::Arc; |
| |
| // Some convenient typedefs for a fast hash map and hash set. |
| type HashMap<K, V> = ::hashbrown::HashMap<K, V>; |
| type HashSet<K> = ::hashbrown::HashSet<K>; |
| pub(crate) use ::hashbrown::hash_map::Entry; |
| |
| 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") |
| /// .whitelisted_type("SomeCoolClass") |
| /// .whitelisted_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. [`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. Rustified enum |
| /// |
| /// If none of the above patterns match, then bindgen will generate a set of Rust constants. |
| #[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()); |
| |
| if self.options.default_enum_style != Default::default() { |
| output_vector.push("--default-enum-variant=".into()); |
| output_vector.push(match self.options.default_enum_style { |
| codegen::EnumVariation::Rust => "rust", |
| codegen::EnumVariation::Bitfield => "bitfield", |
| codegen::EnumVariation::Consts => "consts", |
| codegen::EnumVariation::ModuleConsts => "moduleconsts", |
| }.into()) |
| } |
| |
| self.options |
| .bitfield_enums |
| .get_items() |
| .iter() |
| .map(|item| { |
| output_vector.push("--bitfield-enum".into()); |
| output_vector.push(item.to_owned()); |
| }) |
| .count(); |
| |
| self.options |
| .rustified_enums |
| .get_items() |
| .iter() |
| .map(|item| { |
| output_vector.push("--rustified-enum".into()); |
| output_vector.push(item.to_owned()); |
| }) |
| .count(); |
| |
| self.options |
| .constified_enum_modules |
| .get_items() |
| .iter() |
| .map(|item| { |
| output_vector.push("--constified-enum-module".into()); |
| output_vector.push(item.to_owned()); |
| }) |
| .count(); |
| |
| self.options |
| .constified_enums |
| .get_items() |
| .iter() |
| .map(|item| { |
| output_vector.push("--constified-enum".into()); |
| output_vector.push(item.to_owned()); |
| }) |
| .count(); |
| |
| self.options |
| .blacklisted_types |
| .get_items() |
| .iter() |
| .map(|item| { |
| output_vector.push("--blacklist-type".into()); |
| output_vector.push(item.to_owned()); |
| }) |
| .count(); |
| |
| self.options |
| .blacklisted_functions |
| .get_items() |
| .iter() |
| .map(|item| { |
| output_vector.push("--blacklist-function".into()); |
| output_vector.push(item.to_owned()); |
| }) |
| .count(); |
| |
| self.options |
| .blacklisted_items |
| .get_items() |
| .iter() |
| .map(|item| { |
| output_vector.push("--blacklist-item".into()); |
| output_vector.push(item.to_owned()); |
| }) |
| .count(); |
| |
| 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.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.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()); |
| } |
| |
| self.options |
| .opaque_types |
| .get_items() |
| .iter() |
| .map(|item| { |
| output_vector.push("--opaque-type".into()); |
| output_vector.push(item.to_owned()); |
| }) |
| .count(); |
| |
| self.options |
| .raw_lines |
| .iter() |
| .map(|item| { |
| output_vector.push("--raw-line".into()); |
| output_vector.push(item.to_owned()); |
| }) |
| .count(); |
| |
| if self.options.use_core { |
| output_vector.push("--use-core".into()); |
| } |
| |
| if self.options.conservative_inline_namespaces { |
| output_vector.push("--conservative-inline-namespaces".into()); |
| } |
| |
| self.options |
| .whitelisted_functions |
| .get_items() |
| .iter() |
| .map(|item| { |
| output_vector.push("--whitelist-function".into()); |
| output_vector.push(item.to_owned()); |
| }) |
| .count(); |
| |
| self.options |
| .whitelisted_types |
| .get_items() |
| .iter() |
| .map(|item| { |
| output_vector.push("--whitelist-type".into()); |
| output_vector.push(item.to_owned()); |
| }) |
| .count(); |
| |
| self.options |
| .whitelisted_vars |
| .get_items() |
| .iter() |
| .map(|item| { |
| output_vector.push("--whitelist-var".into()); |
| output_vector.push(item.to_owned()); |
| }) |
| .count(); |
| |
| 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 { |
| output_vector.extend( |
| self.input_headers[..self.input_headers.len() - 1] |
| .iter() |
| .cloned(), |
| ); |
| } |
| |
| if !self.options.record_matches { |
| output_vector.push("--no-record-matches".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()); |
| } |
| |
| self.options |
| .no_partialeq_types |
| .get_items() |
| .iter() |
| .map(|item| { |
| output_vector.push("--no-partialeq".into()); |
| output_vector.push(item.to_owned()); |
| }) |
| .count(); |
| |
| self.options |
| .no_copy_types |
| .get_items() |
| .iter() |
| .map(|item| { |
| output_vector.push("--no-copy".into()); |
| output_vector.push(item.to_owned()); |
| }) |
| .count(); |
| |
| self.options |
| .no_hash_types |
| .get_items() |
| .iter() |
| .map(|item| { |
| output_vector.push("--no-hash".into()); |
| output_vector.push(item.to_owned()); |
| }) |
| .count(); |
| |
| 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 |
| } |
| |
| /// 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 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: |
| /// |
| /// https://github.com/rust-lang-nursery/rust-bindgen/issues/426 |
| 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-nursery/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. |
| 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. |
| 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. |
| 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. |
| 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. |
| 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. |
| 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. |
| 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. |
| 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 Rust |
| /// enum. |
| /// |
| /// This makes bindgen generate enums instead of constants. Regular |
| /// expressions are supported. |
| /// |
| /// **Use this with caution.** You should not be using Rust enums unless |
| /// you have complete control of the C/C++ code that you're binding to. |
| /// Take a look at https://github.com/rust-lang/rust/issues/36927 for |
| /// more information. |
| 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 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 |
| } |
| |
| /// 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 |
| } |
| |
| /// 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 |
| } |
| |
| /// Allows configuring types in different situations, see the |
| /// [`ParseCallbacks`](./callbacks/trait.ParseCallbacks.html) documentation. |
| pub fn parse_callbacks( |
| mut self, |
| cb: Box<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 |
| } |
| |
| /// Prepend the enum name to constant or bitfield variants. |
| pub fn prepend_enum_name(mut self, doit: bool) -> Self { |
| self.options.prepend_enum_name = doit; |
| 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, ()> { |
| 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(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 `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 |
| } |
| } |
| |
| /// 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 bitfield. |
| bitfield_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 module of constants. |
| constified_enum_modules: RegexSet, |
| |
| /// The enum patterns to mark an enum as a set of constants. |
| constified_enums: 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 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>, |
| |
| /// 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<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-nursery/rust-bindgen/issues/528 |
| enable_mangling: bool, |
| |
| /// Whether to prepend the enum name to bitfield or constant 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 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 `Hash` for. |
| no_hash_types: RegexSet, |
| } |
| |
| /// 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.rustified_enums, |
| &mut self.no_partialeq_types, |
| &mut self.no_copy_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(), |
| rustified_enums: Default::default(), |
| constified_enums: Default::default(), |
| constified_enum_modules: 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, |
| use_core: false, |
| ctypes_prefix: None, |
| 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, |
| prepend_enum_name: true, |
| time_phases: false, |
| record_matches: true, |
| rustfmt_bindings: true, |
| rustfmt_configuration_file: None, |
| no_partialeq_types: Default::default(), |
| no_copy_types: Default::default(), |
| no_hash_types: Default::default(), |
| } |
| } |
| } |
| |
| 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: 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())); |
| } |
| |
| /// Generated Rust bindings. |
| #[derive(Debug)] |
| pub struct Bindings { |
| options: BindgenOptions, |
| module: proc_macro2::TokenStream, |
| } |
| |
| impl Bindings { |
| /// Generate bindings for the given options. |
| pub(crate) fn generate( |
| mut options: BindgenOptions, |
| ) -> Result<Bindings, ()> { |
| ensure_libclang_is_loaded(); |
| |
| debug!("Generating bindings, libclang at {}", clang_sys::get_library().unwrap().path().display()); |
| |
| options.build(); |
| |
| // 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); |
| |
| // TODO: Make this path fixup configurable? |
| if let Some(clang) = clang_sys::support::Clang::find( |
| None, |
| &clang_args_for_clang_sys, |
| ) { |
| debug!("Found clang: {:?}", clang); |
| |
| // If --target is specified, assume caller knows what they're doing |
| // and don't mess with include paths for them |
| let has_target_arg = options |
| .clang_args |
| .iter() |
| .rposition(|arg| arg.starts_with("--target")) |
| .is_some(); |
| if !has_target_arg { |
| // 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); |
| } |
| } |
| } |
| } |
| } |
| |
| #[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); |
| |
| { |
| let _t = time::Timer::new("parse") |
| .with_output(time_phases); |
| parse(&mut context)?; |
| } |
| |
| let (items, options) = codegen::codegen(context); |
| |
| Ok(Bindings { |
| options: 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<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<Write + 'a>) -> io::Result<()> { |
| writer.write( |
| "/* automatically generated by rust-bindgen */\n\n".as_bytes(), |
| )?; |
| |
| for line in self.options.raw_lines.iter() { |
| writer.write(line.as_bytes())?; |
| writer.write("\n".as_bytes())?; |
| } |
| |
| if !self.options.raw_lines.is_empty() { |
| writer.write("\n".as_bytes())?; |
| } |
| |
| let bindings = self.module.to_string(); |
| |
| match self.rustfmt_generated_string(&bindings) { |
| Ok(rustfmt_bindings) => { |
| writer.write(rustfmt_bindings.as_bytes())?; |
| }, |
| Err(err) => { |
| eprintln!("Failed to run rustfmt: {} (non-fatal, continuing)", err); |
| writer.write(bindings.as_bytes())?; |
| }, |
| } |
| Ok(()) |
| } |
| |
| /// 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 = match self.options.rustfmt_path { |
| Some(ref p) => Cow::Borrowed(p), |
| None => { |
| let path = which::which("rustfmt") |
| .map_err(|e| { |
| io::Error::new(io::ErrorKind::Other, format!("{}", e)) |
| })?; |
| |
| Cow::Owned(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 { |
| if !clang_sys::is_loaded() { |
| // TODO(emilio): Return meaningful error (breaking). |
| clang_sys::load().expect("Unable to find libclang"); |
| } |
| |
| 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(), |
| } |
| } |
| |
| /// Test command_line_flag function. |
| #[test] |
| fn commandline_flag_unit_test_function() { |
| //Test 1 |
| let bindings = ::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 = ::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), |
| )); |
| |
| } |