• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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