1{{#title Other Rust–C++ interop tools — Rust ♡ C++}} 2# Context: other Rust–C++ interop tools 3 4When it comes to interacting with an idiomatic Rust API or idiomatic C++ API 5from the other language, the generally applicable approaches outside of the CXX 6crate are: 7 8- Build a C-compatible wrapper around the code (expressed using `extern "C"` 9 signatures, primitives, C-compatible structs, raw pointers). Translate that 10 manually to equivalent `extern "C"` declarations in the other language and 11 keep them in sync. Preferably, build a safe/idiomatic wrapper around the 12 translated `extern "C"` signatures for callers to use. 13 14- Build a C wrapper around the C++ code and use **[bindgen]** to translate that 15 programmatically to `extern "C"` Rust signatures. Preferably, build a 16 safe/idiomatic Rust wrapper on top. 17 18- Build a C-compatible Rust wrapper around the Rust code and use **[cbindgen]** 19 to translate that programmatically to an `extern "C"` C++ header. Preferably, 20 build an idiomatic C++ wrapper. 21 22**If the code you are binding is already *"effectively C"*, the above has you 23covered.** You should use bindgen or cbindgen, or manually translated C 24signatures if there aren't too many and they seldom change. 25 26[bindgen]: https://github.com/rust-lang/rust-bindgen 27[cbindgen]: https://github.com/eqrion/cbindgen 28 29## C++ vs C 30 31Bindgen has some basic support for C++. It can reason about classes, member 32functions, and the layout of templated types. However, everything it does 33related to C++ is best-effort only. Bindgen starts from a point of wanting to 34generate declarations for everything, so any C++ detail that it hasn't 35implemented will cause a crash if you are lucky ([bindgen#388]) or more likely 36silently emit an incompatible signature ([bindgen#380], [bindgen#607], 37[bindgen#652], [bindgen#778], [bindgen#1194]) which will do arbitrary 38memory-unsafe things at runtime whenever called. 39 40[bindgen#388]: https://github.com/rust-lang/rust-bindgen/issues/388 41[bindgen#380]: https://github.com/rust-lang/rust-bindgen/issues/380 42[bindgen#607]: https://github.com/rust-lang/rust-bindgen/issues/607 43[bindgen#652]: https://github.com/rust-lang/rust-bindgen/issues/652 44[bindgen#778]: https://github.com/rust-lang/rust-bindgen/issues/778 45[bindgen#1194]: https://github.com/rust-lang/rust-bindgen/issues/1194 46 47Thus using bindgen correctly requires not just juggling all your pointers 48correctly at the language boundary, but also understanding ABI details and their 49workarounds and reliably applying them. For example, the programmer will 50discover that their program sometimes segfaults if they call a function that 51returns std::unique\_ptr\<T\> through bindgen. Why? Because unique\_ptr, despite 52being "just a pointer", has a different ABI than a pointer or a C struct 53containing a pointer ([bindgen#778]) and is not directly expressible in Rust. 54Bindgen emitted something that *looks* reasonable and you will have a hell of a 55time in gdb working out what went wrong. Eventually people learn to avoid 56anything involving a non-trivial copy constructor, destructor, or inheritance, 57and instead stick to raw pointers and primitives and trivial structs only 58— in other words C. 59 60## Geometric intuition for why there is so much opportunity for improvement 61 62The CXX project attempts a different approach to C++ FFI. 63 64Imagine Rust and C and C++ as three vertices of a scalene triangle, with length 65of the edges being related to similarity of the languages when it comes to 66library design. 67 68The most similar pair (the shortest edge) is Rust–C++. These languages 69have largely compatible concepts of things like ownership, vectors, strings, 70fallibility, etc that translate clearly from signatures in either language to 71signatures in the other language. 72 73When we make a binding for an idiomatic C++ API using bindgen, and we fall down 74to raw pointers and primitives and trivial structs as described above, what we 75are really doing is coding the two longest edges of the triangle: getting from 76C++ down to C, and C back up to Rust. The Rust–C edge always involves a 77great deal of `unsafe` code, and the C++–C edge similarly requires care 78just for basic memory safety. Something as basic as "how do I pass ownership of 79a string to the other language?" becomes a strap-yourself-in moment, 80particularly for someone not already an expert in one or both sides. 81 82You should think of the `cxx` crate as being the midpoint of the Rust–C++ 83edge. Rather than coding the two long edges, you will code half the short edge 84in Rust and half the short edge in C++, in both cases with the library playing 85to the strengths of the Rust type system *and* the C++ type system to help 86assure correctness. 87 88If you've already been through the tutorial in the previous chapter, take a 89moment to appreciate that the C++ side *really* looks like we are just writing 90C++ and the Rust side *really* looks like we are just writing Rust. Anything you 91could do wrong in Rust, and almost anything you could reasonably do wrong in 92C++, will be caught by the compiler. This highlights that we are on the "short 93edge of the triangle". 94 95But it all still boils down to the same things: it's still FFI from one piece of 96native code to another, nothing is getting serialized or allocated or 97runtime-checked in between. 98 99## Role of CXX 100 101The role of CXX is to capture the language boundary with more fidelity than what 102`extern "C"` is able to represent. You can think of CXX as being a replacement 103for `extern "C"` in a sense. 104 105From this perspective, CXX is a lower level tool than the bindgens. Just as 106bindgen and cbindgen are built on top of `extern "C"`, it makes sense to think 107about higher level tools built on top of CXX. Such a tool might consume a C++ 108header and/or Rust module (and/or IDL like Thrift) and emit the corresponding 109safe cxx::bridge language boundary, leveraging CXX's static analysis and 110underlying implementation of that boundary. We are beginning to see this space 111explored by the [autocxx] tool, though nothing yet ready for broad use in the 112way that CXX on its own is. 113 114[autocxx]: https://github.com/google/autocxx 115 116But note in other ways CXX is higher level than the bindgens, with rich support 117for common standard library types. CXX's types serve as an intuitive vocabulary 118for designing a good boundary between components in different languages. 119