diff options
-rw-r--r-- | Cargo.toml | 3 | ||||
-rw-r--r-- | src/bin/bindgen.rs | 13 | ||||
-rw-r--r-- | src/gen.rs | 138 | ||||
-rw-r--r-- | src/lib.rs | 74 |
4 files changed, 95 insertions, 133 deletions
@@ -14,7 +14,8 @@ build = "build.rs" clippy = { version = "*", optional = true } log = "0.3.*" libc = "0.2.*" -syntex_syntax = "0.32" +syntex_syntax = "0.37" +clang-sys = "0.7.2" [features] static = [] diff --git a/src/bin/bindgen.rs b/src/bin/bindgen.rs index fd0a7ffe..228c5f95 100644 --- a/src/bin/bindgen.rs +++ b/src/bin/bindgen.rs @@ -4,6 +4,7 @@ extern crate bindgen; #[macro_use] extern crate log; +extern crate clang_sys; use bindgen::{Bindings, BindgenOptions, LinkType, Logger}; use std::io; @@ -214,12 +215,14 @@ pub fn main() { let mut bind_args: Vec<_> = env::args().collect(); let bin = bind_args.remove(0); - match bindgen::get_include_dir() { - Some(path) => { - bind_args.push("-I".to_owned()); - bind_args.push(path); + if let Some(clang) = clang_sys::support::Clang::find(None) { + // 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() { + bind_args.push("-isystem".to_owned()); + bind_args.push(path); + } } - None => (), } match parse_args(&bind_args) { @@ -150,21 +150,17 @@ fn enum_name(ctx: &GenCtx, name: &str) -> String { fn gen_unmangle_method(ctx: &mut GenCtx, v: &VarInfo, counts: &mut HashMap<String, isize>, - self_kind: ast::SelfKind) + self_kind: Option<ast::Mutability>) -> ast::ImplItem { - let fndecl; + let mut fndecl; let mut args = vec![]; - match self_kind { - ast::SelfKind::Static => (), - ast::SelfKind::Region(_, mutable, _) => { - let selfexpr = match mutable { - ast::Mutability::Immutable => quote_expr!(&ctx.ext_cx, &*self), - ast::Mutability::Mutable => quote_expr!(&ctx.ext_cx, &mut *self), - }; - args.push(selfexpr); - }, - _ => unreachable!() + if let Some(mutability) = self_kind { + let selfexpr = match mutability { + ast::Mutability::Immutable => quote_expr!(&ctx.ext_cx, &*self), + ast::Mutability::Mutable => quote_expr!(&ctx.ext_cx, &mut *self), + }; + args.push(selfexpr); } match v.ty { @@ -173,13 +169,12 @@ fn gen_unmangle_method(ctx: &mut GenCtx, &*sig.ret_ty, sig.args.as_slice(), false); let mut unnamed: usize = 0; - let iter = if args.len() > 0 { + let iter = if !args.is_empty() { sig.args[1..].iter() } else { sig.args.iter() }; - for arg in iter { - let (ref n, _) = *arg; + for &(ref n, _) in iter { let argname = if n.is_empty() { unnamed += 1; format!("arg{}", unnamed) @@ -197,7 +192,7 @@ fn gen_unmangle_method(ctx: &mut GenCtx, }) }), span: ctx.span, - attrs: None, + attrs: ast::ThinVec::new(), }; args.push(P(expr)); } @@ -205,38 +200,71 @@ fn gen_unmangle_method(ctx: &mut GenCtx, _ => unreachable!() }; + + if let Some(mutability) = self_kind { + assert!(!fndecl.inputs.is_empty()); + fndecl.inputs[0] = ast::Arg { + ty: P(ast::Ty { + id: ast::DUMMY_NODE_ID, + node: ast::TyKind::Rptr(None, ast::MutTy { + ty: P(ast::Ty { + id: ast::DUMMY_NODE_ID, + node: ast::TyKind::ImplicitSelf, + span: ctx.span + }), + mutbl: mutability, + }), + span: ctx.span, + }), + pat: P(ast::Pat { + id: ast::DUMMY_NODE_ID, + node: ast::PatKind::Ident(ast::BindingMode::ByValue(ast::Mutability::Immutable), + respan(ctx.span, ctx.ext_cx.ident_of("self")), + None), + span: ctx.span, + }), + id: ast::DUMMY_NODE_ID, + }; + } + let sig = ast::MethodSig { unsafety: ast::Unsafety::Unsafe, abi: Abi::Rust, decl: P(fndecl), generics: empty_generics(), - explicit_self: respan(ctx.span, self_kind), constness: ast::Constness::NotConst, }; - let block = ast::Block { - stmts: vec![], - expr: Some(P(ast::Expr { - id: ast::DUMMY_NODE_ID, - node: ast::ExprKind::Call( - P(ast::Expr { - id: ast::DUMMY_NODE_ID, - node: ast::ExprKind::Path(None, ast::Path { - span: ctx.span, - global: false, - segments: vec!(ast::PathSegment { - identifier: ctx.ext_cx.ident_of(&v.mangled), - parameters: ast::PathParameters::none() - }) - }), + let call = P(ast::Expr { + id: ast::DUMMY_NODE_ID, + node: ast::ExprKind::Call( + P(ast::Expr { + id: ast::DUMMY_NODE_ID, + node: ast::ExprKind::Path(None, ast::Path { span: ctx.span, - attrs: None, + global: false, + segments: vec![ast::PathSegment { + identifier: ctx.ext_cx.ident_of(&v.mangled), + parameters: ast::PathParameters::none() + }] }), - args - ), - span: ctx.span, - attrs: None, - })), + span: ctx.span, + attrs: ast::ThinVec::new(), + }), + args + ), + span: ctx.span, + attrs: ast::ThinVec::new(), + }); + + let block = ast::Block { + stmts: vec![ + ast::Stmt { + id: ast::DUMMY_NODE_ID, + node: ast::StmtKind::Expr(call), + span: ctx.span, + } + ], id: ast::DUMMY_NODE_ID, rules: ast::BlockCheckMode::Default, span: ctx.span @@ -282,16 +310,12 @@ pub fn gen_mods(links: &[(String, LinkType)], // Create a dummy ExtCtxt. We only need this for string interning and that uses TLS. let mut features = Features::new(); features.quote = true; - let cfg = ExpansionConfig { - crate_name: "xxx".to_owned(), - features: Some(&features), - recursion_limit: 64, - trace_mac: false, - }; - let sess = &parse::ParseSess::new(); - let mut feature_gated_cfgs = vec![]; + + let cfg = ExpansionConfig::default("xxx".to_owned()); + let sess = parse::ParseSess::new(); + let mut loader = base::DummyMacroLoader; let mut ctx = GenCtx { - ext_cx: base::ExtCtxt::new(sess, vec![], cfg, &mut feature_gated_cfgs), + ext_cx: base::ExtCtxt::new(&sess, vec![], cfg, &mut loader), options: options, span: span, module_map: map, @@ -1220,11 +1244,11 @@ fn cstruct_to_rs(ctx: &mut GenCtx, name: &str, ci: CompInfo) -> Vec<P<ast::Item> TFuncPtr(ref sig) => { let name = v.mangled.clone(); let explicit_self = if v.is_static { - ast::SelfKind::Static + None } else if v.is_const { - ast::SelfKind::Region(None, ast::Mutability::Immutable, ctx.ext_cx.ident_of("self")) + Some(ast::Mutability::Immutable) } else { - ast::SelfKind::Region(None, ast::Mutability::Mutable, ctx.ext_cx.ident_of("self")) + Some(ast::Mutability::Mutable) }; unmangledlist.push(gen_unmangle_method(ctx, &v, &mut unmangle_count, explicit_self)); mangledlist.push(cfunc_to_rs(ctx, name, String::new(), String::new(), @@ -1698,8 +1722,6 @@ fn gen_fullbitfield_method(ctx: &mut GenCtx, bindgen_name: &String, variadic: false }; - let stmts = Vec::with_capacity(bitfields.len() + 1); - let mut offset = 0; let mut exprs = quote_expr!(&ctx.ext_cx, 0); @@ -1721,8 +1743,13 @@ fn gen_fullbitfield_method(ctx: &mut GenCtx, bindgen_name: &String, } let block = ast::Block { - stmts: stmts, - expr: Some(exprs), + stmts: vec![ + ast::Stmt { + id: ast::DUMMY_NODE_ID, + node: ast::StmtKind::Expr(exprs), + span: ctx.span, + } + ], id: ast::DUMMY_NODE_ID, rules: ast::BlockCheckMode::Default, span: ctx.span @@ -1734,7 +1761,6 @@ fn gen_fullbitfield_method(ctx: &mut GenCtx, bindgen_name: &String, abi: Abi::Rust, decl: P(fndecl), generics: empty_generics(), - explicit_self: respan(ctx.span, ast::SelfKind::Static), constness: ast::Constness::Const, }, P(block) ); @@ -2151,7 +2177,7 @@ fn mk_arrty(ctx: &GenCtx, base: &ast::Ty, n: usize) -> ast::Ty { id: ast::DUMMY_NODE_ID, node: sz, span: ctx.span, - attrs: None, + attrs: ast::ThinVec::new(), }) ); @@ -7,6 +7,7 @@ #![cfg_attr(feature = "clippy", plugin(clippy))] extern crate syntex_syntax as syntax; +extern crate clang_sys; extern crate libc; #[macro_use] extern crate log; @@ -15,8 +16,7 @@ use std::collections::HashSet; use std::default::Default; use std::io::{Write, self}; use std::fs::OpenOptions; -use std::path::{Path, self}; -use std::{env, fs}; +use std::path::Path; use syntax::ast; use syntax::codemap::{DUMMY_SP, Span}; @@ -332,8 +332,7 @@ fn builtin_names() -> HashSet<String> { } #[test] -fn builder_state() -{ +fn builder_state() { let logger = DummyLogger; let mut build = builder(); { @@ -345,70 +344,3 @@ fn builder_state() assert!(build.options.clang_args.binary_search(&"example.h".to_owned()).is_ok()); assert!(build.options.links.binary_search(&("m".to_owned(), LinkType::Static)).is_ok()); } - -// Get the first directory in PATH that contains a file named "clang". -fn get_clang_dir() -> Option<path::PathBuf>{ - if let Some(paths) = env::var_os("PATH") { - for mut path in env::split_paths(&paths) { - path.push("clang"); - if let Ok(real_path) = fs::canonicalize(&path) { - if fs::metadata(&real_path).iter().any(|m| m.is_file()) && - real_path - .file_name() - .and_then(|f| f.to_str()) - .iter() - .any(|&f| f.starts_with("clang")) { - if let Some(dir) = real_path.parent() { - return Some(dir.to_path_buf()) - } - } - } - } - } - None -} - -// Try to find the directory that contains clang's bundled headers. Clang itself does something -// very similar: it takes the parent directory of the current executable, appends -// "../lib/clang/<VERSIONSTRING>/include". We have two problems emulating this behaviour: -// * We don't have a very good way of finding the clang executable, but can fake this by -// searching $PATH and take one directory that contains "clang". -// * We don't have access to <VERSIONSTRING>. There is clang_getClangVersion(), but it returns -// a human-readable description string which is not guaranteed to be stable and a pain to parse. -// We work around that by just taking the first directory in ../lib/clang and hope it's the -// current version. -// TODO: test if this works on Windows at all. -#[doc(hidden)] -pub fn get_include_dir() -> Option<String> { - match get_clang_dir() { - Some(mut p) => { - p.push(".."); - p.push("lib"); - p.push("clang"); - - let dir_iter = match fs::read_dir(p) { - Ok(dir_iter) => dir_iter, - _ => return None - }; - for dir in dir_iter { - match dir { - Ok(dir) => { - // Let's take the first dir. In my case, there's only one directory - // there anyway. - let mut p = dir.path(); - p.push("include"); - match p.into_os_string().into_string() { - Ok(s) => return Some(s), - // We found the directory, but can't access it as it contains - // invalid unicode. - _ => return None, - } - } - _ => return None, - } - } - None - } - None => None, - } -} |