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

Generating bindings for headers using STL types #598

Closed
lostman opened this issue Mar 21, 2017 · 14 comments
Closed

Generating bindings for headers using STL types #598

lostman opened this issue Mar 21, 2017 · 14 comments

Comments

@lostman
Copy link

lostman commented Mar 21, 2017

I'm trying to generate bindings for a header that uses STL types:

// cpp/Test.hpp
#include<string>

class Test {
private:
    std::string m_value;
public:
    Test();
    const char* get_value();
};

Test::Test() {
    m_value = "test";
};

const char* Test::get_value() {
    return m_value.c_str();
}

README states:

You must use whitelisting when working with C++ to avoid pulling in all of the std::*

which makes it sound like it should work. My bindgen configuration is:

    let bindings = Builder::default()
        .enable_cxx_namespaces()
        .raw_line("pub use self::root::*;")
        .header("cpp/Test.hpp")
        .clang_arg("-x")
        .clang_arg("c++")
        .clang_arg("-std=c++14")
        .clang_arg("-stdlib=libc++")
        .whitelist_recursively(false)
        .whitelisted_type("Test")
        // also tried
        // .opaque_type("std::string")
        .generate()
        .expect("Unable to generate bindings");

However, bindgen fails with:

thread 'main' panicked at 'Should have found the template definition one way or another', src/libcore/option.rs:785

Could you clarify whether this should work?

@emilio
Copy link
Contributor

emilio commented Mar 21, 2017

Yup, this is expected to work, but it fails right now because of unexpected regressions from #544.

cc @fitzgen.

We're working that out in #585 and #584, that's why there isn't a newly published version yet.

@lostman
Copy link
Author

lostman commented Mar 22, 2017

Thanks! I'll try a different version and see if I can get it working.

Where would be the best place to ask about best practices? For instance, if I had

std::string Test::get_string_value() {
    return m_value;
}

And set std::string as opaque, would I still be able to call it's methods from Rust (c_str and constructor in particular). Or would I need my own wrappers:

const char* from_string(std::string s) {
    return s.c_str();
}

std::string to_string(const char* s) {
    return std::string(s);
}

@lostman
Copy link
Author

lostman commented Mar 24, 2017

Another issue I came across involves virtual functions:

// cpp/Test.hpp
class Test {
public:
    virtual void do_stuff();
};

with an out-of-line default implementation:

// cpp/Test.cpp
#include "Test.hpp"
#include <iostream>

void Test::do_stuff() {
    std::cout << "do stuff!" << std::endl;
}

Unfortunately this doesn't generate a binding. I was able to work around it with a wrapper:

void test_do_stuff(Test t) { t.do_stuff(); }

I was also able to add this function manually:

extern "C" {
    #[link_name = "_ZN4Test8do_stuffEv"]
    pub fn Test_do_stuff(t: &mut bindings::Test);
}

impl bindings::Test {
    pub unsafe fn do_stuff(&mut self) {
        Test_do_stuff(&mut *self)
    }
}

And that works:

#[test]
fn test_do_stuff() {
    unsafe {
        let mut x = bindings::Test::new();
        x.do_stuff()
    }
}

@emilio
Copy link
Contributor

emilio commented Mar 25, 2017

That wouldn't do the right thing if any other instance would override the virtual function. The proper thing to do is to fill the VTable with method pointers, and generate methods calling through them.

Nobody has got to do it yet though, and vtable layout is kinda hard and not interoperable between MSVC and LLVM/gcc last time I checked, so it's not a trivial problem to solve.

@emilio
Copy link
Contributor

emilio commented Mar 25, 2017

Regarding

And set std::string as opaque, would I still be able to call it's methods from Rust (c_str and constructor in particular). Or would I need my own wrappers?

The reply is you would need your own wrappers, at least for now. String inherits from basic_string<char_t> in all the libstd's I've known, and that's kinda hard to deal with, because we don't generate methods for template structs (they'd have different symbols depending on the instantiation, etc).

@lostman
Copy link
Author

lostman commented Mar 27, 2017

Thanks for clarifying! Another question, if I may. Is this a sane thing to do?

mem::transmute::<*mut Derived, *mut Base>(&mut value)

Otherwise I'll need more wrappers:

Base* derived_to_base(Derived* x) {
    return static_cast<Base*>(x);
}

@emilio
Copy link
Contributor

emilio commented Mar 27, 2017

You should be able to just use &mut value._base, right?

@lostman
Copy link
Author

lostman commented Mar 28, 2017

Thanks! Didn't know that's the way to do it.

@fitzgen
Copy link
Member

fitzgen commented Apr 6, 2017

On master with libclang 3.9, invoking bindgen like this:

$ cargo run -- ~/scratch/bindgen-issue-598.hpp --whitelist-type Test -- -std=c++14

then I get this:

/* automatically generated by rust-bindgen */

#[repr(C)]
pub struct std___cxx11_basic_string<_CharT> {
    pub _M_dataplus: std_basic_string__Alloc_hider,
    pub _M_string_length: std_basic_string_size_type,
    pub __bindgen_anon_1: std_basic_string__bindgen_ty_2<_CharT>,
}
pub type std___cxx11_basic_string__Char_alloc_type = __gnu_cxx___alloc_traits;
pub type std___cxx11_basic_string__Alloc_traits = __gnu_cxx___alloc_traits;
pub type std___cxx11_basic_string_traits_type<_Traits> = _Traits;
pub type std___cxx11_basic_string_value_type = [u8; 0usize];
pub type std___cxx11_basic_string_allocator_type =
    std_basic_string__Char_alloc_type;
pub type std___cxx11_basic_string_size_type = std_basic_string__Alloc_traits;
pub type std___cxx11_basic_string_difference_type =
    std_basic_string__Alloc_traits;
pub type std___cxx11_basic_string_reference = std_basic_string__Alloc_traits;
pub type std___cxx11_basic_string_const_reference =
    std_basic_string__Alloc_traits;
pub type std___cxx11_basic_string_pointer = std_basic_string__Alloc_traits;
pub type std___cxx11_basic_string_const_pointer =
    std_basic_string__Alloc_traits;
pub type std___cxx11_basic_string_iterator =
    __gnu_cxx___normal_iterator<std_basic_string_pointer>;
pub type std___cxx11_basic_string_const_iterator =
    __gnu_cxx___normal_iterator<std_basic_string_const_pointer>;
pub type std___cxx11_basic_string_const_reverse_iterator =
    std_reverse_iterator<std_basic_string_const_iterator>;
pub type std___cxx11_basic_string_reverse_iterator =
    std_reverse_iterator<std_basic_string_iterator>;
pub type std___cxx11_basic_string___const_iterator =
    std_basic_string_const_iterator;
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct std___cxx11_basic_string__Alloc_hider {
    pub _M_p: std_basic_string_pointer,
}
pub const std___cxx11_basic_string__S_local_capacity:
          std_basic_string__bindgen_ty_1 =
    std___cxx11_basic_string__bindgen_ty_1::_S_local_capacity;
#[repr(i32)]
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub enum std___cxx11_basic_string__bindgen_ty_1 { _S_local_capacity = 0, }
#[repr(C)]
pub union std___cxx11_basic_string__bindgen_ty_2<_CharT> {
    pub _M_local_buf: *mut _CharT,
    pub _M_allocated_capacity: std_basic_string_size_type,
}
pub type std___cxx11_string = std_basic_string<::std::os::raw::c_char>;
#[repr(C)]
#[derive(Debug)]
pub struct std_allocator {
    pub _address: u8,
}
pub type std_allocator_size_type = usize;
pub type std_allocator_difference_type = isize;
pub type std_allocator_pointer<_Tp> = *mut _Tp;
pub type std_allocator_const_pointer<_Tp> = *mut _Tp;
pub type std_allocator_reference<_Tp> = *mut _Tp;
pub type std_allocator_const_reference<_Tp> = *mut _Tp;
pub type std_allocator_value_type<_Tp> = _Tp;
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct std_allocator_rebind {
    pub _address: u8,
}
pub type std_allocator_rebind_other = std_allocator;
pub type std_allocator_propagate_on_container_move_assignment = std_true_type;
pub type std_allocator_is_always_equal = std_true_type;
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct std_char_traits {
    pub _address: u8,
}
#[test]
fn __bindgen_test_layout_std_char_traits_instantiation_5183() {
    assert_eq!(::std::mem::size_of::<std_char_traits>() , 1usize , concat ! (
               "Size of template specialization: " , stringify ! (
               std_char_traits ) ));
    assert_eq!(::std::mem::align_of::<std_char_traits>() , 1usize , concat ! (
               "Alignment of template specialization: " , stringify ! (
               std_char_traits ) ));
}
pub type std_true_type = u8;
pub type std_false_type = u8;
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct std___and_ {
    pub _address: u8,
}
#[repr(C)]
pub struct std_is_empty {
    pub _address: u8,
}
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct std_make_unsigned {
    pub _address: u8,
}
pub type std_make_unsigned_type = u8;
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct std___detector {
    pub _address: u8,
}
pub type std___detector_value_t = std_false_type;
pub type std___detector_type<_Default> = _Default;
pub type std___detected_or = std___detector;
pub type std___detected_or_t = std___detected_or;
pub type std___detected_or_t_ = std___detected_or_t;
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct std_iterator {
    pub _address: u8,
}
pub type std_iterator_iterator_category<_Category> = _Category;
pub type std_iterator_value_type<_Tp> = _Tp;
pub type std_iterator_difference_type<_Distance> = _Distance;
pub type std_iterator_pointer<_Pointer> = _Pointer;
pub type std_iterator_reference<_Reference> = _Reference;
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct std___iterator_traits {
    pub _address: u8,
}
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct std_iterator_traits {
    pub _address: u8,
}
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct std___undefined([u8; 0]);
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct std___get_first_arg {
    pub _address: u8,
}
pub type std___get_first_arg_type = std___undefined;
pub type std___get_first_arg_t = std___get_first_arg;
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct std___replace_first_arg {
    pub _address: u8,
}
pub type std___replace_first_arg_type = std___undefined;
pub type std___replace_first_arg_t = std___replace_first_arg;
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct std_pointer_traits {
    pub _address: u8,
}
pub type std_pointer_traits___element_type = [u8; 0usize];
pub type std_pointer_traits___difference_type = [u8; 0usize];
pub type std_pointer_traits___rebind = [u8; 0usize];
pub type std_pointer_traits_pointer<_Ptr> = _Ptr;
pub type std_pointer_traits_element_type = std___detected_or_t_;
pub type std_pointer_traits_difference_type = std___detected_or_t;
pub type std_pointer_traits_rebind = std___detected_or_t_;
pub type std___ptr_rebind = std_pointer_traits;
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct std_reverse_iterator<_Iterator> {
    pub current: _Iterator,
}
pub type std_reverse_iterator___traits_type = std_iterator_traits;
pub type std_reverse_iterator_iterator_type<_Iterator> = _Iterator;
pub type std_reverse_iterator_difference_type =
    std_reverse_iterator___traits_type;
pub type std_reverse_iterator_pointer = std_reverse_iterator___traits_type;
pub type std_reverse_iterator_reference = std_reverse_iterator___traits_type;
pub type std_streamoff = ::std::os::raw::c_long;
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct std_fpos<_StateT> {
    pub _M_off: std_streamoff,
    pub _M_state: _StateT,
}
pub type std_streampos = std_fpos<__mbstate_t>;
pub type std___allocator_base = __gnu_cxx_new_allocator;
#[test]
fn __bindgen_test_layout_std_allocator_instantiation_8734() {
    assert_eq!(::std::mem::size_of::<std_allocator>() , 1usize , concat ! (
               "Size of template specialization: " , stringify ! (
               std_allocator ) ));
    assert_eq!(::std::mem::align_of::<std_allocator>() , 1usize , concat ! (
               "Alignment of template specialization: " , stringify ! (
               std_allocator ) ));
}
#[repr(C)]
#[derive(Debug, Copy)]
pub struct std___allocator_traits_base {
    pub _address: u8,
}
pub type std___allocator_traits_base___rebind = [u8; 0usize];
pub type std___allocator_traits_base___pointer = [u8; 0usize];
pub type std___allocator_traits_base___c_pointer = [u8; 0usize];
pub type std___allocator_traits_base___v_pointer = [u8; 0usize];
pub type std___allocator_traits_base___cv_pointer = [u8; 0usize];
pub type std___allocator_traits_base___diff_type = [u8; 0usize];
pub type std___allocator_traits_base___size_type = [u8; 0usize];
pub type std___allocator_traits_base___pocca = [u8; 0usize];
pub type std___allocator_traits_base___pocma = [u8; 0usize];
pub type std___allocator_traits_base___pocs = [u8; 0usize];
pub type std___allocator_traits_base___equal = [u8; 0usize];
#[test]
fn bindgen_test_layout_std___allocator_traits_base() {
    assert_eq!(::std::mem::size_of::<std___allocator_traits_base>() , 1usize ,
               concat ! (
               "Size of: " , stringify ! ( std___allocator_traits_base ) ));
    assert_eq! (::std::mem::align_of::<std___allocator_traits_base>() , 1usize
                , concat ! (
                "Alignment of " , stringify ! ( std___allocator_traits_base )
                ));
}
impl Clone for std___allocator_traits_base {
    fn clone(&self) -> Self { *self }
}
pub type std___alloc_rebind = std___detected_or_t_;
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct std_allocator_traits {
    pub _address: u8,
}
pub type std_allocator_traits_allocator_type<_Alloc> = _Alloc;
pub type std_allocator_traits_value_type = [u8; 0usize];
pub type std_allocator_traits_pointer = std___detected_or_t;
pub type std_allocator_traits_const_pointer = std___detected_or_t;
pub type std_allocator_traits_void_pointer = std___detected_or_t;
pub type std_allocator_traits_const_void_pointer = std___detected_or_t;
pub type std_allocator_traits_difference_type = std___detected_or_t;
pub type std_allocator_traits_size_type = std___detected_or_t;
pub type std_allocator_traits_propagate_on_container_copy_assignment =
    std___detected_or_t;
pub type std_allocator_traits_propagate_on_container_move_assignment =
    std___detected_or_t;
pub type std_allocator_traits_propagate_on_container_swap =
    std___detected_or_t;
pub type std_allocator_traits_is_always_equal = std___detected_or_t;
pub type std_allocator_traits_rebind_alloc = std___alloc_rebind;
pub type std_allocator_traits_rebind_traits = std_allocator_traits;
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct std_allocator_traits___construct_helper {
    pub _address: u8,
}
pub type std_allocator_traits___construct_helper_type<_Alloc> = _Alloc;
pub type std_allocator_traits___has_construct =
    std_allocator_traits___construct_helper;
#[test]
fn __bindgen_test_layout_std___cxx11_basic_string_instantiation_14120() {
    assert_eq!(::std::mem::size_of::<std_basic_string<::std::os::raw::c_char>>()
               , 32usize , concat ! (
               "Size of template specialization: " , stringify ! (
               std_basic_string<::std::os::raw::c_char> ) ));
    assert_eq!(::std::mem::align_of::<std_basic_string<::std::os::raw::c_char>>()
               , 8usize , concat ! (
               "Alignment of template specialization: " , stringify ! (
               std_basic_string<::std::os::raw::c_char> ) ));
}
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct __gnu_cxx___normal_iterator<_Iterator> {
    pub _M_current: _Iterator,
}
pub type __gnu_cxx___normal_iterator___traits_type = std_iterator_traits;
pub type __gnu_cxx___normal_iterator_iterator_type<_Iterator> = _Iterator;
pub type __gnu_cxx___normal_iterator_iterator_category =
    __gnu_cxx___normal_iterator___traits_type;
pub type __gnu_cxx___normal_iterator_value_type =
    __gnu_cxx___normal_iterator___traits_type;
pub type __gnu_cxx___normal_iterator_difference_type =
    __gnu_cxx___normal_iterator___traits_type;
pub type __gnu_cxx___normal_iterator_reference =
    __gnu_cxx___normal_iterator___traits_type;
pub type __gnu_cxx___normal_iterator_pointer =
    __gnu_cxx___normal_iterator___traits_type;
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct __gnu_cxx__Char_types {
    pub _address: u8,
}
pub type __gnu_cxx__Char_types_int_type = ::std::os::raw::c_ulong;
pub type __gnu_cxx__Char_types_pos_type = std_streampos;
pub type __gnu_cxx__Char_types_off_type = std_streamoff;
pub type __gnu_cxx__Char_types_state_type = mbstate_t;
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct __gnu_cxx_char_traits {
    pub _address: u8,
}
pub type __gnu_cxx_char_traits_char_type<_CharT> = _CharT;
pub type __gnu_cxx_char_traits_int_type = __gnu_cxx__Char_types;
pub type __gnu_cxx_char_traits_pos_type = __gnu_cxx__Char_types;
pub type __gnu_cxx_char_traits_off_type = __gnu_cxx__Char_types;
pub type __gnu_cxx_char_traits_state_type = __gnu_cxx__Char_types;
#[repr(C)]
#[derive(Debug)]
pub struct __gnu_cxx_new_allocator {
    pub _address: u8,
}
pub type __gnu_cxx_new_allocator_size_type = usize;
pub type __gnu_cxx_new_allocator_difference_type = isize;
pub type __gnu_cxx_new_allocator_pointer<_Tp> = *mut _Tp;
pub type __gnu_cxx_new_allocator_const_pointer<_Tp> = *mut _Tp;
pub type __gnu_cxx_new_allocator_reference<_Tp> = *mut _Tp;
pub type __gnu_cxx_new_allocator_const_reference<_Tp> = *mut _Tp;
pub type __gnu_cxx_new_allocator_value_type<_Tp> = _Tp;
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct __gnu_cxx_new_allocator_rebind {
    pub _address: u8,
}
pub type __gnu_cxx_new_allocator_rebind_other = __gnu_cxx_new_allocator;
pub type __gnu_cxx_new_allocator_propagate_on_container_move_assignment =
    std_true_type;
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct __gnu_cxx___alloc_traits {
    pub _address: u8,
}
pub type __gnu_cxx___alloc_traits_allocator_type<_Alloc> = _Alloc;
pub type __gnu_cxx___alloc_traits__Base_type = std_allocator_traits;
pub type __gnu_cxx___alloc_traits_value_type =
    __gnu_cxx___alloc_traits__Base_type;
pub type __gnu_cxx___alloc_traits_pointer =
    __gnu_cxx___alloc_traits__Base_type;
pub type __gnu_cxx___alloc_traits_const_pointer =
    __gnu_cxx___alloc_traits__Base_type;
pub type __gnu_cxx___alloc_traits_size_type =
    __gnu_cxx___alloc_traits__Base_type;
pub type __gnu_cxx___alloc_traits_difference_type =
    __gnu_cxx___alloc_traits__Base_type;
pub type __gnu_cxx___alloc_traits_reference =
    *mut __gnu_cxx___alloc_traits_value_type;
pub type __gnu_cxx___alloc_traits_const_reference =
    *const __gnu_cxx___alloc_traits_value_type;
pub type __gnu_cxx___alloc_traits___is_custom_pointer = std___and_;
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct __gnu_cxx___alloc_traits_rebind {
    pub _address: u8,
}
pub type __gnu_cxx___alloc_traits_rebind_other =
    __gnu_cxx___alloc_traits__Base_type;
#[repr(C)]
#[derive(Copy)]
pub struct __mbstate_t {
    pub __count: ::std::os::raw::c_int,
    pub __value: __mbstate_t__bindgen_ty_1,
}
#[repr(C)]
#[derive(Copy)]
pub union __mbstate_t__bindgen_ty_1 {
    pub __wch: ::std::os::raw::c_uint,
    pub __wchb: [::std::os::raw::c_char; 4usize],
}
#[test]
fn bindgen_test_layout___mbstate_t__bindgen_ty_1() {
    assert_eq!(::std::mem::size_of::<__mbstate_t__bindgen_ty_1>() , 4usize ,
               concat ! (
               "Size of: " , stringify ! ( __mbstate_t__bindgen_ty_1 ) ));
    assert_eq! (::std::mem::align_of::<__mbstate_t__bindgen_ty_1>() , 4usize ,
                concat ! (
                "Alignment of " , stringify ! ( __mbstate_t__bindgen_ty_1 )
                ));
    assert_eq! (unsafe {
                & ( * ( 0 as * const __mbstate_t__bindgen_ty_1 ) ) . __wch as
                * const _ as usize } , 0usize , concat ! (
                "Alignment of field: " , stringify ! (
                __mbstate_t__bindgen_ty_1 ) , "::" , stringify ! ( __wch ) ));
    assert_eq! (unsafe {
                & ( * ( 0 as * const __mbstate_t__bindgen_ty_1 ) ) . __wchb as
                * const _ as usize } , 0usize , concat ! (
                "Alignment of field: " , stringify ! (
                __mbstate_t__bindgen_ty_1 ) , "::" , stringify ! ( __wchb )
                ));
}
impl Clone for __mbstate_t__bindgen_ty_1 {
    fn clone(&self) -> Self { *self }
}
#[test]
fn bindgen_test_layout___mbstate_t() {
    assert_eq!(::std::mem::size_of::<__mbstate_t>() , 8usize , concat ! (
               "Size of: " , stringify ! ( __mbstate_t ) ));
    assert_eq! (::std::mem::align_of::<__mbstate_t>() , 4usize , concat ! (
                "Alignment of " , stringify ! ( __mbstate_t ) ));
    assert_eq! (unsafe {
                & ( * ( 0 as * const __mbstate_t ) ) . __count as * const _ as
                usize } , 0usize , concat ! (
                "Alignment of field: " , stringify ! ( __mbstate_t ) , "::" ,
                stringify ! ( __count ) ));
    assert_eq! (unsafe {
                & ( * ( 0 as * const __mbstate_t ) ) . __value as * const _ as
                usize } , 4usize , concat ! (
                "Alignment of field: " , stringify ! ( __mbstate_t ) , "::" ,
                stringify ! ( __value ) ));
}
impl Clone for __mbstate_t {
    fn clone(&self) -> Self { *self }
}
pub type mbstate_t = __mbstate_t;
#[repr(C)]
pub struct Test {
    pub m_value: std_string,
}
#[test]
fn bindgen_test_layout_Test() {
    assert_eq!(::std::mem::size_of::<Test>() , 32usize , concat ! (
               "Size of: " , stringify ! ( Test ) ));
    assert_eq! (::std::mem::align_of::<Test>() , 8usize , concat ! (
                "Alignment of " , stringify ! ( Test ) ));
    assert_eq! (unsafe {
                & ( * ( 0 as * const Test ) ) . m_value as * const _ as usize
                } , 0usize , concat ! (
                "Alignment of field: " , stringify ! ( Test ) , "::" ,
                stringify ! ( m_value ) ));
}
extern "C" {
    #[link_name = "_ZN4Test9get_valueEv"]
    pub fn Test_get_value(this: *mut Test) -> *const ::std::os::raw::c_char;
}
extern "C" {
    #[link_name = "_ZN4TestC1Ev"]
    pub fn Test_Test(this: *mut Test);
}
impl Test {
    #[inline]
    pub unsafe fn get_value(&mut self) -> *const ::std::os::raw::c_char {
        Test_get_value(self)
    }
    #[inline]
    pub unsafe fn new() -> Self {
        let mut __bindgen_tmp = ::std::mem::uninitialized();
        Test_Test(&mut __bindgen_tmp);
        __bindgen_tmp
    }
}
#[test]
fn __bindgen_test_layout_std_integral_constant_instantiation_14264() {
    assert_eq!(::std::mem::size_of::<u8>() , 1usize , concat ! (
               "Size of template specialization: " , stringify ! ( u8 ) ));
    assert_eq!(::std::mem::align_of::<u8>() , 1usize , concat ! (
               "Alignment of template specialization: " , stringify ! ( u8 )
               ));
}
#[test]
fn __bindgen_test_layout_std_integral_constant_instantiation_14268() {
    assert_eq!(::std::mem::size_of::<u8>() , 1usize , concat ! (
               "Size of template specialization: " , stringify ! ( u8 ) ));
    assert_eq!(::std::mem::align_of::<u8>() , 1usize , concat ! (
               "Alignment of template specialization: " , stringify ! ( u8 )
               ));
}

@fitzgen
Copy link
Member

fitzgen commented Apr 6, 2017

Which, although very verbose, seems correct to me.

I suspect this got fixed in one of the recent related PRs.

@fitzgen
Copy link
Member

fitzgen commented Apr 6, 2017

Going to go ahead and close this issue; if I'm overlooking anything, please reopen :)

@fitzgen fitzgen closed this as completed Apr 6, 2017
@cbourjau
Copy link

cbourjau commented Jul 5, 2017

@fitzgen I ran into this issue via google. For me the problem is that bindgen's generated code creates some symbols with _cxx11 in their name but then references them without that part in their names. The code which you posted above seems to have the same issue imho (note the last line):

/* automatically generated by rust-bindgen */

#[repr(C)]
pub struct std___cxx11_basic_string<_CharT> {
    pub _M_dataplus: std_basic_string__Alloc_hider,
    pub _M_string_length: std_basic_string_size_type,
    pub __bindgen_anon_1: std_basic_string__bindgen_ty_2<_CharT>,
}
pub type std___cxx11_basic_string__Char_alloc_type = __gnu_cxx___alloc_traits;
pub type std___cxx11_basic_string__Alloc_traits = __gnu_cxx___alloc_traits;
pub type std___cxx11_basic_string_traits_type<_Traits> = _Traits;
pub type std___cxx11_basic_string_value_type = [u8; 0usize];
pub type std___cxx11_basic_string_allocator_type =
    std_basic_string__Char_alloc_type;       // <== Note the missing cxx11 here!
...

Since you wrote that this code looks correct to you, I wonder if I am missing something obvious here? I asked about this on IRC as well where it was pointed out that this might be an "ABI tagging" issue?

@fitzgen
Copy link
Member

fitzgen commented Jul 5, 2017

@cbourjau I didn't dig into the generated code, just squinted at it, in that comment. Was mostly comparing against what we did before, which was panic.

Would you mind filing a new issue with a reduced header and steps to reproduce and all that?

@YjyJeff
Copy link

YjyJeff commented Jul 12, 2021

Regarding

And set std::string as opaque, would I still be able to call it's methods from Rust (c_str and constructor in particular). Or would I need my own wrappers?

The reply is you would need your own wrappers, at least for now. String inherits from basic_string<char_t> in all the libstd's I've known, and that's kinda hard to deal with, because we don't generate methods for template structs (they'd have different symbols depending on the instantiation, etc).

Can I use it Without wrappers now?

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

No branches or pull requests

5 participants