diff options
-rw-r--r-- | .travis.yml | 1 | ||||
-rw-r--r-- | libbindgen/build.rs | 39 | ||||
-rw-r--r-- | libbindgen/src/clang.rs | 14 | ||||
-rw-r--r-- | libbindgen/src/codegen/mod.rs | 23 | ||||
-rw-r--r-- | libbindgen/src/lib.rs | 10 | ||||
-rw-r--r-- | libbindgen/tests/tests.rs | 58 | ||||
-rw-r--r-- | src/options.rs | 7 |
7 files changed, 99 insertions, 53 deletions
diff --git a/.travis.yml b/.travis.yml index 98073e00..17beccc6 100644 --- a/.travis.yml +++ b/.travis.yml @@ -12,7 +12,6 @@ os: rust: - stable - - nightly env: - CARGO_TARGET_DIR=/tmp/bindgen LLVM_VERSION=3.8 BINDGEN_FEATURES=llvm_stable diff --git a/libbindgen/build.rs b/libbindgen/build.rs index b9cf3e60..228a7f22 100644 --- a/libbindgen/build.rs +++ b/libbindgen/build.rs @@ -1,10 +1,9 @@ mod codegen { extern crate quasi_codegen; use std::path::Path; - use std::env; pub fn main() { - let out_dir = env::var_os("OUT_DIR").unwrap(); + let out_dir = Path::new(env!("OUT_DIR")); let src = Path::new("src/codegen/mod.rs"); let dst = Path::new(&out_dir).join("codegen.rs"); @@ -14,6 +13,42 @@ mod codegen { } } +mod testgen { + use std::char; + use std::ffi::OsStr; + use std::fs::{self, File}; + use std::io::Write; + use std::path::Path; + + pub fn main() { + let out_dir = Path::new(env!("OUT_DIR")); + let mut dst = File::create(Path::new(&out_dir).join("tests.rs")).unwrap(); + + let manifest_dir = Path::new(env!("CARGO_MANIFEST_DIR")); + let headers_dir = manifest_dir.join("tests").join("headers"); + + let entries = fs::read_dir(headers_dir) + .expect("Couldn't read headers dir") + .map(|result| result.expect("Couldn't read header file")); + + for entry in entries { + match entry.path().extension().and_then(OsStr::to_str) { + Some("h") | Some("hpp") => { + let func = entry.file_name().to_str().unwrap() + .replace(|c| !char::is_alphanumeric(c), "_") + .replace("__", "_") + .to_lowercase(); + let _ = writeln!(dst, "test_header!(header_{}, {:?});", + func, entry.path()); + } + _ => {} + } + } + let _ = dst.flush(); + } +} + fn main() { codegen::main(); + testgen::main(); } diff --git a/libbindgen/src/clang.rs b/libbindgen/src/clang.rs index 7da755ea..d10457b3 100644 --- a/libbindgen/src/clang.rs +++ b/libbindgen/src/clang.rs @@ -1235,21 +1235,23 @@ pub fn type_to_str(x: Enum_CXTypeKind) -> String { /// Dump the Clang AST to stdout for debugging purposes. pub fn ast_dump(c: &Cursor, depth: isize) -> Enum_CXVisitorResult { fn print_indent(depth: isize, s: &str) { - let mut i = 0; - while i < depth { + for _ in 0..depth { print!("\t"); - i += 1; } println!("{}", s); } - let ct = c.cur_type().kind(); + print_indent(depth, - &format!("({} {} {}", + &format!("(kind: {}, spelling: {}, type: {}", kind_to_str(c.kind()), c.spelling(), - type_to_str(ct))); + type_to_str(c.cur_type().kind()))); + + // Recurse. c.visit(|s| ast_dump(&s, depth + 1)); + print_indent(depth, ")"); + CXChildVisit_Continue } diff --git a/libbindgen/src/codegen/mod.rs b/libbindgen/src/codegen/mod.rs index 8e04fd7c..99ec56f4 100644 --- a/libbindgen/src/codegen/mod.rs +++ b/libbindgen/src/codegen/mod.rs @@ -228,9 +228,12 @@ impl CodeGenerator for Item { result: &mut CodegenResult, _extra: &()) { if self.is_hidden(ctx) || result.seen(self.id()) { + debug!("<Item as CodeGenerator>::codegen: Ignoring hidden or seen: self = {:?}", self); return; } + debug!("<Item as CodeGenerator>::codegen: self = {:?}", self); + result.set_seen(self.id()); match *self.kind() { @@ -264,6 +267,8 @@ impl CodeGenerator for Module { ctx: &BindgenContext, result: &mut CodegenResult, item: &Item) { + debug!("<Module as CodeGenerator>::codegen: item = {:?}", item); + if !ctx.options().enable_cxx_namespaces { for child in self.children() { ctx.resolve_item(*child).codegen(ctx, result, &()); @@ -299,6 +304,8 @@ impl CodeGenerator for Var { ctx: &BindgenContext, result: &mut CodegenResult, item: &Item) { + debug!("<Var as CodeGenerator>::codegen: item = {:?}", item); + let canonical_name = item.canonical_name(ctx); if result.seen_var(&canonical_name) { @@ -349,6 +356,8 @@ impl CodeGenerator for Type { ctx: &BindgenContext, result: &mut CodegenResult, item: &Item) { + debug!("<Type as CodeGenerator>::codegen: item = {:?}", item); + match *self.kind() { TypeKind::Void | TypeKind::NullPtr | @@ -600,6 +609,9 @@ impl CodeGenerator for CompInfo { result: &mut CodegenResult, item: &Item) { use aster::struct_field::StructFieldBuilder; + + debug!("<CompInfo as CodeGenerator>::codegen: item = {:?}", item); + // Don't output classes with template parameters that aren't types, and // also don't output template specializations, neither total or partial. // @@ -1361,6 +1373,8 @@ impl CodeGenerator for Enum { ctx: &BindgenContext, result: &mut CodegenResult, item: &Item) { + debug!("<Enum as CodeGenerator>::codegen: item = {:?}", item); + let name = item.canonical_name(ctx); let enum_ty = item.expect_type(); let layout = enum_ty.layout(ctx); @@ -1800,6 +1814,8 @@ impl CodeGenerator for Function { ctx: &BindgenContext, result: &mut CodegenResult, item: &Item) { + debug!("<Function as CodeGenerator>::codegen: item = {:?}", item); + let name = self.name(); let mut canonical_name = item.canonical_name(ctx); let mangled_name = self.mangled_name(); @@ -1892,6 +1908,13 @@ pub fn codegen(context: &mut BindgenContext) -> Vec<P<ast::Item>> { let whitelisted_items: ItemSet = context.whitelisted_items().collect(); + if context.options().emit_ir { + for &id in whitelisted_items.iter() { + let item = context.resolve_item(id); + println!("ir: {:?} = {:#?}", id, item); + } + } + for &id in whitelisted_items.iter() { let item = context.resolve_item(id); diff --git a/libbindgen/src/lib.rs b/libbindgen/src/lib.rs index d0ca7b03..e4923b77 100644 --- a/libbindgen/src/lib.rs +++ b/libbindgen/src/lib.rs @@ -225,6 +225,12 @@ impl Builder { 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; @@ -314,6 +320,9 @@ pub struct BindgenOptions { /// 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 ignore functions and only generate bindings for /// structures, types, and methods. pub ignore_functions: bool, @@ -380,6 +389,7 @@ impl Default for BindgenOptions { builtins: false, links: vec![], emit_ast: false, + emit_ir: false, ignore_functions: false, ignore_methods: false, derive_debug: true, diff --git a/libbindgen/tests/tests.rs b/libbindgen/tests/tests.rs index c9826260..c0786406 100644 --- a/libbindgen/tests/tests.rs +++ b/libbindgen/tests/tests.rs @@ -6,10 +6,9 @@ extern crate libbindgen; extern crate log; extern crate shlex; -use std::env; use std::fs; use std::io::{BufRead, BufReader, Error, ErrorKind, Read}; -use std::path::{Path, PathBuf}; +use std::path::PathBuf; #[path="../../src/options.rs"] mod options; @@ -93,46 +92,17 @@ fn create_bindgen_builder(header: &PathBuf) builder_from_flags(args).map(|(builder, _)| builder.no_unstable_rust()) } -#[test] -fn run_bindgen_tests() { - log::set_logger(|max_log_level| { - use env_logger::Logger; - let env_logger = Logger::new(); - max_log_level.set(env_logger.filter()); - Box::new(env_logger) - }) - .expect("Failed to set logger."); - - let manifest_env = env::var("CARGO_MANIFEST_DIR") - .expect("CARGO_MANIFEST_DIR not set!"); - let manifest_dir = Path::new(&manifest_env); - let headers_dir = manifest_dir.join("tests").join("headers"); - - let entries = fs::read_dir(&headers_dir) - .expect("Couldn't read headers dir") - .map(|result| result.expect("Couldn't read header file")); - - let headers: Vec<_> = entries.filter_map(|entry| { - match entry.path().extension().and_then(|s| s.to_str()) { - Some("h") | Some("hpp") => Some(entry.path()), - _ => None, - } - }) - .collect(); - - let failures: Vec<_> = headers.iter() - .filter_map(|header| { - create_bindgen_builder(header) - .and_then(|builder| compare_generated_header(header, builder)) - .err() - }) - .collect(); - - let num_failures = failures.len(); - - if num_failures > 0 { - panic!("{} test{} failed!", - num_failures, - if num_failures > 1 {"s"} else {""}); - } +macro_rules! test_header { + ($function:ident, $header:expr) => ( + #[test] + fn $function() { + let header = PathBuf::from($header); + let _ = create_bindgen_builder(&header) + .and_then(|builder| compare_generated_header(&header, builder)) + .map_err(|err| panic!(format!("{}", err)) ); + } + ) } + +// This file is generated by build.rs +include!(concat!(env!("OUT_DIR"), "/tests.rs")); diff --git a/src/options.rs b/src/options.rs index c3c6a1f2..2ea74a27 100644 --- a/src/options.rs +++ b/src/options.rs @@ -52,6 +52,9 @@ pub fn builder_from_flags<I>(args: I) Arg::with_name("emit-clang-ast") .long("emit-clang-ast") .help("Output the Clang AST for debugging purposes."), + Arg::with_name("emit-ir") + .long("emit-ir") + .help("Output our internal IR for debugging purposes."), Arg::with_name("enable-cxx-namespaces") .long("enable-cxx-namespaces") .help("Enable support for C++ namespaces."), @@ -183,6 +186,10 @@ pub fn builder_from_flags<I>(args: I) builder = builder.emit_clang_ast(); } + if matches.is_present("emit-ir") { + builder = builder.emit_ir(); + } + if matches.is_present("enable-cxx-namespaces") { builder = builder.enable_cxx_namespaces(); } |