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.rs808
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(),
- }
-}