1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
|
# Generating Bindings to C++
`bindgen` can handle some C++ features, but not all of them. To set
expectations: `bindgen` will give you the type definitions and FFI declarations
you need to build an API to the C++ library, but using those types in Rust will
be nowhere near as nice as using them in C++. You will have to manually call
constructors, destructors, overloaded operators, etc yourself.
When passing in header files, the file will automatically be treated as C++ if
it ends in `.hpp`. If it doesn't, adding `-x c++` clang args can be used to
force C++ mode. You probably also want to use `-std=c++14` or similar clang args
as well.
You pretty much **must** use [allowlisting](./allowlisting.md) when working
with C++ to avoid pulling in all of the `std::.*` types, many of which `bindgen`
cannot handle. Additionally, you may want to mark other types as
[opaque](./opaque.md) that `bindgen` stumbles on. It is recommended to mark
all of `std::.*` opaque, and to allowlist only precisely the functions and types
you intend to use.
You should read up on the [FAQs](./faq.md) as well.
## Supported Features
* Inheritance (for the most part; there are
[some outstanding bugs](https://github.com/rust-lang/rust-bindgen/issues/380))
* Methods
* Bindings to constructors and destructors (but they aren't implicitly or
automatically invoked)
* Function and method overloading
* Templates *without* specialization. You should be able to access individual
fields of the class or struct.
## Unsupported Features
When `bindgen` finds a type that is too difficult or impossible to translate
into Rust, it will automatically treat it as an opaque blob of bytes. The
philosophy is that
1. we should always get layout, size, and alignment correct, and
2. just because one type uses specialization, that shouldn't cause `bindgen` to
give up on everything else.
Without further ado, here are C++ features that `bindgen` does not support or
cannot translate into Rust:
* Inline functions and methods: see
["Why isn't `bindgen` generating bindings to inline functions?"](./faq.md#why-isnt-bindgen-generating-bindings-to-inline-functions)
* Template functions, methods of template classes and structs. We don't know
which monomorphizations exist, and can't create new ones because we aren't a
C++ compiler.
* Anything related to template specialization:
* Partial template specialization
* Traits templates
* Substitution Failure Is Not An Error (SFINAE)
* Cross language inheritance, for example inheriting from a Rust struct in C++.
* Automatically calling copy and/or move constructors or destructors. Supporting
this isn't possible with Rust's move semantics.
* Exceptions: if a function called through a `bindgen`-generated interface
raises an exception that is not caught by the function itself, this will
generate undefined behaviour. See
[the tracking issue for exceptions](https://github.com/rust-lang/rust-bindgen/issues/1208)
for more details.
* Many C++ specific aspects of calling conventions. For example in the Itanium abi types that are
"[non trivial for the purposes of calls](https://itanium-cxx-abi.github.io/cxx-abi/abi.html#non-trivial)"
should be passed by pointer, even if they are otherwise eligable to be passed in a register.
Similarly in both the Itanium and MSVC ABIs such types are returned by "hidden parameter", much like
large structs in C that would not fit into a register. This also applies to types with any base classes
in the MSVC ABI (see [x64 calling convention](https://learn.microsoft.com/en-us/cpp/build/x64-calling-convention?view=msvc-170#return-values)).
Because bindgen does not know about these rules generated interfaces using such types are currently invalid.
## Constructor semantics
`bindgen` will generate a wrapper for any class constructor declared in the
input headers. For example, this headers file
```c++
class MyClass {
public:
MyClass();
void method();
};
```
Will produce the following code:
```rust,ignore
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct MyClass {
pub _address: u8,
}
extern "C" {
#[link_name = "\u{1}_ZN7MyClass6methodEv"]
pub fn MyClass_method(this: *mut MyClass);
}
extern "C" {
#[link_name = "\u{1}_ZN7MyClassC1Ev"]
pub fn MyClass_MyClass(this: *mut MyClass);
}
impl MyClass {
#[inline]
pub unsafe fn method(&mut self) {
MyClass_method(self)
}
#[inline]
pub unsafe fn new() -> Self {
let mut __bindgen_tmp = ::std::mem::MaybeUninit::uninit();
MyClass_MyClass(__bindgen_tmp.as_mut_ptr());
__bindgen_tmp.assume_init()
}
}
```
This `MyClass::new` Rust method can be used as a substitute for the `MyClass`
C++ constructor. However, the address of the value from inside the method will
be different than from the outside. This is because the `__bindgen_tmp` value
is moved when the `MyClass::new` method returns.
In contrast, the C++ constructor will not move the value, meaning that the
address of the value will be the same inside and outside the constructor.
If the original C++ relies on this semantic difference somehow, you should use the
`MyClass_MyClass` binding directly instead of the `MyClass::new` method.
In other words, the Rust equivalent for the following C++ code
```c++
MyClass instance = MyClass();
instance.method();
```
is not this
```rust,ignore
let instance = MyClass::new();
instance.method();
```
but this
```rust,ignore
let instance = std::mem::MaybeUninit::<MyClass>::uninit();
MyClass_MyClass(instance.as_mut_ptr());
instance.assume_init_mut().method();
```
You can easily verify this fact if you provide a implementation for `MyClass`
and `method` that prints the the `this` pointer address. However, you can
ignore this fact if you know that the original C++ code does not rely on the
instance address in its internal logic.
|