rust-bindgen icon indicating copy to clipboard operation
rust-bindgen copied to clipboard

type is redefined

Open alexcwyu opened this issue 2 years ago • 2 comments

Input C/C++ Header

Header

#include "AeronArchive.h"

the actual header can be found here https://github.com/real-logic/aeron/blob/1.41.4/aeron-archive/src/main/cpp/client/AeronArchive.h

Bindgen Invocation

bindgen code

    println!("cargo:rerun-if-changed=build.rs");
    println!("cargo:rerun-if-changed=bindings.h");

    let aeron_path = canonicalize(Path::new("./aeron")).unwrap();
    let header_path = aeron_path.join("aeron-archive/src/main/cpp/client");
    let out_path = PathBuf::from(env::var("OUT_DIR").unwrap());

    let cmake_output = Config::new(&aeron_path)
        .build();

    let base_lib_dir = cmake_output.join("build");
    println!(
        "cargo:rustc-link-search=native={}",
        base_lib_dir.join("lib").display()
    );
    // Because the `cmake_output` path is different for debug/release, we're not worried
    // about accidentally linking the Debug library when this is a release build or vice-versa
    println!(
        "cargo:rustc-link-search=native={}",
        base_lib_dir.join("lib/Debug").display()
    );
    println!(
        "cargo:rustc-link-search=native={}",
        base_lib_dir.join("binaries/Debug").display()
    );
    println!(
        "cargo:rustc-link-search=native={}",
        base_lib_dir.join("lib/Release").display()
    );
    println!(
        "cargo:rustc-link-search=native={}",
        base_lib_dir.join("binaries/Release").display()
    );

    println!("cargo:rustc-link-lib=static=aeron_archive_client");
    println!("cargo:rustc-link-lib=static=aeron_archive_client_wrapper");
    println!("cargo:rustc-link-lib=stdc++");

    println!("cargo:include={}", header_path.display());
    let bindings = bindgen::Builder::default()
        .clang_arg(format!("-I{}", header_path.display()))
        .clang_arg(format!(
            "-I{}",
            aeron_path.join("aeron-client/src/main/c").display()
        ))
        .header("bindings.h")
        .enable_cxx_namespaces()
        // enable C++
        .clang_args(&["-x", "c++", "--std=c++14"])
        .opaque_type("std::.*")
        .constified_enum_module("aeron_.*_enum")
        .derive_debug(false)
        .parse_callbacks(Box::new(bindgen::CargoCallbacks))
        .generate()
        .expect("Unable to generate aeron bindings");

    bindings
        .write_to_file(out_path.join("bindings.rs"))
        .expect("Couldn't write bindings!");

Actual Results

error

error[E0428]: the name `this_t` is defined multiple times
     --> /home/alex/workspaces/personal/aeron-lib/target/debug/build/libaeron_archive-sys-0a7352ee9f461a4a/out/bindings.rs:10595:5
      |
10115 |     pub type this_t = root::aeron::concurrent::logbuffer::BufferClaim;
      |     ------------------------------------------------------------------ previous definition of the type `this_t` here
...
10595 |     pub type this_t = root::aeron::ChannelUri;
      |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `this_t` redefined here
      |
      = note: `this_t` must be defined only once in the type namespace of this module

error[E0428]: the name `this_t` is defined multiple times
     --> /home/alex/workspaces/personal/aeron-lib/target/debug/build/libaeron_archive-sys-0a7352ee9f461a4a/out/bindings.rs:10597:5
      |
10115 |     pub type this_t = root::aeron::concurrent::logbuffer::BufferClaim;
      |     ------------------------------------------------------------------ previous definition of the type `this_t` here
...
10597 |     pub type this_t = root::aeron::archive::client::Context;
      |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `this_t` redefined here
      |
      = note: `this_t` must be defined only once in the type namespace of this module

error[E0428]: the name `this_t` is defined multiple times
     --> /home/alex/workspaces/personal/aeron-lib/target/debug/build/libaeron_archive-sys-0a7352ee9f461a4a/out/bindings.rs:10598:5
      |
10115 |     pub type this_t = root::aeron::concurrent::logbuffer::BufferClaim;
      |     ------------------------------------------------------------------ previous definition of the type `this_t` here
...
10598 |     pub type this_t = root::aeron::BufferBuilder;
      |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `this_t` redefined here
      |
      = note: `this_t` must be defined only once in the type namespace of this module

generated file

// skip other line....
    pub type this_t = root::aeron::ChannelUri;
    pub type this_t = root::aeron::archive::client::Context;
    pub type this_t = root::aeron::BufferBuilder;
}

Expected Results

no redefined type

alexcwyu avatar Jun 30 '23 03:06 alexcwyu

This sounds like another of those C++ template issues where we don't have a straight solution and it is mostly caused by how libclang exposes the information of the templates. There's not much we can do about how clang exposes this and using other tools like libtooling is not viable due to distribution issues.

pvdrz avatar Jul 24 '23 16:07 pvdrz

I wanted to get creduced test cases even if there might not be a solution soon.

Here is the preprocessed header output. __bindgen.hpp.gz

I grepped for 3 things in the interestingness tests for creduce when running rustc --test on the bindings

  • previous definition of the type
  • erroneous constant encountered
  • cycle detected when expanding type alias

test-case1.hpp

typedef long a;
template <typename = int> class b {
  typedef int bu;
  typedef b bv;
  bv &bw(bu *, a, bu);
};
template <> b<> &b<>::bw(bu *, a, bu);
template <> b<wchar_t> &b<wchar_t>::bw(bu *, a, bu);

test-case1.rs

/* automatically generated by rust-bindgen 0.69.4 */

pub type a = ::std::os::raw::c_long;
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct b {
    pub _address: u8,
}
pub type b_bu = ::std::os::raw::c_int;
pub type b_bv = b;
pub type bu = ::std::os::raw::c_int;
pub type bu = ::std::os::raw::c_int;

test-case2.hpp

template <typename, typename a> class d { a ay; };
template <typename, typename, typename, typename b> using bf = d<b, int>;
template <typename b> class e { bf<int, int, int, b> bh; };
e<int> c;

test-case2.rs

/* automatically generated by rust-bindgen 0.69.4 */

#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct d<a> {
    pub ay: a,
    pub _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell<a>>,
}
pub type bf = d<a>;
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct e {
    pub bh: bf,
}
#[test]
fn __bindgen_test_layout_e_open0_int_close0_instantiation() {
    assert_eq!(
        ::std::mem::size_of::<e>(),
        4usize,
        concat!("Size of template specialization: ", stringify!(e))
    );
    assert_eq!(
        ::std::mem::align_of::<e>(),
        4usize,
        concat!("Alignment of template specialization: ", stringify!(e))
    );
}
extern "C" {
    pub static mut c: e;
}

test-case3.hpp

typedef struct a b;
template <typename, typename = a> class bk;
template <typename> struct c { typedef int bm; };
struct a : c<int> {};
template <typename, typename bu> class bk {
  typedef typename bu::bm bm;
  typedef bk by;
  by &ca(b, bm);
};
template <> bk<wchar_t> &bk<wchar_t>::ca(b, bm);

test-case3.rs

pub struct c {
    pub _address: u8,
}
pub type c_bm = ::std::os::raw::c_int;
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct a {
    pub _address: u8,
}
#[test]
fn bindgen_test_layout_a() {
    assert_eq!(
        ::std::mem::size_of::<a>(),
        1usize,
        concat!("Size of: ", stringify!(a))
    );
    assert_eq!(
        ::std::mem::align_of::<a>(),
        1usize,
        concat!("Alignment of ", stringify!(a))
    );
}
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct bk {
    pub _address: u8,
}
pub type bk_bm = [u8; 0usize];
pub type bk_by = bk;
#[test]
fn __bindgen_test_layout_c_open0_int_close0_instantiation() {
    assert_eq!(
        ::std::mem::size_of::<c>(),
        1usize,
        concat!("Size of template specialization: ", stringify!(c))
    );
    assert_eq!(
        ::std::mem::align_of::<c>(),
        1usize,
        concat!("Alignment of template specialization: ", stringify!(c))
    );
}
pub type bm = bm;
pub type bm = ::std::os::raw::c_int;

boydjohnson avatar Mar 16 '24 23:03 boydjohnson