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