#![deny(missing_docs)]
#![deny(warnings)]
#![deny(unused_extern_crates)]
#![allow(deprecated)]
#![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;
macro_rules! doc_mod {
($m:ident, $doc_mod_name:ident) => {
cfg_if! {
if #[cfg(feature = "docs_")] {
pub mod $doc_mod_name {
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;
#[derive(Debug, Clone)]
pub struct CodegenConfig {
pub functions: bool,
pub types: bool,
pub vars: bool,
pub methods: bool,
pub constructors: bool,
}
impl CodegenConfig {
pub fn all() -> Self {
CodegenConfig {
functions: true,
types: true,
vars: true,
methods: true,
constructors: true,
}
}
pub fn nothing() -> Self {
CodegenConfig {
functions: false,
types: false,
vars: false,
methods: false,
constructors: false,
}
}
}
impl Default for CodegenConfig {
fn default() -> Self {
CodegenConfig::all()
}
}
#[derive(Debug,Default)]
pub struct Builder {
options: BindgenOptions,
}
pub fn builder() -> Builder {
Default::default()
}
impl Builder {
pub fn header<T: Into<String>>(mut self, header: T) -> Builder {
let header = header.into();
self.options.input_header = Some(header);
self
}
pub fn generate_comments(mut self, doit: bool) -> Self {
self.options.generate_comments = doit;
self
}
pub fn whitelist_recursively(mut self, doit: bool) -> Self {
self.options.whitelist_recursively = doit;
self
}
pub fn objc_extern_crate(mut self, doit: bool) -> Self {
self.options.objc_extern_crate = doit;
self
}
pub fn dummy_uses<T: Into<String>>(mut self, dummy_uses: T) -> Builder {
self.options.dummy_uses = Some(dummy_uses.into());
self
}
pub fn hide_type<T: AsRef<str>>(mut self, arg: T) -> Builder {
self.options.hidden_types.insert(arg);
self
}
pub fn opaque_type<T: AsRef<str>>(mut self, arg: T) -> Builder {
self.options.opaque_types.insert(arg);
self
}
pub fn whitelisted_type<T: AsRef<str>>(mut self, arg: T) -> Builder {
self.options.whitelisted_types.insert(arg);
self
}
pub fn whitelisted_function<T: AsRef<str>>(mut self, arg: T) -> Builder {
self.options.whitelisted_functions.insert(arg);
self
}
pub fn whitelisted_var<T: AsRef<str>>(mut self, arg: T) -> Builder {
self.options.whitelisted_vars.insert(arg);
self
}
pub fn bitfield_enum<T: AsRef<str>>(mut self, arg: T) -> Builder {
self.options.bitfield_enums.insert(arg);
self
}
pub fn constified_enum<T: AsRef<str>>(mut self, arg: T) -> Builder {
self.options.constified_enums.insert(arg);
self
}
pub fn raw_line<T: Into<String>>(mut self, arg: T) -> Builder {
self.options.raw_lines.push(arg.into());
self
}
pub fn clang_arg<T: Into<String>>(mut self, arg: T) -> Builder {
self.options.clang_args.push(arg.into());
self
}
pub fn link<T: Into<String>>(mut self, library: T) -> Builder {
self.options.links.push((library.into(), LinkType::Default));
self
}
pub fn link_static<T: Into<String>>(mut self, library: T) -> Builder {
self.options.links.push((library.into(), LinkType::Static));
self
}
pub fn link_framework<T: Into<String>>(mut self, library: T) -> Builder {
self.options.links.push((library.into(), LinkType::Framework));
self
}
pub fn emit_builtins(mut self) -> Builder {
self.options.builtins = true;
self
}
pub fn no_convert_floats(mut self) -> Self {
self.options.convert_floats = false;
self
}
pub fn derive_debug(mut self, doit: bool) -> Self {
self.options.derive_debug = doit;
self
}
pub fn emit_clang_ast(mut self) -> Builder {
self.options.emit_ast = true;
self
}
pub fn emit_ir(mut self) -> Builder {
self.options.emit_ir = true;
self
}
pub fn enable_cxx_namespaces(mut self) -> Builder {
self.options.enable_cxx_namespaces = true;
self
}
pub fn disable_name_namespacing(mut self) -> Builder {
self.options.disable_name_namespacing = true;
self
}
pub fn conservative_inline_namespaces(mut self) -> Builder {
self.options.conservative_inline_namespaces = true;
self
}
pub fn ignore_functions(mut self) -> Builder {
self.options.codegen_config.functions = false;
self
}
pub fn ignore_methods(mut self) -> Builder {
self.options.codegen_config.methods = false;
self
}
pub fn no_unstable_rust(mut self) -> Builder {
self.options.unstable_rust = false;
self
}
pub fn use_core(mut self) -> Builder {
self.options.use_core = true;
self
}
pub fn ctypes_prefix<T: Into<String>>(mut self, prefix: T) -> Builder {
self.options.ctypes_prefix = Some(prefix.into());
self
}
pub fn type_chooser(mut self, cb: Box<chooser::TypeChooser>) -> Self {
self.options.type_chooser = Some(cb);
self
}
pub fn with_codegen_config(mut self, config: CodegenConfig) -> Self {
self.options.codegen_config = config;
self
}
pub fn generate<'ctx>(self) -> Result<Bindings<'ctx>, ()> {
Bindings::generate(self.options, None)
}
}
#[derive(Debug)]
#[deprecated]
pub struct BindgenOptions {
pub hidden_types: RegexSet,
pub opaque_types: RegexSet,
pub whitelisted_types: RegexSet,
pub whitelisted_functions: RegexSet,
pub whitelisted_vars: RegexSet,
pub bitfield_enums: RegexSet,
pub constified_enums: RegexSet,
pub builtins: bool,
pub links: Vec<(String, LinkType)>,
pub emit_ast: bool,
pub emit_ir: bool,
pub enable_cxx_namespaces: bool,
pub disable_name_namespacing: bool,
pub derive_debug: bool,
pub unstable_rust: bool,
pub use_core: bool,
pub ctypes_prefix: Option<String>,
pub namespaced_constants: bool,
pub msvc_mangling: bool,
pub convert_floats: bool,
pub raw_lines: Vec<String>,
pub clang_args: Vec<String>,
pub input_header: Option<String>,
pub dummy_uses: Option<String>,
pub type_chooser: Option<Box<chooser::TypeChooser>>,
pub codegen_config: CodegenConfig,
pub conservative_inline_namespaces: bool,
pub generate_comments: bool,
pub whitelist_recursively: bool,
pub objc_extern_crate: 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();
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,
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,
generate_comments: true,
whitelist_recursively: true,
objc_extern_crate: false,
}
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub enum LinkType {
Default,
Static,
Framework,
}
fn ensure_libclang_is_loaded() {
if clang_sys::is_loaded() {
return;
}
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() {
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());
}
}
}
#[derive(Debug)]
pub struct Bindings<'ctx> {
context: BindgenContext<'ctx>,
module: ast::Mod,
}
impl<'ctx> Bindings<'ctx> {
#[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();
if let Some(clang) = clang_sys::support::Clang::find(None) {
let has_target_arg = options.clang_args
.iter()
.rposition(|arg| arg.starts_with("--target"))
.is_some();
if !has_target_arg {
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,
})
}
pub fn into_ast(self) -> Vec<P<ast::Item>> {
self.module.items
}
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()
}
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))
}
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()
}
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(())
}
}
fn filter_builtins(ctx: &BindgenContext, cursor: &clang::Cursor) -> bool {
let (file, _, _, _) = cursor.location().location();
match file.name() {
None => ctx.options().builtins,
Some(..) => true,
}
}
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
}
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(())
}
#[derive(Debug)]
pub struct ClangVersion {
pub parsed: Option<(u32, u32)>,
pub full: String,
}
pub fn clang_version() -> ClangVersion {
if !clang_sys::is_loaded() {
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(),
}
}