CXX enables calling C++ code from Rust and vice versa through safe low-level bindings so you do not have to create your foreign function interface on top of unsafe C-style signatures. InfoQ has taken the chance to speak with CXX creator David Tolnay.
CXX uses static analysis of the types and function signatures to protect both Rust's and C++'s invariants. Then it uses a pair of code generators to implement the boundary efficiently on both sides together with any necessary static assertions for later in the build process to verify correctness.
According to Tolnay, the bridge created using CXX has zero or negligible overhead, not requiring copying, serialization, memory allocation, or runtime checks.
CXX aims to make it possible to write perfectly idiomatic code on both sides of the bridge, meaning you can write idiomatic Rust code using idiomatic C++ code, and vice versa. To this aim, CXX provides built-in bindings for standard library types such as strings, vectors, and so on.
This is how a Rust program using CXX to call C++ code may look like:
#[cxx::bridge]
mod ffi {
unsafe extern "C++" {
include!("cxx-demo/include/blobstore.h");
type BlobstoreClient;
fn new_blobstore_client() -> UniquePtr<BlobstoreClient>;
}
}
fn main() {
let client = ffi::new_blobstore_client();
}
InfoQ has taken the chance to speak with CXX creator David Tolnay.
InfoQ: What is your background and how would you describe your involvement with the Rust project?
David Tolnay: Software engineer in the San Francisco area with a focus on codebase design: the libraries, patterns, and practices that enable developers to operate successfully in large (10 million+ line) codebases. I have been working with Rust since 2016, and have created and maintain many widely used Rust libraries as side projects. These days around 30% of all open source packages on the Rust package registry depend directly on at least one library by me.
InfoQ: What is the rationale for CXX? What was your motivation to create it?
Tolnay: Prior to CXX, Rust interop with C was fine (unsafe, though in a way that C developers would be comfortable with) while interop with C++ was "make it look as much like C as you can manage."
That state of the world was something teams with Rust expertise were generally able to navigate, calling C++ code where needed to get their job done. However, it was by no means pleasant to write or maintain.
Meanwhile teams just getting started with Rust really struggled. For someone introducing Rust into a C++ codebase, or especially someone coming into Rust with neither Rust nor C++ experience, being dumped into unsafe code so early on is a showstopper and a reason to decide against Rust.
CXX leverages the idea that Rust and modern C++ are way more similar than either is to C. We can interoperate at a suitable level of abstraction without unsafe C in between, and do so without sacrificing efficiency on the language boundary.
InfoQ: What is/was the biggest challenge in CXX design/implementation?
Tolnay: Delivering a good experience for Cargo users. Cargo is the build system commonly used by open source Rust projects. Whereas some build systems like Bazel are highly designed around multi-language builds, Cargo is not that.
It's taken a few thorough redesigns but CXX on Cargo now comes close to matching the experience of CXX in a natively polyglot build system. That pleasantly encompasses Rust depending on C++, C++ depending on Rust, and C++ depending on C++ from other crates.
InfoQ: How would you describe CXX current status? In which scenarios would you suggest its use at the moment?
Tolnay: I have rolled out CXX in a large hybrid-Rust–C++ codebase in which many engineers have used it successfully with positive reception. There is more to improve but it delivers a developer experience that I stand behind as my recommendation for all Rust–C++ interop.
InfoQ: What’s on CXX roadmap?
Tolnay: The biggest idea not yet explored is first-class async function support. We support async already but it's not quite as seamless as being able to directly
.await
an arbitrary async C++ function andco_await
an arbitrary async Rust function.
If you want to try CXX out, you can start with its tutorial and GitHub repository.