diff options
-rw-r--r-- | Cargo.lock | 2 | ||||
-rw-r--r-- | Cargo.toml | 2 | ||||
-rwxr-xr-x | releases/friends.sh | 19 | ||||
-rw-r--r-- | releases/release-announcement-template.md | 72 | ||||
-rw-r--r-- | src/ir/item.rs | 19 | ||||
-rw-r--r-- | src/lib.rs | 71 | ||||
-rw-r--r-- | src/main.rs | 4 | ||||
-rw-r--r-- | src/options.rs | 9 | ||||
-rw-r--r-- | src/uses.rs | 105 | ||||
-rw-r--r-- | tests/expectations/tests/issue-848-replacement-system-include.rs | 24 | ||||
-rw-r--r-- | tests/expectations/tests/template.rs | 23 | ||||
-rw-r--r-- | tests/headers/issue-848-replacement-system-include.hpp | 7 | ||||
-rw-r--r-- | tests/headers/issue-848/an-include.h | 17 | ||||
-rw-r--r-- | tests/headers/template.hpp | 4 |
14 files changed, 208 insertions, 170 deletions
@@ -1,6 +1,6 @@ [root] name = "bindgen" -version = "0.28.0" +version = "0.29.0" dependencies = [ "aster 0.41.0 (registry+https://github.com/rust-lang/crates.io-index)", "cexpr 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -13,7 +13,7 @@ name = "bindgen" readme = "README.md" repository = "https://github.com/rust-lang-nursery/rust-bindgen" documentation = "https://docs.rs/bindgen" -version = "0.28.0" +version = "0.29.0" build = "build.rs" exclude = [ diff --git a/releases/friends.sh b/releases/friends.sh new file mode 100755 index 00000000..453f5d37 --- /dev/null +++ b/releases/friends.sh @@ -0,0 +1,19 @@ +#!/usr/bin/env bash + +set -eu +set -o pipefail + +cd "$(dirname $0)" + +if [[ -z "${1+x}" ]]; then + read -p "List friends since which commit/tag? " since + echo +else + since=$1 +fi + +git shortlog -s -n "$since.." \ + | cut -f 2- \ + | sort -u \ + | grep -v bors\-servo \ + | xargs -I{} echo "- {}" diff --git a/releases/release-announcement-template.md b/releases/release-announcement-template.md new file mode 100644 index 00000000..c9d5eae2 --- /dev/null +++ b/releases/release-announcement-template.md @@ -0,0 +1,72 @@ +# Announcing `bindgen` $TODO_VERSION + +`bindgen` automatically generates Rust FFI bindings to C and C++ libraries. + +Upgrade to this release by updating your `Cargo.toml`: + +```toml +bindgen = "$TODO_VERSION" +``` + +* [GitHub][] +* [crates.io][] +* [Users Guide][guide] +* [API Documentation][docs] + +## Changelog + +### Added + +* TODO (or remove section if none) + +### Changed + +* TODO (or remove section if none) + +### Deprecated + +* TODO (or remove section if none) + +### Removed + +* TODO (or remove section if none) + +### Fixed + +* TODO (or remove section if none) + +### Security + +* TODO (or remove section if none) + + +## Friends + +Thanks to everyone who contributed to this release! + +<insert the output of friends.sh here> + +## Contributing + +Want to join us? Check out our [CONTRIBUTING.md][contributing] and take a look +at some of these issues: + +* [Issues labeled "easy"][easy] +* [Issues labeled "less easy"][less-easy] +* Still can't find something to work on? [Drop a comment here.][looking] + +Want to help improve our documentation? +[Check out the issues labeled "docs".][docs-issues] + +Found a bug with `bindgen`? [File an issue here.][file-issue] + +[GitHub]: https://github.com/rust-lang-nursery/rust-bindgen +[crates.io]: https://crates.io/crates/bindgen +[guide]: https://rust-lang-nursery.github.io/rust-bindgen +[docs]: https://docs.rs/bindgen +[contributing]: https://github.com/rust-lang-nursery/rust-bindgen/blob/master/CONTRIBUTING.md +[easy]: https://github.com/rust-lang-nursery/rust-bindgen/issues?q=is%3Aopen+is%3Aissue+label%3AE-easy +[less-easy]: https://github.com/rust-lang-nursery/rust-bindgen/issues?q=is%3Aopen+is%3Aissue+label%3AE-less-easy +[looking]: https://github.com/rust-lang-nursery/rust-bindgen/issues/747 +[docs-issues]: https://github.com/rust-lang-nursery/rust-bindgen/issues?q=is%3Aopen+is%3Aissue+label%3AI-needs-docs +[file-issue]: https://github.com/rust-lang-nursery/rust-bindgen/issues/new diff --git a/src/ir/item.rs b/src/ir/item.rs index 8a210e38..ff692fdb 100644 --- a/src/ir/item.rs +++ b/src/ir/item.rs @@ -728,12 +728,21 @@ impl Item { ItemKind::Type(ref ty) => { let name = match *ty.kind() { TypeKind::ResolvedTypeRef(..) => panic!("should have resolved this in name_target()"), - _ => ty.name(), + TypeKind::Pointer(inner) => { + ctx.resolve_item(inner) + .expect_type().name() + .map(|name| format!("ptr_{}", name)) + } + TypeKind::Array(inner, length) => { + ctx.resolve_item(inner) + .expect_type().name() + .map(|name| format!("array_{}_{}", name, length)) + } + _ => ty.name().map(ToOwned::to_owned) }; - name.map(ToOwned::to_owned) - .unwrap_or_else(|| { - format!("_bindgen_ty_{}", self.exposed_id(ctx)) - }) + name.unwrap_or_else(|| { + format!("_bindgen_ty_{}", self.exposed_id(ctx)) + }) } ItemKind::Function(ref fun) => { let mut name = fun.name().to_owned(); @@ -65,7 +65,6 @@ mod clang; mod ir; mod parse; mod regex_set; -mod uses; pub mod callbacks; @@ -76,7 +75,6 @@ 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")); @@ -265,11 +263,6 @@ impl Builder { output_vector.push(prefix.clone()); } - if let Some(ref dummy) = self.options.dummy_uses { - output_vector.push("--dummy-uses".into()); - output_vector.push(dummy.clone()); - } - if self.options.emit_ast { output_vector.push("--emit-clang-ast".into()); } @@ -519,13 +512,6 @@ impl Builder { 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. Regular expressions are /// supported. pub fn hide_type<T: AsRef<str>>(mut self, arg: T) -> Builder { @@ -1001,10 +987,6 @@ pub struct BindgenOptions { /// Unsaved files for input. pub input_unsaved_files: Vec<clang::UnsavedFile>, - /// 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 visitor to allow customizing different kinds of /// situations. pub parse_callbacks: Option<Box<callbacks::ParseCallbacks>>, @@ -1094,7 +1076,6 @@ impl Default for BindgenOptions { clang_args: vec![], input_header: None, input_unsaved_files: vec![], - dummy_uses: None, parse_callbacks: None, codegen_config: CodegenConfig::all(), conservative_inline_namespaces: false, @@ -1162,8 +1143,35 @@ impl<'ctx> Bindings<'ctx> { options.build(); + // Filter out include paths and similar stuff, so we don't incorrectly + // promote them to `-isystem`. + let clang_args_for_clang_sys = { + let mut last_was_include_prefix = false; + options.clang_args.iter().filter(|arg| { + if last_was_include_prefix { + last_was_include_prefix = false; + return false; + } + + let arg = &**arg; + + // https://clang.llvm.org/docs/ClangCommandLineReference.html + // -isystem and -isystem-after are harmless. + if arg == "-I" || arg == "--include-directory" { + last_was_include_prefix = true; + return false; + } + + if arg.starts_with("-I") || arg.starts_with("--include-directory=") { + return false; + } + + true + }).cloned().collect::<Vec<_>>() + }; + // TODO: Make this path fixup configurable? - if let Some(clang) = clang_sys::support::Clang::find(None, &options.clang_args) { + if let Some(clang) = clang_sys::support::Clang::find(None, &clang_args_for_clang_sys) { // 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 @@ -1250,29 +1258,6 @@ impl<'ctx> Bindings<'ctx> { 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 diff --git a/src/main.rs b/src/main.rs index 9cd4f806..32248cb0 100644 --- a/src/main.rs +++ b/src/main.rs @@ -64,11 +64,9 @@ pub fn main() { std::process::exit(1); } - let mut bindings = builder_result.unwrap(); + let bindings = builder_result.unwrap(); bindings.write(output) .expect("Unable to write output"); - bindings.write_dummy_uses() - .expect("Unable to write dummy uses to file."); } Err(error) => { println!("{}", error); diff --git a/src/options.rs b/src/options.rs index 3d54eb39..f2ed5494 100644 --- a/src/options.rs +++ b/src/options.rs @@ -88,11 +88,6 @@ pub fn builder_from_flags<I> // All positional arguments after the end of options marker, `--` Arg::with_name("clang-args") .multiple(true), - Arg::with_name("dummy-uses") - .long("dummy-uses") - .help("For testing purposes, generate a C/C++ file containing \ - dummy uses of all types defined in the input header.") - .takes_value(true), Arg::with_name("emit-clang-ast") .long("emit-clang-ast") .help("Output the Clang AST for debugging purposes."), @@ -282,10 +277,6 @@ pub fn builder_from_flags<I> builder = builder.ctypes_prefix(prefix); } - if let Some(dummy) = matches.value_of("dummy-uses") { - builder = builder.dummy_uses(dummy); - } - if let Some(links) = matches.values_of("dynamic") { for library in links { builder = builder.link(library); diff --git a/src/uses.rs b/src/uses.rs deleted file mode 100644 index fc7c126e..00000000 --- a/src/uses.rs +++ /dev/null @@ -1,105 +0,0 @@ -//! Take in our IR and output a C/C++ file with dummy uses of each IR type. -//! -//! Say that we had this C++ header, `header.hpp`: -//! -//! ```c++ -//! class Point { -//! int x; -//! int y; -//! } -//! -//! enum Bar { -//! THIS, -//! THAT, -//! OTHER -//! } -//! ``` -//! -//! If we generated dummy uses for this header, we would get a `.cpp` file like -//! this: -//! -//! ```c++ -//! #include "header.hpp" -//! -//! void dummy(Point*) {} -//! void dummy(Bar*) {} -//! ``` -//! -//! This is useful because we can compile this `.cpp` file into an object file, -//! and then compare its debugging information to the debugging information -//! generated for our Rust bindings. These two sets of debugging information had -//! better agree on the C/C++ types' physical layout, or else our bindings are -//! incorrect! -//! -//! "But you still haven't explained why we have to generate the dummy uses" you -//! complain. Well if the types are never used, then they are elided when the -//! C/C++ compiler generates debugging information. - -use ir::context::BindgenContext; -use ir::item::{Item, ItemAncestors, ItemCanonicalName}; -use ir::template::TemplateParameters; -use std::io; - -// Like `canonical_path`, except we always take namespaces into account, ignore -// the generated names of anonymous items, and return a `String`. -// -// TODO: Would it be easier to try and demangle the USR? -fn namespaced_name(ctx: &BindgenContext, item: &Item) -> String { - let mut names: Vec<_> = item.ancestors(ctx) - .map(|id| ctx.resolve_item(id).canonical_name(ctx)) - .filter(|name| !name.starts_with("_bindgen_")) - .collect(); - names.reverse(); - names.join("::") -} - -/// Generate the dummy uses for all the items in the given context, and write -/// the dummy uses to `dest`. -pub fn generate_dummy_uses<W>(ctx: &mut BindgenContext, - mut dest: W) - -> io::Result<()> - where W: io::Write, -{ - ctx.gen(|ctx| { - let input_header = ctx.options() - .input_header - .as_ref() - .expect("Should not generate dummy uses without an input header"); - - try!(writeln!(dest, "/* automatically generated by rust-bindgen */")); - try!(writeln!(dest, "")); - try!(writeln!(dest, "#include \"{}\"", input_header)); - try!(writeln!(dest, "")); - - let type_items = ctx.whitelisted_items() - .iter() - .cloned() - .map(|id| ctx.resolve_item(id)) - .filter(|item| { - // We only want type items. - if let Some(ty) = item.kind().as_type() { - // However, we don't want anonymous types, as we can't - // generate dummy uses for them. - ty.name().is_some() && - // Nor do we want builtin types or named template type - // arguments. Again, we can't generate dummy uses for - // these. - !ty.is_builtin_or_named() && - // And finally, we won't be creating any dummy - // instantiations, so ignore template declarations and - // instantiations. - item.all_template_params(ctx).is_none() - } else { - false - } - }) - .map(|item| namespaced_name(ctx, item)) - .enumerate(); - - for (idx, name) in type_items { - try!(writeln!(dest, "void dummy{}({}*) {{ }}", idx, name)); - } - - Ok(()) - }) -} diff --git a/tests/expectations/tests/issue-848-replacement-system-include.rs b/tests/expectations/tests/issue-848-replacement-system-include.rs new file mode 100644 index 00000000..14083705 --- /dev/null +++ b/tests/expectations/tests/issue-848-replacement-system-include.rs @@ -0,0 +1,24 @@ +/* automatically generated by rust-bindgen */ + + +#![allow(dead_code, non_snake_case, non_camel_case_types, non_upper_case_globals)] + + +/// This is intended to replace another type, but won't if we treat this include +/// as a system include, because clang doesn't parse comments there. +/// +/// See #848. +/// +/// <div rustbindgen replaces="nsTArray"></div> +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct nsTArray<T> { + pub m: *mut T, + pub _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell<T>>, +} +impl <T> Default for nsTArray<T> { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} +extern "C" { + pub fn func() -> *mut nsTArray<::std::os::raw::c_int>; +} diff --git a/tests/expectations/tests/template.rs b/tests/expectations/tests/template.rs index 8e432167..275f45ea 100644 --- a/tests/expectations/tests/template.rs +++ b/tests/expectations/tests/template.rs @@ -37,6 +37,7 @@ pub struct C { pub mBVolatile: B<::std::os::raw::c_int>, pub mBConstBool: B<bool>, pub mBConstChar: B<u16>, + pub mBArray: B<[::std::os::raw::c_int; 1usize]>, } #[test] fn bindgen_test_layout_C() { @@ -73,6 +74,11 @@ fn bindgen_test_layout_C() { } , 26usize , concat ! ( "Alignment of field: " , stringify ! ( C ) , "::" , stringify ! ( mBConstChar ) )); + assert_eq! (unsafe { + & ( * ( 0 as * const C ) ) . mBArray as * const _ as usize } , + 28usize , concat ! ( + "Alignment of field: " , stringify ! ( C ) , "::" , stringify + ! ( mBArray ) )); } impl Clone for C { fn clone(&self) -> Self { *self } @@ -317,7 +323,7 @@ fn __bindgen_test_layout_B_open0_unsigned_int_close0_instantiation() { B<::std::os::raw::c_uint> ) )); } #[test] -fn __bindgen_test_layout_B_open0__bindgen_ty_id_113_close0_instantiation() { +fn __bindgen_test_layout_B_open0_ptr_const_int_close0_instantiation() { assert_eq!(::std::mem::size_of::<B<*const ::std::os::raw::c_int>>() , 8usize , concat ! ( "Size of template specialization: " , stringify ! ( @@ -368,6 +374,17 @@ fn __bindgen_test_layout_B_open0_const_char16_t_close0_instantiation() { ) )); } #[test] +fn __bindgen_test_layout_B_open0_array_int_1_close0_instantiation() { + assert_eq!(::std::mem::size_of::<B<[::std::os::raw::c_int; 1usize]>>() , + 4usize , concat ! ( + "Size of template specialization: " , stringify ! ( + B<[::std::os::raw::c_int; 1usize]> ) )); + assert_eq!(::std::mem::align_of::<B<[::std::os::raw::c_int; 1usize]>>() , + 4usize , concat ! ( + "Alignment of template specialization: " , stringify ! ( + B<[::std::os::raw::c_int; 1usize]> ) )); +} +#[test] fn __bindgen_test_layout_Foo_open0_int_int_close0_instantiation_1() { assert_eq!(::std::mem::size_of::<Foo<::std::os::raw::c_int>>() , 24usize , concat ! ( @@ -379,7 +396,7 @@ fn __bindgen_test_layout_Foo_open0_int_int_close0_instantiation_1() { Foo<::std::os::raw::c_int> ) )); } #[test] -fn __bindgen_test_layout_Rooted_open0__bindgen_ty_id_144_close0_instantiation() { +fn __bindgen_test_layout_Rooted_open0_ptr_void_close0_instantiation() { assert_eq!(::std::mem::size_of::<Rooted<*mut ::std::os::raw::c_void>>() , 24usize , concat ! ( "Size of template specialization: " , stringify ! ( @@ -390,7 +407,7 @@ fn __bindgen_test_layout_Rooted_open0__bindgen_ty_id_144_close0_instantiation() Rooted<*mut ::std::os::raw::c_void> ) )); } #[test] -fn __bindgen_test_layout_Rooted_open0__bindgen_ty_id_150_close0_instantiation() { +fn __bindgen_test_layout_Rooted_open0_ptr_void_close0_instantiation_1() { assert_eq!(::std::mem::size_of::<Rooted<*mut ::std::os::raw::c_void>>() , 24usize , concat ! ( "Size of template specialization: " , stringify ! ( diff --git a/tests/headers/issue-848-replacement-system-include.hpp b/tests/headers/issue-848-replacement-system-include.hpp new file mode 100644 index 00000000..e95c823f --- /dev/null +++ b/tests/headers/issue-848-replacement-system-include.hpp @@ -0,0 +1,7 @@ +// bindgen-flags: -- -Itests/headers/issue-848 + +#include "an-include.h" + +extern "C" { + nsTArray<int>* func(); +} diff --git a/tests/headers/issue-848/an-include.h b/tests/headers/issue-848/an-include.h new file mode 100644 index 00000000..0421d19f --- /dev/null +++ b/tests/headers/issue-848/an-include.h @@ -0,0 +1,17 @@ +template<typename T> +class nsTArray { + void* mBuffer; +}; + +/** + * This is intended to replace another type, but won't if we treat this include + * as a system include, because clang doesn't parse comments there. + * + * See #848. + * + * <div rustbindgen replaces="nsTArray"></div> + */ +template<typename T> +class nsTArray_Simple { + T* m; +}; diff --git a/tests/headers/template.hpp b/tests/headers/template.hpp index 7d373152..168eac9c 100644 --- a/tests/headers/template.hpp +++ b/tests/headers/template.hpp @@ -19,6 +19,10 @@ struct C { B<volatile int> mBVolatile; B<const bool> mBConstBool; B<const char16_t> mBConstChar; + B<int[1]> mBArray; + // clang 3.x ignores const in this case, so they generate different + // result than clang 4.0. + // B<const int[1]> mBConstArray; }; template<typename T> |