diff --git a/.travis.yml b/.travis.yml index 274aefc11e..02002308ea 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,13 +2,13 @@ language: rust addons: apt: sources: - - llvm-toolchain-precise-3.8 + - llvm-toolchain-precise-3.9 - ubuntu-toolchain-r-test packages: - - libclang-3.8-dev - - llvm-3.8-dev + - libclang-3.9-dev + - llvm-3.9-dev env: - - LLVM_VERSION=3.8 + - LLVM_VERSION=3.9 rust: - stable - nightly @@ -39,7 +39,7 @@ before_script: - echo $LIBCLANG_PATH script: - - cargo build --verbose --features llvm_stable + - cargo build --verbose - make test - git add -A - git diff @ diff --git a/Cargo.toml b/Cargo.toml index cd32574bbf..d0d238d4c4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -43,7 +43,6 @@ features = ["with-syntex"] version = "0.20" [features] -llvm_stable = [] static = [] [lib] diff --git a/Makefile b/Makefile index cad0f51349..853eb195e0 100644 --- a/Makefile +++ b/Makefile @@ -9,7 +9,7 @@ BINDGEN := ./target/debug/bindgen .PHONY: $(BINDGEN) $(BINDGEN): - [ -f $@ ] || cargo build --features llvm_stable + [ -f $@ ] || cargo build .PHONY: test test: regen-tests diff --git a/README.md b/README.md index 30f1c859c7..8d8d8ecebb 100644 --- a/README.md +++ b/README.md @@ -64,11 +64,14 @@ Those instructions list optional steps. For bindgen: ## Building +Just run: + ``` -$ cargo build --features llvm_stable +cargo build ``` -If you want a build with extra features (llvm 3.9) then you can use: +This version of bindgen requires LLVM 3.9, so if you don't have it installed in +your `PATH`, you'll need to build it (see below) and do something like: ``` $ LIBCLANG_PATH=path/to/clang-3.9/build/lib \ diff --git a/build.rs b/build.rs index b9cf3e6045..e618b28e19 100644 --- a/build.rs +++ b/build.rs @@ -15,5 +15,10 @@ mod codegen { } fn main() { + use std::env; + codegen::main(); + if let Ok(path) = env::var("LIBCLANG_PATH") { + println!("cargo:rustc-link-search=native={}", path); + } } diff --git a/src/bin/bindgen.rs b/src/bin/bindgen.rs index 1b9d480689..57b7e08075 100755 --- a/src/bin/bindgen.rs +++ b/src/bin/bindgen.rs @@ -56,6 +56,8 @@ Options: --ignore-methods Avoid generating all kind of methods. + --keep-inline-functions Generate code for inline functions anyway. + --enable-cxx-namespaces Enable support for C++ namespaces. --no-type-renaming Don't rename types. @@ -158,6 +160,9 @@ fn parse_args_or_exit(args: Vec) -> (BindgenOptions, Box) { "--ignore-functions" => { options.ignore_functions = true; } + "--keep-inline-functions" => { + options.keep_inline_functions = true; + } "--no-bitfield-methods" => { options.gen_bitfield_methods = false; } diff --git a/src/clang.rs b/src/clang.rs index ec6dbbe523..f8cb09a3b9 100644 --- a/src/clang.rs +++ b/src/clang.rs @@ -17,8 +17,9 @@ pub struct Cursor { impl fmt::Debug for Cursor { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - write!(fmt, "Cursor({} kind: {}, loc: {}, usr: {:?})", - self.spelling(), kind_to_str(self.kind()), self.location(), self.usr()) + write!(fmt, "Cursor({} kind: {} ({}), loc: {}, usr: {:?})", + self.spelling(), kind_to_str(self.kind()), self.kind(), + self.location(), self.usr()) } } @@ -224,19 +225,10 @@ impl Cursor { } } - #[cfg(not(feature="llvm_stable"))] pub fn is_inlined_function(&self) -> bool { unsafe { clang_Cursor_isFunctionInlined(self.x) != 0 } } - // TODO: Remove this when LLVM 3.9 is released. - // - // This is currently used for CI purposes. - #[cfg(feature="llvm_stable")] - pub fn is_inlined_function(&self) -> bool { - false - } - // bitfield pub fn bit_width(&self) -> Option { unsafe { @@ -405,9 +397,9 @@ impl Eq for Type {} impl fmt::Debug for Type { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - write!(fmt, "Type({}, kind: {}, decl: {:?}, canon: {:?})", - self.spelling(), type_to_str(self.kind()), self.declaration(), - self.declaration().canonical()) + write!(fmt, "Type({}, kind: {} ({}), decl: {:?}, canon: {:?})", + self.spelling(), type_to_str(self.kind()), self.kind(), + self.declaration(), self.declaration().canonical()) } } @@ -586,7 +578,6 @@ impl Type { } } - #[cfg(not(feature="llvm_stable"))] pub fn named(&self) -> Type { unsafe { Type { x: clang_Type_getNamedType(self.x) } @@ -1106,9 +1097,7 @@ pub fn type_to_str(x: Enum_CXTypeKind) -> &'static str { CXType_VariableArray => "VariableArray", CXType_DependentSizedArray => "DependentSizedArray", CXType_MemberPointer => "MemberPointer", - #[cfg(not(feature="llvm_stable"))] CXType_Auto => "Auto", - #[cfg(not(feature="llvm_stable"))] CXType_Elaborated => "Elaborated", _ => "?" } diff --git a/src/clangll.rs b/src/clangll.rs index 47f41ff1ca..4ff5a0daa3 100644 --- a/src/clangll.rs +++ b/src/clangll.rs @@ -408,9 +408,7 @@ pub const CXType_IncompleteArray: c_uint = 114; pub const CXType_VariableArray: c_uint = 115; pub const CXType_DependentSizedArray: c_uint = 116; pub const CXType_MemberPointer: c_uint = 117; -#[cfg(not(feature="llvm_stable"))] pub const CXType_Auto: c_uint = 118; -#[cfg(not(feature="llvm_stable"))] pub const CXType_Elaborated: c_uint = 119; pub type Enum_CXCallingConv = c_uint; pub const CXCallingConv_Default: c_uint = 0; @@ -1113,10 +1111,8 @@ extern "C" { pub fn clang_Type_getNumTemplateArguments(T: CXType) -> c_int; pub fn clang_Type_getTemplateArgumentAsType(T: CXType, i: c_int) -> CXType; - #[cfg(not(feature="llvm_stable"))] pub fn clang_Type_getNamedType(CT: CXType) -> CXType; pub fn clang_Cursor_isBitField(C: CXCursor) -> c_uint; - #[cfg(not(feature="llvm_stable"))] pub fn clang_Cursor_isFunctionInlined(C: CXCursor) -> c_uint; pub fn clang_isVirtualBase(arg1: CXCursor) -> c_uint; pub fn clang_getCXXAccessSpecifier(arg1: CXCursor) -> diff --git a/src/ir/comp.rs b/src/ir/comp.rs index d31b7adf12..1b31a1aba2 100644 --- a/src/ir/comp.rs +++ b/src/ir/comp.rs @@ -583,7 +583,7 @@ impl CompInfo { return CXChildVisit_Continue; } - if cur.is_inlined_function() { + if cur.is_inlined_function() && !ctx.options().keep_inline_functions { return CXChildVisit_Continue; } diff --git a/src/ir/function.rs b/src/ir/function.rs index af170935dc..37f6a8da1f 100644 --- a/src/ir/function.rs +++ b/src/ir/function.rs @@ -111,6 +111,10 @@ impl FunctionSig { use clangll::*; debug!("FunctionSig::from_ty {:?} {:?}", ty, cursor); + if cursor.is_inlined_function() && !ctx.options().keep_inline_functions { + return Err(ParseError::Continue); + } + // Don't parse operatorxx functions in C++ let spelling = cursor.spelling(); if spelling.starts_with("operator") { @@ -122,6 +126,7 @@ impl FunctionSig { } else { ty.declaration() }; + let mut args: Vec<_> = match cursor.kind() { CXCursor_FunctionDecl | CXCursor_CXXMethod => { diff --git a/src/ir/ty.rs b/src/ir/ty.rs index 74452243f6..873d7d2412 100644 --- a/src/ir/ty.rs +++ b/src/ir/ty.rs @@ -543,7 +543,6 @@ impl Type { .expect("Not able to resolve array element?"); TypeKind::Array(inner, ty.array_size()) } - #[cfg(not(feature="llvm_stable"))] CXType_Elaborated => { return Self::from_clang_ty(potential_id, &ty.named(), location, parent_id, ctx); diff --git a/src/lib.rs b/src/lib.rs index 33bd66e706..2683f53bb6 100755 --- a/src/lib.rs +++ b/src/lib.rs @@ -173,6 +173,10 @@ pub struct BindgenOptions { pub emit_ast: bool, pub ignore_functions: bool, pub ignore_methods: bool, + /// Whether to generate code for inline functions. If you do this, you need + /// to make sure you compile the C++ code with a flag like + /// -fkeep-inline-functions + pub keep_inline_functions: bool, pub gen_bitfield_methods: bool, pub fail_on_unknown_type: bool, pub enable_cxx_namespaces: bool, @@ -208,6 +212,7 @@ impl Default for BindgenOptions { emit_ast: false, ignore_functions: false, ignore_methods: false, + keep_inline_functions: false, gen_bitfield_methods: true, fail_on_unknown_type: true, rename_types: true, diff --git a/tests/expectations/class_with_typedef.rs b/tests/expectations/class_with_typedef.rs index bc19f2bd0d..60fe564510 100644 --- a/tests/expectations/class_with_typedef.rs +++ b/tests/expectations/class_with_typedef.rs @@ -22,38 +22,16 @@ fn bindgen_test_layout_C() { assert_eq!(::std::mem::align_of::() , 8usize); } extern "C" { - #[link_name = "_ZN1C6methodEi"] - pub fn C_method(this: *mut C, c: C_MyInt); -} -extern "C" { - #[link_name = "_ZN1C9methodRefERi"] - pub fn C_methodRef(this: *mut C, c: *mut C_MyInt); -} -extern "C" { - #[link_name = "_ZN1C16complexMethodRefERPKc"] - pub fn C_complexMethodRef(this: *mut C, c: *mut C_Lookup); -} -extern "C" { - #[link_name = "_ZN1C13anotherMethodEi"] - pub fn C_anotherMethod(this: *mut C, c: AnotherInt); + #[link_name = "_ZN1C16notInlinedMethodEi"] + pub fn C_notInlinedMethod(this: *mut C, c: C_MyInt); } impl Clone for C { fn clone(&self) -> Self { *self } } impl C { #[inline] - pub unsafe fn method(&mut self, c: C_MyInt) { C_method(&mut *self, c) } - #[inline] - pub unsafe fn methodRef(&mut self, c: *mut C_MyInt) { - C_methodRef(&mut *self, c) - } - #[inline] - pub unsafe fn complexMethodRef(&mut self, c: *mut C_Lookup) { - C_complexMethodRef(&mut *self, c) - } - #[inline] - pub unsafe fn anotherMethod(&mut self, c: AnotherInt) { - C_anotherMethod(&mut *self, c) + pub unsafe fn notInlinedMethod(&mut self, c: C_MyInt) { + C_notInlinedMethod(&mut *self, c) } } #[repr(C)] diff --git a/tests/expectations/inlined_functions.rs b/tests/expectations/inlined_functions.rs new file mode 100644 index 0000000000..cb3c7af8c1 --- /dev/null +++ b/tests/expectations/inlined_functions.rs @@ -0,0 +1,37 @@ +/* automatically generated by rust-bindgen */ + + +#![allow(non_snake_case)] + + +extern "C" { + #[link_name = "_Z3foov"] + pub fn foo() -> bool; +} +#[repr(C)] +#[derive(Debug, Copy)] +pub struct C { + pub _address: u8, +} +#[test] +fn bindgen_test_layout_C() { + assert_eq!(::std::mem::size_of::() , 1usize); + assert_eq!(::std::mem::align_of::() , 1usize); +} +extern "C" { + #[link_name = "_ZN1C3fooEv"] + pub fn C_foo(); +} +extern "C" { + #[link_name = "_ZN1C3barEv"] + pub fn C_bar() -> bool; +} +impl Clone for C { + fn clone(&self) -> Self { *self } +} +impl C { + #[inline] + pub unsafe fn foo() { C_foo() } + #[inline] + pub unsafe fn bar() -> bool { C_bar() } +} diff --git a/tests/headers/class_with_typedef.hpp b/tests/headers/class_with_typedef.hpp index f36c7b5d32..8ddc983d13 100644 --- a/tests/headers/class_with_typedef.hpp +++ b/tests/headers/class_with_typedef.hpp @@ -16,6 +16,7 @@ class C { void methodRef(MyInt& c) {}; void complexMethodRef(Lookup& c) {}; void anotherMethod(AnotherInt c) {}; + void notInlinedMethod(MyInt c); }; class D: public C { diff --git a/tests/headers/inlined_functions.hpp b/tests/headers/inlined_functions.hpp new file mode 100644 index 0000000000..553d480b7b --- /dev/null +++ b/tests/headers/inlined_functions.hpp @@ -0,0 +1,11 @@ +// bindgen-flags: --keep-inline-functions + +inline bool foo() { + return true; +} + +class C { +public: + static void foo() { } + static bool bar() { return false; } +}; diff --git a/tests/tools/run-bindgen.py b/tests/tools/run-bindgen.py index 0d8ed580bb..637aa74c63 100755 --- a/tests/tools/run-bindgen.py +++ b/tests/tools/run-bindgen.py @@ -40,6 +40,7 @@ # https://forums.developer.apple.com/thread/9233 if "DYLD_LIBRARY_PATH" not in env and "LIBCLANG_PATH" in env: env["DYLD_LIBRARY_PATH"] = env["LIBCLANG_PATH"] + subprocess.check_call(base_command, cwd=os.getcwd(), env=env)