summaryrefslogtreecommitdiff
path: root/libbindgen/src/lib.rs
diff options
context:
space:
mode:
Diffstat (limited to 'libbindgen/src/lib.rs')
-rw-r--r--libbindgen/src/lib.rs611
1 files changed, 611 insertions, 0 deletions
diff --git a/libbindgen/src/lib.rs b/libbindgen/src/lib.rs
new file mode 100644
index 00000000..d0ca7b03
--- /dev/null
+++ b/libbindgen/src/lib.rs
@@ -0,0 +1,611 @@
+//! 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.
+
+#![cfg_attr(feature = "clippy", feature(plugin))]
+#![cfg_attr(feature = "clippy", plugin(clippy))]
+
+#![deny(missing_docs)]
+#![deny(warnings)]
+
+// 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]
+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 libc;
+extern crate regex;
+#[macro_use]
+extern crate log;
+#[macro_use]
+extern crate lazy_static;
+
+// 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 clangll;
+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::borrow::Borrow;
+use std::collections::HashSet;
+use std::fs::OpenOptions;
+use std::io::{self, Write};
+use std::path::Path;
+
+use syntax::ast;
+use syntax::codemap::{DUMMY_SP, Span};
+use syntax::print::pp::eof;
+use syntax::print::pprust;
+use syntax::ptr::P;
+
+/// 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.clone());
+ self.clang_arg(header)
+ }
+
+ /// 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: Into<String>>(mut self, arg: T) -> Builder {
+ self.options.hidden_types.insert(arg.into());
+ self
+ }
+
+ /// Treat the given type as opaque in the generated bindings.
+ pub fn opaque_type<T: Into<String>>(mut self, arg: T) -> Builder {
+ self.options.opaque_types.insert(arg.into());
+ 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: Borrow<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: Borrow<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: Borrow<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: Borrow<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
+ }
+
+ /// Enable C++ namespaces.
+ pub fn enable_cxx_namespaces(mut self) -> Builder {
+ self.options.enable_cxx_namespaces = true;
+ self
+ }
+
+ /// Ignore functions.
+ pub fn ignore_functions(mut self) -> Builder {
+ self.options.ignore_functions = true;
+ self
+ }
+
+ /// Ignore methods.
+ pub fn ignore_methods(mut self) -> Builder {
+ self.options.ignore_methods = true;
+ 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
+ }
+
+ /// 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: HashSet<String>,
+
+ /// The set of types that should be treated as opaque structures in the
+ /// generated code.
+ pub opaque_types: HashSet<String>,
+
+ /// 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 ignore functions and only generate bindings for
+ /// structures, types, and methods.
+ pub ignore_functions: bool,
+
+ /// True if we should avoid generating bindings for methods, and instead
+ /// just generate code for structures and types.
+ pub ignore_methods: bool,
+
+ /// True if we should emulate C++ namespaces with Rust modules in the
+ /// generated bindings.
+ pub enable_cxx_namespaces: 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>>,
+}
+
+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,
+ ignore_functions: false,
+ ignore_methods: false,
+ derive_debug: true,
+ enable_cxx_namespaces: 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,
+ }
+ }
+}
+
+/// 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,
+}
+
+/// 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(options: BindgenOptions,
+ span: Option<Span>)
+ -> Result<Bindings<'ctx>, ()> {
+ let span = span.unwrap_or(DUMMY_SP);
+
+ let mut context = BindgenContext::new(options);
+ 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.
+ // https://github.com/Manishearth/rust-clippy/issues/740
+ #[cfg_attr(feature = "clippy", allow(needless_lifetimes))]
+ 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>,
+ children: &mut Vec<ItemId>)
+ -> clangll::Enum_CXVisitorResult {
+ if !filter_builtins(ctx, &cursor) {
+ return CXChildVisit_Continue;
+ }
+
+ use clangll::CXChildVisit_Continue;
+ match Item::parse(cursor, parent, ctx) {
+ Ok(id) => children.push(id),
+ Err(ParseError::Continue) => {}
+ Err(ParseError::Recurse) => {
+ cursor.visit(|child| parse_one(ctx, child, parent, children));
+ }
+ }
+ CXChildVisit_Continue
+}
+
+/// Parse the Clang AST into our `Item` internal representation.
+fn parse(context: &mut BindgenContext) {
+ use clang::Diagnostic;
+ use clangll::*;
+
+ for d in context.translation_unit().diags().iter() {
+ let msg = d.format(Diagnostic::default_opts());
+ let is_err = d.severity() >= CXDiagnostic_Error;
+ println!("{}, err: {}", msg, is_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, children| {
+ cursor.visit(|cursor| parse_one(context, cursor, None, children))
+ });
+
+ assert!(context.current_module() == context.root_module(),
+ "How did this happen?");
+}
+
+/// 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 {
+ 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(),
+ }
+}