| # 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 `clang_args(["-x", "c++"])` 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 eligible 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 `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. |