| //! 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. |
| |
| #![deny(missing_docs)] |
| #![deny(warnings)] |
| #![deny(unused_extern_crates)] |
| |
| // We internally use the deprecated BindgenOptions all over the place. Once we |
| // remove its `pub` declaration, we can un-deprecate it and remove this pragma. |
| #![allow(deprecated)] |
| |
| // To avoid rather annoying warnings when matching with CXCursor_xxx as a |
| // constant. |
| #![allow(non_upper_case_globals)] |
| |
| #[macro_use] |
| #[allow(unused_extern_crates)] |
| extern crate cfg_if; |
| extern crate cexpr; |
| extern crate syntex_syntax as syntax; |
| extern crate aster; |
| extern crate quasi; |
| extern crate clang_sys; |
| extern crate peeking_take_while; |
| extern crate regex; |
| #[macro_use] |
| extern crate lazy_static; |
| |
| #[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 ir; |
| mod parse; |
| mod regex_set; |
| mod uses; |
| |
| pub mod callbacks; |
| |
| #[cfg(rustfmt)] |
| mod codegen; |
| |
| doc_mod!(clang, clang_docs); |
| doc_mod!(ir, ir_docs); |
| doc_mod!(parse, parse_docs); |
| doc_mod!(regex_set, regex_set_docs); |
| doc_mod!(uses, uses_docs); |
| |
| mod codegen { |
| include!(concat!(env!("OUT_DIR"), "/codegen.rs")); |
| } |
| |
| use ir::context::{BindgenContext, ItemId}; |
| use ir::item::Item; |
| use parse::{ClangItemParser, ParseError}; |
| use regex_set::RegexSet; |
| |
| use std::fs::OpenOptions; |
| use std::io::{self, Write}; |
| use std::path::Path; |
| use std::sync::Arc; |
| |
| use syntax::ast; |
| use syntax::codemap::{DUMMY_SP, Span}; |
| use syntax::print::pp::eof; |
| use syntax::print::pprust; |
| use syntax::ptr::P; |
| |
| /// A type used to indicate which kind of items do we have to generate. |
| /// |
| /// TODO(emilio): Use `bitflags!` |
| #[derive(Debug, Clone)] |
| pub struct CodegenConfig { |
| /// Whether to generate functions. |
| pub functions: bool, |
| /// Whether to generate types. |
| pub types: bool, |
| /// Whether to generate constants. |
| pub vars: bool, |
| /// Whether to generate methods. |
| pub methods: bool, |
| /// Whether to generate constructors. |
| pub constructors: bool, |
| /// Whether to generate destructors. |
| pub destructors: bool, |
| } |
| |
| impl CodegenConfig { |
| /// Generate all kinds of items. |
| pub fn all() -> Self { |
| CodegenConfig { |
| functions: true, |
| types: true, |
| vars: true, |
| methods: true, |
| constructors: true, |
| destructors: true, |
| } |
| } |
| |
| /// Generate nothing. |
| pub fn nothing() -> Self { |
| CodegenConfig { |
| functions: false, |
| types: false, |
| vars: false, |
| methods: false, |
| constructors: false, |
| destructors: false, |
| } |
| } |
| } |
| |
| 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 = try!(builder().header("path/to/input/header") |
| /// .whitelisted_type("SomeCoolClass") |
| /// .whitelisted_function("do_some_cool_thing") |
| /// .generate()); |
| /// |
| /// // Write the generated bindings to an output file. |
| /// try!(bindings.write_to_file("path/to/output.rs")); |
| /// ``` |
| #[derive(Debug,Default)] |
| pub struct Builder { |
| options: BindgenOptions, |
| } |
| |
| /// 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(ref header) = self.options.input_header { |
| //Positional argument 'header' |
| output_vector.push(header.clone().into()); |
| } |
| |
| self.options |
| .bitfield_enums |
| .get_items() |
| .iter() |
| .map(|item| { |
| output_vector.push("--bitfield-enum".into()); |
| output_vector.push(item.trim_left_matches("^").trim_right_matches("$").into()); |
| }) |
| .count(); |
| |
| self.options |
| .constified_enums |
| .get_items() |
| .iter() |
| .map(|item| { |
| output_vector.push("--constified-enum".into()); |
| output_vector.push(item.trim_left_matches("^").trim_right_matches("$").into()); |
| }) |
| .count(); |
| |
| self.options |
| .hidden_types |
| .get_items() |
| .iter() |
| .map(|item| { |
| output_vector.push("--blacklist-type".into()); |
| output_vector.push(item.trim_left_matches("^").trim_right_matches("$").into()); |
| }) |
| .count(); |
| |
| if !self.options.layout_tests { |
| output_vector.push("--no-layout-tests".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.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.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 let Some(ref dummy) = self.options.dummy_uses { |
| output_vector.push("--dummy-uses".into()); |
| output_vector.push(dummy.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.disable_name_namespacing { |
| output_vector.push("--disable-name-namespacing".into()); |
| } |
| |
| self.options |
| .links |
| .iter() |
| .map(|&(ref item, _)| { |
| output_vector.push("--framework".into()); |
| output_vector.push(item.trim_left_matches("^").trim_right_matches("$").into()); |
| }) |
| .count(); |
| |
| 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("function".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()); |
| } |
| |
| self.options |
| .links |
| .iter() |
| .map(|&(ref item, _)| { |
| output_vector.push("--clang-args".into()); |
| output_vector.push(item.trim_left_matches("^").trim_right_matches("$").into()); |
| }) |
| .count(); |
| |
| 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.unstable_rust { |
| output_vector.push("--unstable-rust".into()); |
| } |
| |
| self.options |
| .opaque_types |
| .get_items() |
| .iter() |
| .map(|item| { |
| output_vector.push("--opaque-type".into()); |
| output_vector.push(item.trim_left_matches("^").trim_right_matches("$").into()); |
| }) |
| .count(); |
| |
| self.options |
| .raw_lines |
| .iter() |
| .map(|item| { |
| output_vector.push("--raw-line".into()); |
| output_vector.push(item.trim_left_matches("^").trim_right_matches("$").into()); |
| }) |
| .count(); |
| |
| self.options |
| .links |
| .iter() |
| .map(|&(ref item, _)| { |
| output_vector.push("--static".into()); |
| output_vector.push(item.trim_left_matches("^").trim_right_matches("$").into()); |
| }) |
| .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.trim_left_matches("^").trim_right_matches("$").into()); |
| }) |
| .count(); |
| |
| self.options |
| .whitelisted_types |
| .get_items() |
| .iter() |
| .map(|item| { |
| output_vector.push("--whitelist-type".into()); |
| output_vector.push(item.trim_left_matches("^").trim_right_matches("$").into()); |
| }) |
| .count(); |
| |
| self.options |
| .whitelisted_vars |
| .get_items() |
| .iter() |
| .map(|item| { |
| output_vector.push("--whitelist-var".into()); |
| output_vector.push(item.trim_left_matches("^").trim_right_matches("$").into()); |
| }) |
| .count(); |
| |
| if !self.options.clang_args.is_empty() { |
| output_vector.push("--".into()); |
| self.options |
| .clang_args |
| .iter() |
| .cloned() |
| .map(|item| { |
| output_vector.push(item); |
| }) |
| .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 { |
| if let Some(prev_header) = self.options.input_header.take() { |
| self.options.clang_args.push("-include".into()); |
| self.options.clang_args.push(prev_header); |
| } |
| |
| let header = header.into(); |
| self.options.input_header = Some(header); |
| 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.options.input_unsaved_files.push(clang::UnsavedFile::new(name, contents)); |
| 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/servo/rust-bindgen/issues/426 |
| pub fn generate_comments(mut self, doit: bool) -> Self { |
| self.options.generate_comments = doit; |
| self |
| } |
| |
| /// Whether to whitelist types recursively or not. Defaults to true. |
| /// |
| /// This can be used to get bindgen to generate _exactly_ the types you want |
| /// in your bindings, and then import other types manually via other means |
| /// (like [`raw_line`](#method.raw_line)). |
| 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 |
| } |
| |
| /// 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/servo/rust-bindgen/issues/528 |
| pub fn trust_clang_mangling(mut self, doit: bool) -> Self { |
| self.options.enable_mangling = doit; |
| self |
| } |
| |
| /// Generate a C/C++ file that includes the header and has dummy uses of |
| /// every type defined in the header. |
| pub fn dummy_uses<T: Into<String>>(mut self, dummy_uses: T) -> Builder { |
| self.options.dummy_uses = Some(dummy_uses.into()); |
| self |
| } |
| |
| /// Hide the given type from the generated bindings. Regular expressions are |
| /// supported. |
| pub fn hide_type<T: AsRef<str>>(mut self, arg: T) -> Builder { |
| self.options.hidden_types.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. |
| pub fn whitelisted_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 whitelisted_function<T: AsRef<str>>(mut self, arg: T) -> Builder { |
| self.options.whitelisted_functions.insert(arg); |
| self |
| } |
| |
| /// 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 whitelisted_var<T: AsRef<str>>(mut self, arg: T) -> Builder { |
| self.options.whitelisted_vars.insert(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 being |
| /// constant. |
| /// |
| /// This makes bindgen generate constants instead of enums. Regular |
| /// expressions are supported. |
| pub fn constified_enum<T: AsRef<str>>(mut self, arg: T) -> Builder { |
| self.options.constified_enums.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) -> Builder { |
| self.options.raw_lines.push(arg.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 |
| } |
| |
| /// Make the generated bindings link the given shared library. |
| pub fn link<T: Into<String>>(mut self, library: T) -> Builder { |
| self.options.links.push((library.into(), LinkType::Default)); |
| self |
| } |
| |
| /// Make the generated bindings link the given static library. |
| pub fn link_static<T: Into<String>>(mut self, library: T) -> Builder { |
| self.options.links.push((library.into(), LinkType::Static)); |
| self |
| } |
| |
| /// Make the generated bindings link the given framework. |
| pub fn link_framework<T: Into<String>>(mut self, library: T) -> Builder { |
| self.options.links.push((library.into(), LinkType::Framework)); |
| 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 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 |
| } |
| |
| /// 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 |
| } |
| |
| /// 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.functions = false; |
| self |
| } |
| |
| /// Ignore methods. |
| pub fn ignore_methods(mut self) -> Builder { |
| self.options.codegen_config.methods = false; |
| self |
| } |
| |
| /// Avoid generating any unstable Rust, such as Rust unions, in the generated bindings. |
| pub fn unstable_rust(mut self, doit: bool) -> Self { |
| self.options.unstable_rust = doit; |
| self |
| } |
| |
| /// Use core instead of libstd in the generated bindings. |
| pub fn use_core(mut self) -> Builder { |
| self.options.use_core = true; |
| self |
| } |
| |
| /// Use the given prefix for the raw types instead of `::std::os::raw`. |
| pub fn ctypes_prefix<T: Into<String>>(mut self, prefix: T) -> Builder { |
| self.options.ctypes_prefix = Some(prefix.into()); |
| self |
| } |
| |
| /// 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 |
| } |
| |
| /// Generate the Rust bindings using the options built up thus far. |
| pub fn generate<'ctx>(self) -> Result<Bindings<'ctx>, ()> { |
| Bindings::generate(self.options, None) |
| } |
| } |
| |
| /// Configuration options for generated bindings. |
| /// |
| /// Deprecated: use a `Builder` instead. |
| #[derive(Debug)] |
| #[deprecated] |
| pub struct BindgenOptions { |
| /// The set of types that have been blacklisted and should not appear |
| /// anywhere in the generated code. |
| pub hidden_types: RegexSet, |
| |
| /// The set of types that should be treated as opaque structures in the |
| /// generated code. |
| pub opaque_types: RegexSet, |
| |
| /// 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. |
| pub whitelisted_types: RegexSet, |
| |
| /// Whitelisted functions. See docs for `whitelisted_types` for more. |
| pub whitelisted_functions: RegexSet, |
| |
| /// Whitelisted variables. See docs for `whitelisted_types` for more. |
| pub whitelisted_vars: RegexSet, |
| |
| /// The enum patterns to mark an enum as bitfield. |
| pub bitfield_enums: RegexSet, |
| |
| /// The enum patterns to mark an enum as constant. |
| pub constified_enums: RegexSet, |
| |
| /// Whether we should generate builtins or not. |
| pub builtins: bool, |
| |
| /// The set of libraries we should link in the generated Rust code. |
| pub links: Vec<(String, LinkType)>, |
| |
| /// True if we should dump the Clang AST for debugging purposes. |
| pub emit_ast: bool, |
| |
| /// True if we should dump our internal IR for debugging purposes. |
| pub emit_ir: bool, |
| |
| /// Output graphviz dot file. |
| pub emit_ir_graphviz: Option<String>, |
| |
| /// True if we should emulate C++ namespaces with Rust modules in the |
| /// generated bindings. |
| pub enable_cxx_namespaces: bool, |
| |
| /// True if we should avoid mangling names with namespaces. |
| pub disable_name_namespacing: bool, |
| |
| /// True if we should generate layout tests for generated structures. |
| pub layout_tests: bool, |
| |
| /// True if we should derive Debug trait implementations for C/C++ structures |
| /// and types. |
| pub derive_debug: bool, |
| |
| /// True if we should derive Default trait implementations for C/C++ structures |
| /// and types. |
| pub derive_default: bool, |
| |
| /// True if we can use unstable Rust code in the bindings, false if we |
| /// cannot. |
| pub unstable_rust: bool, |
| |
| /// True if we should avoid using libstd to use libcore instead. |
| pub use_core: bool, |
| |
| /// An optional prefix for the "raw" types, like `c_int`, `c_void`... |
| pub ctypes_prefix: Option<String>, |
| |
| /// True if we should generate constant names that are **directly** under |
| /// namespaces. |
| pub namespaced_constants: bool, |
| |
| /// True if we should use MSVC name mangling rules. |
| pub msvc_mangling: bool, |
| |
| /// Whether we should convert float types to f32/f64 types. |
| pub convert_floats: bool, |
| |
| /// The set of raw lines to prepend to the generated Rust code. |
| pub raw_lines: Vec<String>, |
| |
| /// The set of arguments to pass straight through to Clang. |
| pub clang_args: Vec<String>, |
| |
| /// The input header file. |
| pub input_header: Option<String>, |
| |
| /// Unsaved files for input. |
| pub input_unsaved_files: Vec<clang::UnsavedFile>, |
| |
| /// Generate a dummy C/C++ file that includes the header and has dummy uses |
| /// of all types defined therein. See the `uses` module for more. |
| pub dummy_uses: Option<String>, |
| |
| /// A user-provided visitor to allow customizing different kinds of |
| /// situations. |
| pub parse_callbacks: Option<Box<callbacks::ParseCallbacks>>, |
| |
| /// Which kind of items should we generate? By default, we'll generate all |
| /// of them. |
| pub codegen_config: CodegenConfig, |
| |
| /// Whether to treat inline namespaces conservatively. |
| /// |
| /// See the builder method description for more details. |
| pub conservative_inline_namespaces: bool, |
| |
| /// Wether to keep documentation comments in the generated output. See the |
| /// documentation for more details. |
| pub generate_comments: bool, |
| |
| /// Whether to generate inline functions. Defaults to false. |
| pub generate_inline_functions: bool, |
| |
| /// Wether to whitelist types recursively. Defaults to true. |
| pub whitelist_recursively: bool, |
| |
| /// Intead of emitting 'use objc;' to files generated from objective c files, |
| /// generate '#[macro_use] extern crate objc;' |
| pub objc_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/servo/rust-bindgen/issues/528 |
| pub enable_mangling: bool, |
| |
| /// Whether to prepend the enum name to bitfield or constant variants. |
| pub prepend_enum_name: bool, |
| } |
| |
| /// 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) { |
| self.whitelisted_vars.build(); |
| self.whitelisted_types.build(); |
| self.whitelisted_functions.build(); |
| self.hidden_types.build(); |
| self.opaque_types.build(); |
| self.bitfield_enums.build(); |
| self.constified_enums.build(); |
| } |
| } |
| |
| impl Default for BindgenOptions { |
| fn default() -> BindgenOptions { |
| BindgenOptions { |
| hidden_types: Default::default(), |
| opaque_types: Default::default(), |
| whitelisted_types: Default::default(), |
| whitelisted_functions: Default::default(), |
| whitelisted_vars: Default::default(), |
| bitfield_enums: Default::default(), |
| constified_enums: Default::default(), |
| builtins: false, |
| links: vec![], |
| emit_ast: false, |
| emit_ir: false, |
| emit_ir_graphviz: None, |
| layout_tests: true, |
| derive_debug: true, |
| derive_default: false, |
| enable_cxx_namespaces: false, |
| disable_name_namespacing: false, |
| unstable_rust: false, |
| use_core: false, |
| ctypes_prefix: None, |
| namespaced_constants: true, |
| msvc_mangling: false, |
| convert_floats: true, |
| raw_lines: vec![], |
| clang_args: vec![], |
| input_header: None, |
| input_unsaved_files: vec![], |
| dummy_uses: None, |
| parse_callbacks: None, |
| codegen_config: CodegenConfig::all(), |
| conservative_inline_namespaces: false, |
| generate_comments: true, |
| generate_inline_functions: false, |
| whitelist_recursively: true, |
| objc_extern_crate: false, |
| enable_mangling: true, |
| prepend_enum_name: true, |
| } |
| } |
| } |
| |
| /// The linking type to use with a given library. |
| /// |
| /// TODO: #104: This is ignored at the moment, but shouldn't be. |
| #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] |
| pub enum LinkType { |
| /// Use shared library linking. This is the default. |
| Default, |
| /// Use static linking. |
| Static, |
| /// The library is an OSX framework. |
| Framework, |
| } |
| |
| 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<'ctx> { |
| context: BindgenContext<'ctx>, |
| module: ast::Mod, |
| } |
| |
| impl<'ctx> Bindings<'ctx> { |
| /// Generate bindings for the given options. |
| /// |
| /// Deprecated - use a `Builder` instead |
| #[deprecated] |
| pub fn generate(mut options: BindgenOptions, |
| span: Option<Span>) |
| -> Result<Bindings<'ctx>, ()> { |
| let span = span.unwrap_or(DUMMY_SP); |
| ensure_libclang_is_loaded(); |
| |
| options.build(); |
| |
| // TODO: Make this path fixup configurable? |
| if let Some(clang) = clang_sys::support::Clang::find(None) { |
| // 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 { |
| // TODO: distinguish C and C++ paths? C++'s should be enough, I |
| // guess. |
| if let Some(cpp_search_paths) = clang.cpp_search_paths { |
| for path in cpp_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); |
| } |
| } |
| } |
| } |
| } |
| |
| if let Some(h) = options.input_header.as_ref() { |
| options.clang_args.push(h.clone()) |
| } |
| |
| for f in options.input_unsaved_files.iter() { |
| options.clang_args.push(f.name.to_str().unwrap().to_owned()) |
| } |
| |
| let mut context = BindgenContext::new(options); |
| try!(parse(&mut context)); |
| |
| let module = ast::Mod { |
| inner: span, |
| items: codegen::codegen(&mut context), |
| }; |
| |
| Ok(Bindings { |
| context: context, |
| module: module, |
| }) |
| } |
| |
| /// Convert these bindings into a Rust AST. |
| pub fn into_ast(self) -> Vec<P<ast::Item>> { |
| self.module.items |
| } |
| |
| /// Convert these bindings into source text (with raw lines prepended). |
| pub fn to_string(&self) -> String { |
| let mut mod_str = vec![]; |
| { |
| let ref_writer = Box::new(mod_str.by_ref()) as Box<Write>; |
| self.write(ref_writer).expect("Could not write bindings to string"); |
| } |
| String::from_utf8(mod_str).unwrap() |
| } |
| |
| /// Write these bindings as source text to a file. |
| pub fn write_to_file<P: AsRef<Path>>(&self, path: P) -> io::Result<()> { |
| let file = try!(OpenOptions::new() |
| .write(true) |
| .truncate(true) |
| .create(true) |
| .open(path)); |
| self.write(Box::new(file)) |
| } |
| |
| /// Write these bindings as source text to the given `Write`able. |
| pub fn write<'a>(&self, mut writer: Box<Write + 'a>) -> io::Result<()> { |
| try!(writer.write("/* automatically generated by rust-bindgen */\n\n" |
| .as_bytes())); |
| |
| for line in self.context.options().raw_lines.iter() { |
| try!(writer.write(line.as_bytes())); |
| try!(writer.write("\n".as_bytes())); |
| } |
| if !self.context.options().raw_lines.is_empty() { |
| try!(writer.write("\n".as_bytes())); |
| } |
| |
| let mut ps = pprust::rust_printer(writer); |
| try!(ps.print_mod(&self.module, &[])); |
| try!(ps.print_remaining_comments()); |
| try!(eof(&mut ps.s)); |
| ps.s.out.flush() |
| } |
| |
| /// Generate and write dummy uses of all the types we parsed, if we've been |
| /// requested to do so in the options. |
| /// |
| /// See the `uses` module for more information. |
| pub fn write_dummy_uses(&mut self) -> io::Result<()> { |
| let file = if let Some(ref dummy_path) = |
| self.context.options().dummy_uses { |
| Some(try!(OpenOptions::new() |
| .write(true) |
| .truncate(true) |
| .create(true) |
| .open(dummy_path))) |
| } else { |
| None |
| }; |
| |
| if let Some(file) = file { |
| try!(uses::generate_dummy_uses(&mut self.context, file)); |
| } |
| |
| Ok(()) |
| } |
| } |
| |
| /// 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. |
| pub 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; |
| println!("{}, 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 semvar, if parsing was successful |
| pub parsed: Option<(u32, u32)>, |
| /// full version string |
| pub full: String, |
| } |
| |
| /// Get the major and the minor semvar 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!["--no-derive-default", |
| "--generate", "function,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") |
| .whitelisted_type("Distinct_Type") |
| .whitelisted_function("safe_function"); |
| |
| let command_line_flags = bindings.command_line_flags(); |
| let test_cases = vec!["input_header", |
| "--no-derive-default", |
| "--generate", "function,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)) ); |
| |
| } |