Skip to content

Support for one set of bindings depending on another (conflicting __BindgenBitfieldUnit) #2835

Closed
@ian-h-chamberlain

Description

@ian-h-chamberlain

Hi! This is kind of a feature request for a (maybe unusual) use case where bindings are generated in multiple different crates. In our case we have citro3d-sys which depends on some types in ctru-sys.

The idea is to reuse existing types from ctru-sys wherever possible, instead of regenerating a duplicate definition. For the most part, this works great with allowlist_type / blocklist_type, so we can use something like this:

use ctru_sys::*;
use libc::*;
include!(concat!(env!("OUT_DIR"), "/bindings.rs"));

There is one exception where this doesn't work — bindgen-generated types for bitfields. The various _bindgen_ty_* seem to avoid overlap (whether this is by design due to deterministic naming, or just coincidence?), but both sets generate pub struct __BindgenBitfieldUnit<Storage> as well, which unfortunately does overlap.

Input C/C++ Header

Minimal reproduction with two crates a and b:

a.h:

typedef struct A {
  unsigned char x;
  unsigned b1 : 1;
  unsigned b2 : 1;
  unsigned baz;
} A;

b.h:

#include "../a/a.h"

typedef struct B {
  A a;
} B;

typedef struct C {
  unsigned char x;
  unsigned b1 : 1;
  unsigned b2 : 1;
  unsigned baz;
} C;

Bindgen Invocation

a/build.rs:

    bindgen::Builder::default()
        .header("a.h")
        .generate()
        .expect("Unable to generate bindings")
        .write_to_file(PathBuf::from(std::env::var("OUT_DIR").unwrap()).join("bindings.rs"))
        .expect("Couldn't write bindings!");

b/build.rs:

    bindgen::Builder::default()
        .header("b.h")
        .blocklist_type("A")
        .generate()
        .expect("Unable to generate bindings")
        .write_to_file(PathBuf::from(std::env::var("OUT_DIR").unwrap()).join("bindings.rs"))
        .expect("Couldn't write bindings!");

Actual Results

With b/lib.rs:

// Makes it clear when there are duplicates:
#![deny(ambiguous_glob_reexports)]

pub use a::*;

mod bindings {
    use a::*;
    include!(concat!(env!("OUT_DIR"), "/bindings.rs"));
}

pub use bindings::*;
$ cargo check --workspace
   Compiling b v0.1.0 (/Users/ianchamberlain/Documents/Development/rs-sandbox/b)
error: ambiguous glob re-exports
  --> b/src/lib.rs:3:9
   |
3  | pub use a::*;
   |         ^^^^ the name `__BindgenBitfieldUnit` in the type namespace is first re-exported here
...
11 | pub use bindings::*;
   |         ----------- but the name `__BindgenBitfieldUnit` in the type namespace is also re-exported here
   |
note: the lint level is defined here
  --> b/src/lib.rs:1:9
   |
1  | #![deny(ambiguous_glob_reexports)]
   |         ^^^^^^^^^^^^^^^^^^^^^^^^

error: could not compile `b` (lib) due to 1 previous error

Expected Results

I think the simplest option to address this in our case would be a flag to skip generating the __BindgenBitfieldUnit type — would a PR be accepted to add such a flag? I have mostly worked out the implementation already, but maybe there's a better/simpler way to support this kind of use case?

If it would be accepted, I can open a PR adding a skip_bindgen_bitfield_unit flag, which in this case could be used to avoid the generated conflict by reusing a's version of the struct instead of generating a new one in b.

Thank you!

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions