1{{#title extern "C++" — Rust ♡ C++}} 2# extern "C++" 3 4```rust,noplayground 5#[cxx::bridge] 6mod ffi { 7 extern "C++" { 8 include!("path/to/header.h"); 9 include!("path/to/another.h"); 10 11 ... 12 } 13} 14``` 15 16The `extern "C++"` section of a CXX bridge declares C++ types and signatures to 17be made available to Rust, and gives the paths of the header(s) which contain 18the corresponding C++ declarations. 19 20A bridge module may contain zero or more extern "C++" blocks. 21 22## Opaque C++ types 23 24Type defined in C++ that are made available to Rust, but only behind an 25indirection. 26 27```rust,noplayground 28# #[cxx::bridge] 29# mod ffi { 30 extern "C++" { 31 # include!("path/to/header.h"); 32 # 33 type MyType; 34 type MyOtherType; 35 } 36# } 37``` 38 39For example in the ***[Tutorial](tutorial.md)*** we saw `BlobstoreClient` 40implemented as an opaque C++ type. The blobstore client was created in C++ and 41returned to Rust by way of a UniquePtr. 42 43**Mutability:** Unlike extern Rust types and shared types, an extern C++ type is 44not permitted to be passed by plain mutable reference `&mut MyType` across the 45FFI bridge. For mutation support, the bridge is required to use `Pin<&mut 46MyType>`. This is to safeguard against things like mem::swap-ing the contents of 47two mutable references, given that Rust doesn't have information about the size 48of the underlying object and couldn't invoke an appropriate C++ move constructor 49anyway. 50 51**Thread safety:** Be aware that CXX does not assume anything about the thread 52safety of your extern C++ types. In other words the `MyType` etc bindings which 53CXX produces for you in Rust *do not* come with `Send` and `Sync` impls. If you 54are sure that your C++ type satisfies the requirements of `Send` and/or `Sync` 55and need to leverage that fact from Rust, you must provide your own unsafe 56marker trait impls. 57 58```rust,noplayground 59# #[cxx::bridge] 60# mod ffi { 61# extern "C++" { 62# include!("path/to/header.h"); 63# 64# type MyType; 65# } 66# } 67# 68/// The C++ implementation of MyType is thread safe. 69unsafe impl Send for ffi::MyType {} 70unsafe impl Sync for ffi::MyType {} 71``` 72 73Take care in doing this because thread safety in C++ can be extremely tricky to 74assess if you are coming from a Rust background. For example the 75`BlobstoreClient` type in the tutorial is *not thread safe* despite doing only 76completely innocuous things in its implementation. Concurrent calls to the `tag` 77member function trigger a data race on the `blobs` map. 78 79## Functions and member functions 80 81This largely follows the same principles as ***[extern 82"Rust"](extern-rust.md)*** functions and methods. In particular, any signature 83with a `self` parameter is interpreted as a C++ non-static member function and 84exposed to Rust as a method. 85 86The programmer **does not** need to promise that the signatures they have typed 87in are accurate; that would be unreasonable. CXX performs static assertions that 88the signatures exactly correspond with what is declared in C++. Rather, the 89programmer is only on the hook for things that C++'s static information is not 90precise enough to capture, i.e. things that would only be represented at most by 91comments in the C++ code unintelligible to a static assertion: namely whether 92the C++ function is safe or unsafe to be called from Rust. 93 94**Safety:** the extern "C++" block is responsible for deciding whether to expose 95each signature inside as safe-to-call or unsafe-to-call. If an extern block 96contains at least one safe-to-call signature, it must be written as an `unsafe 97extern` block, which serves as an item level unsafe block to indicate that an 98unchecked safety claim is being made about the contents of the block. 99 100```rust,noplayground 101#[cxx::bridge] 102mod ffi { 103 unsafe extern "C++" { 104 # include!("path/to/header.h"); 105 # 106 fn f(); // safe to call 107 } 108 109 extern "C++" { 110 unsafe fn g(); // unsafe to call 111 } 112} 113``` 114 115## Lifetimes 116 117C++ types holding borrowed data may be described naturally in Rust by an extern 118type with a generic lifetime parameter. For example in the case of the following 119pair of types: 120 121```cpp 122// header.h 123 124class Resource; 125 126class TypeContainingBorrow { 127 TypeContainingBorrow(const Resource &res) : res(res) {} 128 const Resource &res; 129}; 130 131std::shared_ptr<TypeContainingBorrow> create(const Resource &res); 132``` 133 134we'd want to expose this to Rust as: 135 136```rust,noplayground 137#[cxx::bridge] 138mod ffi { 139 unsafe extern "C++" { 140 # include!("path/to/header.h"); 141 # 142 type Resource; 143 type TypeContainingBorrow<'a>; 144 145 fn create<'a>(res: &'a Resource) -> SharedPtr<TypeContainingBorrow<'a>>; 146 147 // or with lifetime elision: 148 fn create(res: &Resource) -> SharedPtr<TypeContainingBorrow>; 149 } 150} 151``` 152 153## Reusing existing binding types 154 155Extern C++ types support a syntax for declaring that a Rust binding of the 156correct C++ type already exists outside of the current bridge module. This 157avoids generating a fresh new binding which Rust's type system would consider 158non-interchangeable with the first. 159 160```rust,noplayground 161#[cxx::bridge(namespace = "path::to")] 162mod ffi { 163 extern "C++" { 164 type MyType = crate::existing::MyType; 165 } 166 167 extern "Rust" { 168 fn f(x: &MyType) -> usize; 169 } 170} 171``` 172 173In this case rather than producing a unique new Rust type `ffi::MyType` for the 174Rust binding of C++'s `::path::to::MyType`, CXX will reuse the already existing 175binding at `crate::existing::MyType` in expressing the signature of `f` and any 176other uses of `MyType` within the bridge module. 177 178CXX safely validates that `crate::existing::MyType` is in fact a binding for the 179right C++ type `::path::to::MyType` by generating a static assertion based on 180`crate::existing::MyType`'s implementation of [`ExternType`], which is a trait 181automatically implemented by CXX for bindings that it generates but can also be 182manually implemented as described below. 183 184[`ExternType`]: https://docs.rs/cxx/*/cxx/trait.ExternType.html 185 186`ExternType` serves the following two related use cases. 187 188#### Safely unifying occurrences of an extern type across bridges 189 190In the following snippet, two #\[cxx::bridge\] invocations in different files 191(possibly different crates) both contain function signatures involving the same 192C++ type `example::Demo`. If both were written just containing `type Demo;`, 193then both macro expansions would produce their own separate Rust type called 194`Demo` and thus the compiler wouldn't allow us to take the `Demo` returned by 195`file1::ffi::create_demo` and pass it as the `Demo` argument accepted by 196`file2::ffi::take_ref_demo`. Instead, one of the two `Demo`s has been defined as 197an extern type alias of the other, making them the same type in Rust. 198 199```rust,noplayground 200// file1.rs 201#[cxx::bridge(namespace = "example")] 202pub mod ffi { 203 unsafe extern "C++" { 204 type Demo; 205 206 fn create_demo() -> UniquePtr<Demo>; 207 } 208} 209``` 210 211```rust,noplayground 212// file2.rs 213#[cxx::bridge(namespace = "example")] 214pub mod ffi { 215 unsafe extern "C++" { 216 type Demo = crate::file1::ffi::Demo; 217 218 fn take_ref_demo(demo: &Demo); 219 } 220} 221``` 222 223#### Integrating with bindgen-generated or handwritten unsafe bindings 224 225Handwritten `ExternType` impls make it possible to plug in a data structure 226emitted by bindgen as the definition of a C++ type emitted by CXX. 227 228By writing the unsafe `ExternType` impl, the programmer asserts that the C++ 229namespace and type name given in the type id refers to a C++ type that is 230equivalent to Rust type that is the `Self` type of the impl. 231 232```rust,noplayground 233mod folly_sys; // the bindgen-generated bindings 234 235use cxx::{type_id, ExternType}; 236 237unsafe impl ExternType for folly_sys::StringPiece { 238 type Id = type_id!("folly::StringPiece"); 239 type Kind = cxx::kind::Opaque; 240} 241 242#[cxx::bridge(namespace = "folly")] 243pub mod ffi { 244 unsafe extern "C++" { 245 include!("rust_cxx_bindings.h"); 246 247 type StringPiece = crate::folly_sys::StringPiece; 248 249 fn print_string_piece(s: &StringPiece); 250 } 251} 252 253// Now if we construct a StringPiece or obtain one through one 254// of the bindgen-generated signatures, we are able to pass it 255// along to ffi::print_string_piece. 256``` 257 258The `ExternType::Id` associated type encodes a type-level representation of the 259type's C++ namespace and type name. It will always be defined using the 260`type_id!` macro exposed in the cxx crate. 261 262The `ExternType::Kind` associated type will always be either 263[`cxx::kind::Opaque`] or [`cxx::kind::Trivial`] identifying whether a C++ type 264is soundly relocatable by Rust's move semantics. A C++ type is only okay to hold 265and pass around by value in Rust if its [move constructor is trivial] and it has 266no destructor. In CXX, these are called Trivial extern C++ types, while types 267with nontrivial move behavior or a destructor must be considered Opaque and 268handled by Rust only behind an indirection, such as a reference or UniquePtr. 269 270[`cxx::kind::Opaque`]: https://docs.rs/cxx/*/cxx/kind/enum.Opaque.html 271[`cxx::kind::Trivial`]: https://docs.rs/cxx/*/cxx/kind/enum.Trivial.html 272[move constructor is trivial]: https://en.cppreference.com/w/cpp/types/is_move_constructible 273 274If you believe your C++ type reflected by the ExternType impl is indeed fine to 275hold by value and move in Rust, you can specify: 276 277```rust,noplayground 278# unsafe impl cxx::ExternType for TypeName { 279# type Id = cxx::type_id!("name::space::of::TypeName"); 280 type Kind = cxx::kind::Trivial; 281# } 282``` 283 284which will enable you to pass it into C++ functions by value, return it by 285value, and include it in `struct`s that you have declared to `cxx::bridge`. Your 286claim about the triviality of the C++ type will be checked by a `static_assert` 287in the generated C++ side of the binding. 288 289## Explicit shim trait impls 290 291This is a somewhat niche feature, but important when you need it. 292 293CXX's support for C++'s std::unique\_ptr and std::vector is built on a set of 294internal trait impls connecting the Rust API of UniquePtr and CxxVector to 295underlying template instantiations performed by the C++ compiler. 296 297When reusing a binding type across multiple bridge modules as described in the 298previous section, you may find that your code needs some trait impls which CXX 299hasn't decided to generate. 300 301```rust,noplayground 302#[cxx::bridge] 303mod ffi1 { 304 extern "C++" { 305 include!("path/to/header.h"); 306 307 type A; 308 type B; 309 310 // Okay: CXX sees UniquePtr<B> using a type B defined within the same 311 // bridge, and automatically emits the right template instantiations 312 // corresponding to std::unique_ptr<B>. 313 fn get_b() -> UniquePtr<B>; 314 } 315} 316 317#[cxx::bridge] 318mod ffi2 { 319 extern "C++" { 320 type A = crate::ffi1::A; 321 322 // Rust trait error: CXX processing this module has no visibility into 323 // whether template instantiations corresponding to std::unique_ptr<A> 324 // have already been emitted by the upstream library, so it does not 325 // emit them here. If the upstream library does not have any signatures 326 // involving UniquePtr<A>, an explicit instantiation of the template 327 // needs to be requested in one module or the other. 328 fn get_a() -> UniquePtr<A>; 329 } 330} 331``` 332 333You can request a specific template instantiation at a particular location in 334the Rust crate hierarchy by writing `impl UniquePtr<A> {}` inside of the bridge 335module which defines `A` but does not otherwise contain any use of 336`UniquePtr<A>`. 337 338```rust,noplayground 339#[cxx::bridge] 340mod ffi1 { 341 extern "C++" { 342 include!("path/to/header.h"); 343 344 type A; 345 type B; 346 347 fn get_b() -> UniquePtr<B>; 348 } 349 350 impl UniquePtr<A> {} // explicit instantiation 351} 352``` 353