Skip to content
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

bindgen generates empty vtables #478

Closed
Jascha-N opened this issue Feb 4, 2017 · 4 comments
Closed

bindgen generates empty vtables #478

Jascha-N opened this issue Feb 4, 2017 · 4 comments

Comments

@Jascha-N
Copy link

Jascha-N commented Feb 4, 2017

bindgen generates empty vtables when cross-compiling for ARM. I have made a reduced test-case, while leaving in the automatically generated Builder settings. clang is not able to find the right gcc toolchain so the script manually passes the system include directories (which might be the wrong way to go about?).

input.hpp:

class Foo
{
  public:
    virtual void bar() = 0;
};

Actual output.rs:

/* automatically generated by rust-bindgen */

#[repr(C)]
pub struct Foo__bindgen_vtable {
}
#[repr(C)]
#[derive(Debug, Copy)]
pub struct Foo {
    pub vtable_: *const Foo__bindgen_vtable,
}
#[test]
fn bindgen_test_layout_Foo() {
    assert_eq!(::core::mem::size_of::<Foo>() , 4usize);
    assert_eq!(::core::mem::align_of::<Foo>() , 4usize);
}
impl Clone for Foo {
    fn clone(&self) -> Self { *self }
}

Expected output.rs:

/* ... */

#[repr(C)]
pub struct Foo__bindgen_vtable {
    /* Something here? */
}

/* ... */

Builder settings (pretty-printed debug):

Builder {
    options: BindgenOptions {
        hidden_types: RegexSet {
            items: [],
            set: None
        },
        opaque_types: RegexSet {
            items: [],
            set: None
        },
        whitelisted_types: RegexSet {
            items: [],
            set: None
        },
        whitelisted_functions: RegexSet {
            items: [],
            set: None
        },
        whitelisted_vars: RegexSet {
            items: [],
            set: None
        },
        bitfield_enums: RegexSet {
            items: [],
            set: None
        },
        constified_enums: RegexSet {
            items: [],
            set: None
        },
        builtins: false,
        links: [],
        emit_ast: false,
        emit_ir: false,
        enable_cxx_namespaces: false,
        disable_name_namespacing: false,
        derive_debug: true,
        unstable_rust: true,
        use_core: true,
        ctypes_prefix: Some(
            "::c_types"
        ),
        namespaced_constants: true,
        msvc_mangling: false,
        convert_floats: true,
        raw_lines: [],
        clang_args: [
            "-target",
            "thumbv6m-none-eabi",
            "-isystem",
            "c:\\users\\jascha\\appdata\\local\\arduino15\\packages\\arduino\\tools\\arm-none-eabi-gcc\\4.8.3-2014q1\\bin\\../lib/gcc/arm-none-eabi/4.8.3/../../../../arm-none-eabi/include/c++/4.8.3",
            "-isystem",
            "c:\\users\\jascha\\appdata\\local\\arduino15\\packages\\arduino\\tools\\arm-none-eabi-gcc\\4.8.3-2014q1\\bin\\../lib/gcc/arm-none-eabi/4.8.3/../../../../arm-none-eabi/include/c++/4.8.3/arm-none-eabi",
            "-isystem",
            "c:\\users\\jascha\\appdata\\local\\arduino15\\packages\\arduino\\tools\\arm-none-eabi-gcc\\4.8.3-2014q1\\bin\\../lib/gcc/arm-none-eabi/4.8.3/../../../../arm-none-eabi/include/c++/4.8.3/backward",
            "-isystem",
            "c:\\users\\jascha\\appdata\\local\\arduino15\\packages\\arduino\\tools\\arm-none-eabi-gcc\\4.8.3-2014q1\\bin\\../lib/gcc/arm-none-eabi/4.8.3/include",
            "-isystem",
            "c:\\users\\jascha\\appdata\\local\\arduino15\\packages\\arduino\\tools\\arm-none-eabi-gcc\\4.8.3-2014q1\\bin\\../lib/gcc/arm-none-eabi/4.8.3/include-fixed",
            "-isystem",
            "c:\\users\\jascha\\appdata\\local\\arduino15\\packages\\arduino\\tools\\arm-none-eabi-gcc\\4.8.3-2014q1\\bin\\../lib/gcc/arm-none-eabi/4.8.3/../../../../arm-none-eabi/include",
            "-std=gnu++11",
            "-DF_CPU=48000000L",
            "-DARDUINO=10600",
            "-DARDUINO_SAMD_FEATHER_M0",
            "-DARDUINO_ARCH_SAMD",
            "-DARDUINO_SAMD_ZERO",
            "-D__SAMD21G18A__",
            "-DUSB_VID=0x239A",
            "-DUSB_PID=0x800B",
            "-DUSBCON",
            "-DUSB_MANUFACTURER=\"Adafruit\"",
            "-DUSB_PRODUCT=\"Feather M0\"",
            "-IC:\\Users\\Jascha\\AppData\\Local\\Arduino15\\packages\\arduino\\tools\\CMSIS\\4.0.0-atmel/CMSIS/Include/",
            "-IC:\\Users\\Jascha\\AppData\\Local\\Arduino15\\packages\\arduino\\tools\\CMSIS\\4.0.0-atmel/Device/ATMEL/",
            "-IC:\\Users\\Jascha\\AppData\\Local\\Arduino15\\packages\\adafruit\\hardware\\samd\\1.0.13\\cores\\arduino",
            "-IC:\\Users\\Jascha\\AppData\\Local\\Arduino15\\packages\\adafruit\\hardware\\samd\\1.0.13\\variants\\arduino_zero"
        ],
        input_header: Some(
            "src/arduino_core.hpp"
        ),
        dummy_uses: None,
        type_chooser: None,
        codegen_config: CodegenConfig {
            functions: true,
            types: true,
            vars: true,
            methods: true,
            constructors: true
        },
        conservative_inline_namespaces: false,
        generate_comments: false,
        whitelist_recursively: true,
        objc_extern_crate: false
    }
}
@emilio
Copy link
Contributor

emilio commented Feb 4, 2017

Yeah, not config-specific.

We generate empty vtables always so far. That's because nobody has stopped to figure out what the correct vtable layout is in complex cases, what is the order for the vtable methods (we need to look in the base class chain for that), etc... MSVC and gcc/clang generate different vtable layouts for method overloads, also, as far as I know.

So we generate a dummy pointer-sized member so classes have the correct layout.

We definitely keep track of virtual methods and could attempt to do it (in this case it'd be trivial), but we need to consider all the complex cases too IMO, or at least a way to test that the vtable layout we generate is correct.

@ebkalderon
Copy link

@emilio If I were writing Rust bindings to a C++ library which hands out mostly abstract classes with pure virtual methods, would this mean I cannot rely on bindgen to correctly generate the vtables? I was not aware of this by looking at the bindgen book. Would I need resort to writing a C++ wrapper for each of these abstract classes instead, at least until bindgen can properly support them?

@emilio
Copy link
Contributor

emilio commented Jan 29, 2018

If I were writing Rust bindings to a C++ library which hands out mostly abstract classes with pure virtual methods, would this mean I cannot rely on bindgen to correctly generate the vtables? I was not aware of this by looking at the bindgen book. Would I need resort to writing a C++ wrapper for each of these abstract classes instead, at least until bindgen can properly support them?

Yeah, I think that's pretty much it. There's another issue where the difficulties of this are explained (#27).

I think figuring out what's the subset that works properly cross-platform (at least GCC / clang / MSVC) may not be hard, it just requires research and writing tests.

If someone is interested in giving it a shot I'm happy to mentor, but most of the information needed is probably available already from the vtable codegen code.

@emilio
Copy link
Contributor

emilio commented Aug 29, 2020

Let's close this as a dupe of #27. I think a basic implementation for where there are no overloads should be relatively easy.

@emilio emilio closed this as completed Aug 29, 2020
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

4 participants