133d722a9Sopenharmony_ci{{#title Other Rust–C++ interop tools — Rust ♡ C++}} 233d722a9Sopenharmony_ci# Context: other Rust–C++ interop tools 333d722a9Sopenharmony_ci 433d722a9Sopenharmony_ciWhen it comes to interacting with an idiomatic Rust API or idiomatic C++ API 533d722a9Sopenharmony_cifrom the other language, the generally applicable approaches outside of the CXX 633d722a9Sopenharmony_cicrate are: 733d722a9Sopenharmony_ci 833d722a9Sopenharmony_ci- Build a C-compatible wrapper around the code (expressed using `extern "C"` 933d722a9Sopenharmony_ci signatures, primitives, C-compatible structs, raw pointers). Translate that 1033d722a9Sopenharmony_ci manually to equivalent `extern "C"` declarations in the other language and 1133d722a9Sopenharmony_ci keep them in sync. Preferably, build a safe/idiomatic wrapper around the 1233d722a9Sopenharmony_ci translated `extern "C"` signatures for callers to use. 1333d722a9Sopenharmony_ci 1433d722a9Sopenharmony_ci- Build a C wrapper around the C++ code and use **[bindgen]** to translate that 1533d722a9Sopenharmony_ci programmatically to `extern "C"` Rust signatures. Preferably, build a 1633d722a9Sopenharmony_ci safe/idiomatic Rust wrapper on top. 1733d722a9Sopenharmony_ci 1833d722a9Sopenharmony_ci- Build a C-compatible Rust wrapper around the Rust code and use **[cbindgen]** 1933d722a9Sopenharmony_ci to translate that programmatically to an `extern "C"` C++ header. Preferably, 2033d722a9Sopenharmony_ci build an idiomatic C++ wrapper. 2133d722a9Sopenharmony_ci 2233d722a9Sopenharmony_ci**If the code you are binding is already *"effectively C"*, the above has you 2333d722a9Sopenharmony_cicovered.** You should use bindgen or cbindgen, or manually translated C 2433d722a9Sopenharmony_cisignatures if there aren't too many and they seldom change. 2533d722a9Sopenharmony_ci 2633d722a9Sopenharmony_ci[bindgen]: https://github.com/rust-lang/rust-bindgen 2733d722a9Sopenharmony_ci[cbindgen]: https://github.com/eqrion/cbindgen 2833d722a9Sopenharmony_ci 2933d722a9Sopenharmony_ci## C++ vs C 3033d722a9Sopenharmony_ci 3133d722a9Sopenharmony_ciBindgen has some basic support for C++. It can reason about classes, member 3233d722a9Sopenharmony_cifunctions, and the layout of templated types. However, everything it does 3333d722a9Sopenharmony_cirelated to C++ is best-effort only. Bindgen starts from a point of wanting to 3433d722a9Sopenharmony_cigenerate declarations for everything, so any C++ detail that it hasn't 3533d722a9Sopenharmony_ciimplemented will cause a crash if you are lucky ([bindgen#388]) or more likely 3633d722a9Sopenharmony_cisilently emit an incompatible signature ([bindgen#380], [bindgen#607], 3733d722a9Sopenharmony_ci[bindgen#652], [bindgen#778], [bindgen#1194]) which will do arbitrary 3833d722a9Sopenharmony_cimemory-unsafe things at runtime whenever called. 3933d722a9Sopenharmony_ci 4033d722a9Sopenharmony_ci[bindgen#388]: https://github.com/rust-lang/rust-bindgen/issues/388 4133d722a9Sopenharmony_ci[bindgen#380]: https://github.com/rust-lang/rust-bindgen/issues/380 4233d722a9Sopenharmony_ci[bindgen#607]: https://github.com/rust-lang/rust-bindgen/issues/607 4333d722a9Sopenharmony_ci[bindgen#652]: https://github.com/rust-lang/rust-bindgen/issues/652 4433d722a9Sopenharmony_ci[bindgen#778]: https://github.com/rust-lang/rust-bindgen/issues/778 4533d722a9Sopenharmony_ci[bindgen#1194]: https://github.com/rust-lang/rust-bindgen/issues/1194 4633d722a9Sopenharmony_ci 4733d722a9Sopenharmony_ciThus using bindgen correctly requires not just juggling all your pointers 4833d722a9Sopenharmony_cicorrectly at the language boundary, but also understanding ABI details and their 4933d722a9Sopenharmony_ciworkarounds and reliably applying them. For example, the programmer will 5033d722a9Sopenharmony_cidiscover that their program sometimes segfaults if they call a function that 5133d722a9Sopenharmony_cireturns std::unique\_ptr\<T\> through bindgen. Why? Because unique\_ptr, despite 5233d722a9Sopenharmony_cibeing "just a pointer", has a different ABI than a pointer or a C struct 5333d722a9Sopenharmony_cicontaining a pointer ([bindgen#778]) and is not directly expressible in Rust. 5433d722a9Sopenharmony_ciBindgen emitted something that *looks* reasonable and you will have a hell of a 5533d722a9Sopenharmony_citime in gdb working out what went wrong. Eventually people learn to avoid 5633d722a9Sopenharmony_cianything involving a non-trivial copy constructor, destructor, or inheritance, 5733d722a9Sopenharmony_ciand instead stick to raw pointers and primitives and trivial structs only 5833d722a9Sopenharmony_ci— in other words C. 5933d722a9Sopenharmony_ci 6033d722a9Sopenharmony_ci## Geometric intuition for why there is so much opportunity for improvement 6133d722a9Sopenharmony_ci 6233d722a9Sopenharmony_ciThe CXX project attempts a different approach to C++ FFI. 6333d722a9Sopenharmony_ci 6433d722a9Sopenharmony_ciImagine Rust and C and C++ as three vertices of a scalene triangle, with length 6533d722a9Sopenharmony_ciof the edges being related to similarity of the languages when it comes to 6633d722a9Sopenharmony_cilibrary design. 6733d722a9Sopenharmony_ci 6833d722a9Sopenharmony_ciThe most similar pair (the shortest edge) is Rust–C++. These languages 6933d722a9Sopenharmony_cihave largely compatible concepts of things like ownership, vectors, strings, 7033d722a9Sopenharmony_cifallibility, etc that translate clearly from signatures in either language to 7133d722a9Sopenharmony_cisignatures in the other language. 7233d722a9Sopenharmony_ci 7333d722a9Sopenharmony_ciWhen we make a binding for an idiomatic C++ API using bindgen, and we fall down 7433d722a9Sopenharmony_cito raw pointers and primitives and trivial structs as described above, what we 7533d722a9Sopenharmony_ciare really doing is coding the two longest edges of the triangle: getting from 7633d722a9Sopenharmony_ciC++ down to C, and C back up to Rust. The Rust–C edge always involves a 7733d722a9Sopenharmony_cigreat deal of `unsafe` code, and the C++–C edge similarly requires care 7833d722a9Sopenharmony_cijust for basic memory safety. Something as basic as "how do I pass ownership of 7933d722a9Sopenharmony_cia string to the other language?" becomes a strap-yourself-in moment, 8033d722a9Sopenharmony_ciparticularly for someone not already an expert in one or both sides. 8133d722a9Sopenharmony_ci 8233d722a9Sopenharmony_ciYou should think of the `cxx` crate as being the midpoint of the Rust–C++ 8333d722a9Sopenharmony_ciedge. Rather than coding the two long edges, you will code half the short edge 8433d722a9Sopenharmony_ciin Rust and half the short edge in C++, in both cases with the library playing 8533d722a9Sopenharmony_cito the strengths of the Rust type system *and* the C++ type system to help 8633d722a9Sopenharmony_ciassure correctness. 8733d722a9Sopenharmony_ci 8833d722a9Sopenharmony_ciIf you've already been through the tutorial in the previous chapter, take a 8933d722a9Sopenharmony_cimoment to appreciate that the C++ side *really* looks like we are just writing 9033d722a9Sopenharmony_ciC++ and the Rust side *really* looks like we are just writing Rust. Anything you 9133d722a9Sopenharmony_cicould do wrong in Rust, and almost anything you could reasonably do wrong in 9233d722a9Sopenharmony_ciC++, will be caught by the compiler. This highlights that we are on the "short 9333d722a9Sopenharmony_ciedge of the triangle". 9433d722a9Sopenharmony_ci 9533d722a9Sopenharmony_ciBut it all still boils down to the same things: it's still FFI from one piece of 9633d722a9Sopenharmony_cinative code to another, nothing is getting serialized or allocated or 9733d722a9Sopenharmony_ciruntime-checked in between. 9833d722a9Sopenharmony_ci 9933d722a9Sopenharmony_ci## Role of CXX 10033d722a9Sopenharmony_ci 10133d722a9Sopenharmony_ciThe role of CXX is to capture the language boundary with more fidelity than what 10233d722a9Sopenharmony_ci`extern "C"` is able to represent. You can think of CXX as being a replacement 10333d722a9Sopenharmony_cifor `extern "C"` in a sense. 10433d722a9Sopenharmony_ci 10533d722a9Sopenharmony_ciFrom this perspective, CXX is a lower level tool than the bindgens. Just as 10633d722a9Sopenharmony_cibindgen and cbindgen are built on top of `extern "C"`, it makes sense to think 10733d722a9Sopenharmony_ciabout higher level tools built on top of CXX. Such a tool might consume a C++ 10833d722a9Sopenharmony_ciheader and/or Rust module (and/or IDL like Thrift) and emit the corresponding 10933d722a9Sopenharmony_cisafe cxx::bridge language boundary, leveraging CXX's static analysis and 11033d722a9Sopenharmony_ciunderlying implementation of that boundary. We are beginning to see this space 11133d722a9Sopenharmony_ciexplored by the [autocxx] tool, though nothing yet ready for broad use in the 11233d722a9Sopenharmony_ciway that CXX on its own is. 11333d722a9Sopenharmony_ci 11433d722a9Sopenharmony_ci[autocxx]: https://github.com/google/autocxx 11533d722a9Sopenharmony_ci 11633d722a9Sopenharmony_ciBut note in other ways CXX is higher level than the bindgens, with rich support 11733d722a9Sopenharmony_cifor common standard library types. CXX's types serve as an intuitive vocabulary 11833d722a9Sopenharmony_cifor designing a good boundary between components in different languages. 119