diff options
Diffstat (limited to 'libbindgen/src/lib.rs')
-rw-r--r-- | libbindgen/src/lib.rs | 808 |
1 files changed, 0 insertions, 808 deletions
diff --git a/libbindgen/src/lib.rs b/libbindgen/src/lib.rs deleted file mode 100644 index 60b750de..00000000 --- a/libbindgen/src/lib.rs +++ /dev/null @@ -1,808 +0,0 @@ -//! 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 regex; -#[macro_use] -extern crate lazy_static; - -#[cfg(feature = "logging")] -#[macro_use] -extern crate log; - -#[cfg(not(feature = "logging"))] -#[macro_use] -mod log_stubs; - -// A macro to declare an internal module for which we *must* provide -// documentation for. If we are building with the "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 = "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 chooser; - -#[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, Mutex}; - -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, -} - -impl CodegenConfig { - /// Generate all kinds of items. - pub fn all() -> Self { - CodegenConfig { - functions: true, - types: true, - vars: true, - methods: true, - constructors: true, - } - } - - /// Generate nothing. - pub fn nothing() -> Self { - CodegenConfig { - functions: false, - types: false, - vars: false, - methods: false, - constructors: 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 { - /// Set the input C/C++ header. - pub fn header<T: Into<String>>(mut self, header: T) -> Builder { - let header = header.into(); - self.options.input_header = Some(header); - 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. - 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. - 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. - 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. - 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. - 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. - /// - /// This makes bindgen generate a type that isn't a rust `enum`. - pub fn bitfield_enum<T: AsRef<str>>(mut self, arg: T) -> Builder { - self.options.bitfield_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 - } - - /// 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 - } - - /// 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 auto-namespacing of names if namespaces are disabled. - /// - /// By default, if namespaces are disabled, bindgen tries to mangle the - /// names to from `foo::bar::Baz` to look like `foo_bar_Baz`, instead of - /// just `Baz`. - /// - /// This option disables that behavior. - /// - /// Note that this intentionally doesn't change the names using for - /// whitelisting and blacklisting, that should still be mangled with the - /// namespaces. - /// - /// Note, also, that using this option may cause duplicated names to be - /// generated. - 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 - } - - /// 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 in the generated bindings. - pub fn no_unstable_rust(mut self) -> Builder { - self.options.unstable_rust = false; - 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 `TypeChooser` - /// documentation. - pub fn type_chooser(mut self, cb: Box<chooser::TypeChooser>) -> Self { - self.options.type_chooser = Some(cb); - self - } - - /// Choose what to generate using a CodegenConfig. - pub fn with_codegen_config(mut self, config: CodegenConfig) -> Self { - self.options.codegen_config = config; - 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, - - /// 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, - - /// 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 shold derive Debug trait implementations for C/C++ structures - /// and types. - pub derive_debug: 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>, - - /// 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 type chooser to allow customizing different kinds of - /// situations. - pub type_chooser: Option<Box<chooser::TypeChooser>>, - - /// 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, -} - -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(); - } -} - -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(), - builtins: false, - links: vec![], - emit_ast: false, - emit_ir: false, - derive_debug: true, - enable_cxx_namespaces: false, - disable_name_namespacing: false, - unstable_rust: true, - use_core: false, - ctypes_prefix: None, - namespaced_constants: true, - msvc_mangling: false, - convert_floats: true, - raw_lines: vec![], - clang_args: vec![], - input_header: None, - dummy_uses: None, - type_chooser: None, - codegen_config: CodegenConfig::all(), - conservative_inline_namespaces: false, - } - } -} - -/// 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: Mutex<Option<Arc<clang_sys::SharedLibrary>>> = { - Mutex::new(None) - }; - } - - let mut libclang = LIBCLANG.lock().unwrap(); - if !clang_sys::is_loaded() { - if libclang.is_none() { - // TODO(emilio): Return meaningful error (breaking). - clang_sys::load().expect("Unable to find libclang"); - *libclang = Some(clang_sys::get_library() - .expect("We just loaded libclang and it had \ - better still be here!")); - } else { - clang_sys::set_library(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. - for path in clang.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()) - } - - 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 { - let (file, _, _, _) = cursor.location().location(); - - match file.name() { - None => ctx.options().builtins, - Some(..) => true, - } -} - -/// 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 { - cursor.visit(|cur| clang::ast_dump(&cur, 0)); - } - - 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(), - } -} |