Skip to content

failed to produce bindings for RPM library #363

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
sa2ajj opened this issue Dec 27, 2016 · 17 comments
Closed

failed to produce bindings for RPM library #363

sa2ajj opened this issue Dec 27, 2016 · 17 comments

Comments

@sa2ajj
Copy link

sa2ajj commented Dec 27, 2016

I'm looking into creating Rust bindings for the RPM libraries.

First I installed bindgen, but it seems to be somewhat inconsistent with what servo/rust-bindgen offers. So my second attempt was to clone and build bindgen from servo/rust-bindgen:

$ git clone https://github.com/servo/rust-bindgen
$ cd rust-bindgen/bindgen
$ cargo build --release

after that I created a simple wrapper.h:

#include <rpm/rpmlib.h>
#include <rpm/rpmts.h>

and then run bindgen on it:

$ CLANG_PATH=/opt/clang+llvm-3.9.1-x86_64-linux-gnu-debian8/bin/clangLIBCLANG_PATH=/opt/clang+llvm-3.9.1-x86_64-linux-gnu-debian8/lib/ ~/bin/bindgen wrapper.h --output=rpm.rs

as the result I got these errors:

ERROR:libbindgen::ir::context: Valid declaration with no USR: Cursor(__va_list_tag kind: StructDecl, loc: builtin definitions, usr: None), Some(Cursor(va_list kind: TypedefDecl, loc: /opt/clang+llvm-3.9.1-x86_64-linux-gnu-debian8/bin/../lib/clang/3.9.1/include/stdarg.h:30:27, usr: Some("c:@T@va_list")))
ERROR:libbindgen::ir::context: Valid declaration with no USR: Cursor(__builtin_va_list kind: TypedefDecl, loc: builtin definitions, usr: None), Some(Cursor(va_list kind: TypedefDecl, loc: /opt/clang+llvm-3.9.1-x86_64-linux-gnu-debian8/bin/../lib/clang/3.9.1/include/stdarg.h:30:27, usr: Some("c:@T@va_list")))

Do I miss something?

@emilio
Copy link
Contributor

emilio commented Dec 27, 2016

Those errors are non-fatal, does the generated code compile? You can post it here if you want.

If it doesn't, I bet this is #361, and you need to blacklist the functions that use varargs until we do it automatically.

@fitzgen
Copy link
Member

fitzgen commented Dec 28, 2016

We might want to make all the non-fatal error!(...)s into warn!(...)s, because I expect most people get confused. I know I did when I first started using bindgen.

Thoughts @emilio ?

@emilio
Copy link
Contributor

emilio commented Dec 28, 2016

Sounds good to me.

@sa2ajj
Copy link
Author

sa2ajj commented Dec 28, 2016

right, since I had no rpm.rs after my previous attempts (for some reason my package installed clang 3.8 was used) I did not check whether the aforementioned file has any content: actually it does.

I tried to compile the produced rpm.rs and it failed: from my inexperienced look, the problems are not related to the issues mentioned in this issue #361. A couple of errors from running rustc on the rpm.rs:

error[E0428]: a type named `poptOption` has already been defined in this module
...
error: unions are unstable and possibly buggy (see issue #32836)
...
error: aborting due to 14 previous errors

and the union related error is the 13 beside the first one.

@sa2ajj
Copy link
Author

sa2ajj commented Dec 28, 2016

I forgot to mention:

$ rustc --version
rustc 1.14.0 (e8a012324 2016-12-16)

@emilio
Copy link
Contributor

emilio commented Dec 28, 2016

Ok, so the unions one is that by default we generate rust unions, which are nightly-only right now. We probably should change that default behavior.

Can you call bindgen with --no-unstable-rust, and see if that makes things better? The poptOption error seems interesting.

@sa2ajj
Copy link
Author

sa2ajj commented Dec 28, 2016

As you suggested, I run bindgen with --no-unstable-rust option. The compilation of the resulting rpm.rs failed with

error[E0428]: a type named `poptOption` has already been defined in this module
    --> rpm.rs:1246:1
     |   
1176 | pub struct poptOption {
     | - previous definition of `poptOption` here
...
1246 | pub type poptOption = *mut poptOption;
     | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ already defined

error: main function not found

error[E0391]: unsupported cyclic reference between types/traits detected
    --> rpm.rs:1246:28
     |   
1246 | pub type poptOption = *mut poptOption;
     |                            ^^^^^^^^^^ cyclic reference
     |   
     = note: the cycle begins when processing `poptOption`...
     = note: ...which then again requires processing `poptOption`, completing the cycle.

error: aborting due to previous error

main function not found is understandable, the rest is not that much.

poptOption comes from popt library (#include <popt.h>) and it has this:

struct poptOption {
...
};
...
#ifndef __cplusplus
/*@-exporttype -typeuse@*/
typedef struct poptOption * poptOption;
/*@=exporttype =typeuse@*/
#endif
...

Is C++ somehow controlled by an option?

@emilio
Copy link
Contributor

emilio commented Dec 28, 2016

Yup! passing -x c++ to bindgen like:

./bindgen wrapper.h --output=rpm.rs --no-unstable-rust -- -x c++

Should make it work.

@sa2ajj
Copy link
Author

sa2ajj commented Dec 28, 2016

That definitely made a difference. First, the output of bindgen:

ERROR:libbindgen::ir::item: Unhandled cursor kind CXCursorKind(400): Cursor( kind: UnexposedAttr, loc: /usr/lib/gcc/x86_64-linux-gnu/6.2.1/../../../../include/x86_64-linux-gnu/c++/6.2.1/bits/c++config.h:223:43, usr: None)
ERROR:libbindgen::ir::item: Unhandled cursor kind CXCursorKind(400): Cursor( kind: UnexposedAttr, loc: /usr/lib/gcc/x86_64-linux-gnu/6.2.1/../../../../include/x86_64-linux-gnu/c++/6.2.1/bits/c++config.h:227:43, usr: None)
ERROR:libbindgen::ir::item: Unhandled cursor kind CXCursorKind(417): Cursor(default kind: attribute(visibility), loc: /usr/lib/gcc/x86_64-linux-gnu/6.2.1/../../../../include/c++/6.2.1/cstdlib:120:15, usr: None)
ERROR:libbindgen::ir::item: Unhandled cursor kind CXCursorKind(417): Cursor(default kind: attribute(visibility), loc: /usr/lib/gcc/x86_64-linux-gnu/6.2.1/../../../../include/c++/6.2.1/cstdlib:215:21, usr: None)
ERROR:libbindgen::ir::context: Valid declaration with no USR: Cursor(__va_list_tag kind: StructDecl, loc: builtin definitions, usr: None), Some(Cursor(va_list kind: TypedefDecl, loc: /opt/clang+llvm-3.9.1-x86_64-linux-gnu-debian8/bin/../lib/clang/3.9.1/include/stdarg.h:30:27, usr: Some("c:@T@va_list")))
ERROR:libbindgen::ir::context: Valid declaration with no USR: Cursor(__builtin_va_list kind: TypedefDecl, loc: builtin definitions, usr: None), Some(Cursor(va_list kind: TypedefDecl, loc: /opt/clang+llvm-3.9.1-x86_64-linux-gnu-debian8/bin/../lib/clang/3.9.1/include/stdarg.h:30:27, usr: Some("c:@T@va_list")))

and then the output of rustc:

error: main function not found

error[E0201]: duplicate definitions with name `at_offset_0`:
    --> rpm.rs:5840:5
     |
5826 |     pub fn at_offset_0(&self) -> ::std::os::raw::c_int {
     |     - previous definition of `at_offset_0` here
...
5840 |     pub fn at_offset_0(&self) -> ::std::os::raw::c_int {
     |     ^ duplicate definition

error[E0201]: duplicate definitions with name `set_at_offset_0`:
    --> rpm.rs:5848:5
     |
5834 |     pub fn set_at_offset_0(&mut self, val: ::std::os::raw::c_int) {
     |     - previous definition of `set_at_offset_0` here
...
5848 |     pub fn set_at_offset_0(&mut self, val: ::std::os::raw::c_int) {
     |     ^ duplicate definition

error[E0201]: duplicate definitions with name `at_offset_0`:
    --> rpm.rs:5854:5
     |
5826 |     pub fn at_offset_0(&self) -> ::std::os::raw::c_int {
     |     - previous definition of `at_offset_0` here
...
5854 |     pub fn at_offset_0(&self) -> ::std::os::raw::c_int {
     |     ^ duplicate definition

error[E0201]: duplicate definitions with name `set_at_offset_0`:
    --> rpm.rs:5862:5
     |
5834 |     pub fn set_at_offset_0(&mut self, val: ::std::os::raw::c_int) {
     |     - previous definition of `set_at_offset_0` here
...
5862 |     pub fn set_at_offset_0(&mut self, val: ::std::os::raw::c_int) {
     |     ^ duplicate definition

error[E0201]: duplicate definitions with name `at_offset_0`:
    --> rpm.rs:5868:5
     |
5826 |     pub fn at_offset_0(&self) -> ::std::os::raw::c_int {
     |     - previous definition of `at_offset_0` here
...
5868 |     pub fn at_offset_0(&self) -> ::std::os::raw::c_int {
     |     ^ duplicate definition

error[E0201]: duplicate definitions with name `set_at_offset_0`:
    --> rpm.rs:5876:5
     |
5834 |     pub fn set_at_offset_0(&mut self, val: ::std::os::raw::c_int) {
     |     - previous definition of `set_at_offset_0` here
...
5876 |     pub fn set_at_offset_0(&mut self, val: ::std::os::raw::c_int) {
     |     ^ duplicate definition

error[E0201]: duplicate definitions with name `at_offset_0`:
    --> rpm.rs:5882:5
     |
5826 |     pub fn at_offset_0(&self) -> ::std::os::raw::c_int {
     |     - previous definition of `at_offset_0` here
...
5882 |     pub fn at_offset_0(&self) -> ::std::os::raw::c_int {
     |     ^ duplicate definition

error[E0201]: duplicate definitions with name `set_at_offset_0`:
    --> rpm.rs:5890:5
     |
5834 |     pub fn set_at_offset_0(&mut self, val: ::std::os::raw::c_int) {
     |     - previous definition of `set_at_offset_0` here
...
5890 |     pub fn set_at_offset_0(&mut self, val: ::std::os::raw::c_int) {
     |     ^ duplicate definition

error[E0201]: duplicate definitions with name `at_offset_0`:
    --> rpm.rs:5896:5
     |
5826 |     pub fn at_offset_0(&self) -> ::std::os::raw::c_int {
     |     - previous definition of `at_offset_0` here
...
5896 |     pub fn at_offset_0(&self) -> ::std::os::raw::c_int {
     |     ^ duplicate definition

error[E0201]: duplicate definitions with name `set_at_offset_0`:
    --> rpm.rs:5904:5
     |
5834 |     pub fn set_at_offset_0(&mut self, val: ::std::os::raw::c_int) {
     |     - previous definition of `set_at_offset_0` here
...
5904 |     pub fn set_at_offset_0(&mut self, val: ::std::os::raw::c_int) {
     |     ^ duplicate definition

error[E0201]: duplicate definitions with name `at_offset_0`:
    --> rpm.rs:5910:5
     |
5826 |     pub fn at_offset_0(&self) -> ::std::os::raw::c_int {
     |     - previous definition of `at_offset_0` here
...
5910 |     pub fn at_offset_0(&self) -> ::std::os::raw::c_int {
     |     ^ duplicate definition

error[E0201]: duplicate definitions with name `set_at_offset_0`:
    --> rpm.rs:5918:5
     |
5834 |     pub fn set_at_offset_0(&mut self, val: ::std::os::raw::c_int) {
     |     - previous definition of `set_at_offset_0` here
...
5918 |     pub fn set_at_offset_0(&mut self, val: ::std::os::raw::c_int) {
     |     ^ duplicate definition

error[E0201]: duplicate definitions with name `at_offset_0`:
    --> rpm.rs:5924:5
     |
5826 |     pub fn at_offset_0(&self) -> ::std::os::raw::c_int {
     |     - previous definition of `at_offset_0` here
...
5924 |     pub fn at_offset_0(&self) -> ::std::os::raw::c_int {
     |     ^ duplicate definition

error[E0201]: duplicate definitions with name `set_at_offset_0`:
    --> rpm.rs:5932:5
     |
5834 |     pub fn set_at_offset_0(&mut self, val: ::std::os::raw::c_int) {
     |     - previous definition of `set_at_offset_0` here
...
5932 |     pub fn set_at_offset_0(&mut self, val: ::std::os::raw::c_int) {
     |     ^ duplicate definition

error[E0201]: duplicate definitions with name `at_offset_0`:
    --> rpm.rs:5938:5
     |
5826 |     pub fn at_offset_0(&self) -> ::std::os::raw::c_int {
     |     - previous definition of `at_offset_0` here
...
5938 |     pub fn at_offset_0(&self) -> ::std::os::raw::c_int {
     |     ^ duplicate definition

error[E0201]: duplicate definitions with name `set_at_offset_0`:
    --> rpm.rs:5946:5
     |
5834 |     pub fn set_at_offset_0(&mut self, val: ::std::os::raw::c_int) {
     |     - previous definition of `set_at_offset_0` here
...
5946 |     pub fn set_at_offset_0(&mut self, val: ::std::os::raw::c_int) {
     |     ^ duplicate definition

error[E0201]: duplicate definitions with name `at_offset_0`:
    --> rpm.rs:5952:5
     |
5826 |     pub fn at_offset_0(&self) -> ::std::os::raw::c_int {
     |     - previous definition of `at_offset_0` here
...
5952 |     pub fn at_offset_0(&self) -> ::std::os::raw::c_int {
     |     ^ duplicate definition

error[E0201]: duplicate definitions with name `set_at_offset_0`:
    --> rpm.rs:5960:5
     |
5834 |     pub fn set_at_offset_0(&mut self, val: ::std::os::raw::c_int) {
     |     - previous definition of `set_at_offset_0` here
...
5960 |     pub fn set_at_offset_0(&mut self, val: ::std::os::raw::c_int) {
     |     ^ duplicate definition

error[E0201]: duplicate definitions with name `at_offset_0`:
    --> rpm.rs:5966:5
     |
5826 |     pub fn at_offset_0(&self) -> ::std::os::raw::c_int {
     |     - previous definition of `at_offset_0` here
...
5966 |     pub fn at_offset_0(&self) -> ::std::os::raw::c_int {
     |     ^ duplicate definition

error[E0201]: duplicate definitions with name `set_at_offset_0`:
    --> rpm.rs:5974:5
     |
5834 |     pub fn set_at_offset_0(&mut self, val: ::std::os::raw::c_int) {
     |     - previous definition of `set_at_offset_0` here
...
5974 |     pub fn set_at_offset_0(&mut self, val: ::std::os::raw::c_int) {
     |     ^ duplicate definition

error: aborting due to 20 previous errors

@emilio
Copy link
Contributor

emilio commented Dec 28, 2016

That's... Interesting!

Do you have the definition of the struct that is causing those?

@sa2ajj
Copy link
Author

sa2ajj commented Dec 30, 2016

this comes from <bits/timex.h>, I believe, which means that bindgen tries to generate for all things system.

what I want is to generate bindings for rpm related headers only, is there an easy way to do that?

the code rustc complains about:


#[repr(C)]
#[derive(Debug, Copy)]
pub struct timex {
    pub modes: ::std::os::raw::c_uint,
    pub offset: __syscall_slong_t,
    pub freq: __syscall_slong_t,
    pub maxerror: __syscall_slong_t,
    pub esterror: __syscall_slong_t,
    pub status: ::std::os::raw::c_int,
    pub constant: __syscall_slong_t,
    pub precision: __syscall_slong_t,
    pub tolerance: __syscall_slong_t,
    pub time: timeval,
    pub tick: __syscall_slong_t,
    pub ppsfreq: __syscall_slong_t,
    pub jitter: __syscall_slong_t,
    pub shift: ::std::os::raw::c_int,
    pub stabil: __syscall_slong_t,
    pub jitcnt: __syscall_slong_t,
    pub calcnt: __syscall_slong_t,
    pub errcnt: __syscall_slong_t,
    pub stbcnt: __syscall_slong_t,
    pub tai: ::std::os::raw::c_int,
    pub _bitfield_1: u32,
    pub _bitfield_2: u32,
    pub _bitfield_3: u32,
    pub _bitfield_4: u32,
    pub _bitfield_5: u32,
    pub _bitfield_6: u32,
    pub _bitfield_7: u32,
    pub _bitfield_8: u32,
    pub _bitfield_9: u32,
    pub _bitfield_10: u32,
    pub _bitfield_11: u32,
}
#[test]
fn bindgen_test_layout_timex() {
    assert_eq!(::std::mem::size_of::<timex>() , 208usize);
    assert_eq!(::std::mem::align_of::<timex>() , 8usize);
}
impl Clone for timex {
    fn clone(&self) -> Self { *self }
}
impl timex {
    #[inline]
    pub fn at_offset_0(&self) -> ::std::os::raw::c_int {
        unsafe {
            ::std::mem::transmute(((self._bitfield_1 &
                                        (4294967295usize as u32)) >> 0u32) as
                                      u32)
        }
    }
    ...
    #[inline]
    pub fn at_offset_0(&self) -> ::std::os::raw::c_int {
        unsafe {
            ::std::mem::transmute(((self._bitfield_2 &
                                        (4294967295usize as u32)) >> 0u32) as
                                      u32)
        }
    }
    ...

@emilio
Copy link
Contributor

emilio commented Dec 30, 2016

Yes, you should whitelist the rpm stuff you want, using regexes.

For example: `--whitelist-function "rpm.*".

@fitzgen
Copy link
Member

fitzgen commented Jul 21, 2017

@sa2ajj are you still hitting this on master? If so, the best way to contribute to resolving this bug would be to create a reduced test case.

@sa2ajj
Copy link
Author

sa2ajj commented Oct 25, 2017

sorry for a slow follow-up: i'll check it during the coming weekend :/

@tarcieri
Copy link

tarcieri commented Apr 9, 2018

I've managed to use bindgen to produce a Rust binding for librpm.so, librpmio.so, librpmbuild.so, and librpmsign.so (heads up @sa2ajj):

https://github.com/iqlusion-io/crates/tree/master/rpmlib-sys

I should start by noting that all of the issues being discussed in this thread, at least for me, have been fixed, and IMO the issue can probably be closed.

I ran into several other minor (not-really-bindgen-bug) issues, most of which I've managed to address. Many of them were fixed by having bindgen build a C++ binding instead of a C one. If you want the gorey details you can read about them here:

iqlusioninc/crates#11
iqlusioninc/crates#12
iqlusioninc/crates#17

@emilio
Copy link
Contributor

emilio commented Apr 9, 2018

Ok, I'll close this based on that, thanks @tarcieri!

@tony-iqlusion
Copy link

tony-iqlusion commented Apr 9, 2018

@emilio thanks for the pointers... looks like #1252 is about the same silly header file I was having trouble with on iqlusioninc/crates#12 ! Glad I found a workaround.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

5 participants