1 //! [![github]](https://github.com/dtolnay/cxx) [![crates-io]](https://crates.io/crates/cxx) [![docs-rs]](https://docs.rs/cxx) 2 //! 3 //! [github]: https://img.shields.io/badge/github-8da0cb?style=for-the-badge&labelColor=555555&logo=github 4 //! [crates-io]: https://img.shields.io/badge/crates.io-fc8d62?style=for-the-badge&labelColor=555555&logo=rust 5 //! [docs-rs]: https://img.shields.io/badge/docs.rs-66c2a5?style=for-the-badge&labelColor=555555&logo=docs.rs 6 //! 7 //! <br> 8 //! 9 //! This library provides a **safe** mechanism for calling C++ code from Rust 10 //! and Rust code from C++, not subject to the many ways that things can go 11 //! wrong when using bindgen or cbindgen to generate unsafe C-style bindings. 12 //! 13 //! This doesn't change the fact that 100% of C++ code is unsafe. When auditing 14 //! a project, you would be on the hook for auditing all the unsafe Rust code 15 //! and *all* the C++ code. The core safety claim under this new model is that 16 //! auditing just the C++ side would be sufficient to catch all problems, i.e. 17 //! the Rust side can be 100% safe. 18 //! 19 //! <br> 20 //! 21 //! *Compiler support: requires rustc 1.60+ and c++11 or newer*<br> 22 //! *[Release notes](https://github.com/dtolnay/cxx/releases)* 23 //! 24 //! <br> 25 //! 26 //! # Guide 27 //! 28 //! Please see **<https://cxx.rs>** for a tutorial, reference material, and 29 //! example code. 30 //! 31 //! <br> 32 //! 33 //! # Overview 34 //! 35 //! The idea is that we define the signatures of both sides of our FFI boundary 36 //! embedded together in one Rust module (the next section shows an example). 37 //! From this, CXX receives a complete picture of the boundary to perform static 38 //! analyses against the types and function signatures to uphold both Rust's and 39 //! C++'s invariants and requirements. 40 //! 41 //! If everything checks out statically, then CXX uses a pair of code generators 42 //! to emit the relevant `extern "C"` signatures on both sides together with any 43 //! necessary static assertions for later in the build process to verify 44 //! correctness. On the Rust side this code generator is simply an attribute 45 //! procedural macro. On the C++ side it can be a small Cargo build script if 46 //! your build is managed by Cargo, or for other build systems like Bazel or 47 //! Buck we provide a command line tool which generates the header and source 48 //! file and should be easy to integrate. 49 //! 50 //! The resulting FFI bridge operates at zero or negligible overhead, i.e. no 51 //! copying, no serialization, no memory allocation, no runtime checks needed. 52 //! 53 //! The FFI signatures are able to use native types from whichever side they 54 //! please, such as Rust's `String` or C++'s `std::string`, Rust's `Box` or 55 //! C++'s `std::unique_ptr`, Rust's `Vec` or C++'s `std::vector`, etc in any 56 //! combination. CXX guarantees an ABI-compatible signature that both sides 57 //! understand, based on builtin bindings for key standard library types to 58 //! expose an idiomatic API on those types to the other language. For example 59 //! when manipulating a C++ string from Rust, its `len()` method becomes a call 60 //! of the `size()` member function defined by C++; when manipulation a Rust 61 //! string from C++, its `size()` member function calls Rust's `len()`. 62 //! 63 //! <br> 64 //! 65 //! # Example 66 //! 67 //! In this example we are writing a Rust application that wishes to take 68 //! advantage of an existing C++ client for a large-file blobstore service. The 69 //! blobstore supports a `put` operation for a discontiguous buffer upload. For 70 //! example we might be uploading snapshots of a circular buffer which would 71 //! tend to consist of 2 chunks, or fragments of a file spread across memory for 72 //! some other reason. 73 //! 74 //! A runnable version of this example is provided under the *demo* directory of 75 //! <https://github.com/dtolnay/cxx>. To try it out, run `cargo run` from that 76 //! directory. 77 //! 78 //! ```no_run 79 //! #[cxx::bridge] 80 //! mod ffi { 81 //! // Any shared structs, whose fields will be visible to both languages. 82 //! struct BlobMetadata { 83 //! size: usize, 84 //! tags: Vec<String>, 85 //! } 86 //! 87 //! extern "Rust" { 88 //! // Zero or more opaque types which both languages can pass around but 89 //! // only Rust can see the fields. 90 //! type MultiBuf; 91 //! 92 //! // Functions implemented in Rust. 93 //! fn next_chunk(buf: &mut MultiBuf) -> &[u8]; 94 //! } 95 //! 96 //! unsafe extern "C++" { 97 //! // One or more headers with the matching C++ declarations. Our code 98 //! // generators don't read it but it gets #include'd and used in static 99 //! // assertions to ensure our picture of the FFI boundary is accurate. 100 //! include!("demo/include/blobstore.h"); 101 //! 102 //! // Zero or more opaque types which both languages can pass around but 103 //! // only C++ can see the fields. 104 //! type BlobstoreClient; 105 //! 106 //! // Functions implemented in C++. 107 //! fn new_blobstore_client() -> UniquePtr<BlobstoreClient>; 108 //! fn put(&self, parts: &mut MultiBuf) -> u64; 109 //! fn tag(&self, blobid: u64, tag: &str); 110 //! fn metadata(&self, blobid: u64) -> BlobMetadata; 111 //! } 112 //! } 113 //! # 114 //! # pub struct MultiBuf; 115 //! # 116 //! # fn next_chunk(_buf: &mut MultiBuf) -> &[u8] { 117 //! # unimplemented!() 118 //! # } 119 //! # 120 //! # fn main() {} 121 //! ``` 122 //! 123 //! Now we simply provide Rust definitions of all the things in the `extern 124 //! "Rust"` block and C++ definitions of all the things in the `extern "C++"` 125 //! block, and get to call back and forth safely. 126 //! 127 //! Here are links to the complete set of source files involved in the demo: 128 //! 129 //! - [demo/src/main.rs](https://github.com/dtolnay/cxx/blob/master/demo/src/main.rs) 130 //! - [demo/build.rs](https://github.com/dtolnay/cxx/blob/master/demo/build.rs) 131 //! - [demo/include/blobstore.h](https://github.com/dtolnay/cxx/blob/master/demo/include/blobstore.h) 132 //! - [demo/src/blobstore.cc](https://github.com/dtolnay/cxx/blob/master/demo/src/blobstore.cc) 133 //! 134 //! To look at the code generated in both languages for the example by the CXX 135 //! code generators: 136 //! 137 //! ```console 138 //! # run Rust code generator and print to stdout 139 //! # (requires https://github.com/dtolnay/cargo-expand) 140 //! $ cargo expand --manifest-path demo/Cargo.toml 141 //! 142 //! # run C++ code generator and print to stdout 143 //! $ cargo run --manifest-path gen/cmd/Cargo.toml -- demo/src/main.rs 144 //! ``` 145 //! 146 //! <br> 147 //! 148 //! # Details 149 //! 150 //! As seen in the example, the language of the FFI boundary involves 3 kinds of 151 //! items: 152 //! 153 //! - **Shared structs** — their fields are made visible to both 154 //! languages. The definition written within cxx::bridge is the single source 155 //! of truth. 156 //! 157 //! - **Opaque types** — their fields are secret from the other language. 158 //! These cannot be passed across the FFI by value but only behind an 159 //! indirection, such as a reference `&`, a Rust `Box`, or a `UniquePtr`. Can 160 //! be a type alias for an arbitrarily complicated generic language-specific 161 //! type depending on your use case. 162 //! 163 //! - **Functions** — implemented in either language, callable from the 164 //! other language. 165 //! 166 //! Within the `extern "Rust"` part of the CXX bridge we list the types and 167 //! functions for which Rust is the source of truth. These all implicitly refer 168 //! to the `super` module, the parent module of the CXX bridge. You can think of 169 //! the two items listed in the example above as being like `use 170 //! super::MultiBuf` and `use super::next_chunk` except re-exported to C++. The 171 //! parent module will either contain the definitions directly for simple 172 //! things, or contain the relevant `use` statements to bring them into scope 173 //! from elsewhere. 174 //! 175 //! Within the `extern "C++"` part, we list types and functions for which C++ is 176 //! the source of truth, as well as the header(s) that declare those APIs. In 177 //! the future it's possible that this section could be generated bindgen-style 178 //! from the headers but for now we need the signatures written out; static 179 //! assertions will verify that they are accurate. 180 //! 181 //! Your function implementations themselves, whether in C++ or Rust, *do not* 182 //! need to be defined as `extern "C"` ABI or no\_mangle. CXX will put in the 183 //! right shims where necessary to make it all work. 184 //! 185 //! <br> 186 //! 187 //! # Comparison vs bindgen and cbindgen 188 //! 189 //! Notice that with CXX there is repetition of all the function signatures: 190 //! they are typed out once where the implementation is defined (in C++ or Rust) 191 //! and again inside the cxx::bridge module, though compile-time assertions 192 //! guarantee these are kept in sync. This is different from [bindgen] and 193 //! [cbindgen] where function signatures are typed by a human once and the tool 194 //! consumes them in one language and emits them in the other language. 195 //! 196 //! [bindgen]: https://github.com/rust-lang/rust-bindgen 197 //! [cbindgen]: https://github.com/eqrion/cbindgen/ 198 //! 199 //! This is because CXX fills a somewhat different role. It is a lower level 200 //! tool than bindgen or cbindgen in a sense; you can think of it as being a 201 //! replacement for the concept of `extern "C"` signatures as we know them, 202 //! rather than a replacement for a bindgen. It would be reasonable to build a 203 //! higher level bindgen-like tool on top of CXX which consumes a C++ header 204 //! and/or Rust module (and/or IDL like Thrift) as source of truth and generates 205 //! the cxx::bridge, eliminating the repetition while leveraging the static 206 //! analysis safety guarantees of CXX. 207 //! 208 //! But note in other ways CXX is higher level than the bindgens, with rich 209 //! support for common standard library types. Frequently with bindgen when we 210 //! are dealing with an idiomatic C++ API we would end up manually wrapping that 211 //! API in C-style raw pointer functions, applying bindgen to get unsafe raw 212 //! pointer Rust functions, and replicating the API again to expose those 213 //! idiomatically in Rust. That's a much worse form of repetition because it is 214 //! unsafe all the way through. 215 //! 216 //! By using a CXX bridge as the shared understanding between the languages, 217 //! rather than `extern "C"` C-style signatures as the shared understanding, 218 //! common FFI use cases become expressible using 100% safe code. 219 //! 220 //! It would also be reasonable to mix and match, using CXX bridge for the 95% 221 //! of your FFI that is straightforward and doing the remaining few oddball 222 //! signatures the old fashioned way with bindgen and cbindgen, if for some 223 //! reason CXX's static restrictions get in the way. Please file an issue if you 224 //! end up taking this approach so that we know what ways it would be worthwhile 225 //! to make the tool more expressive. 226 //! 227 //! <br> 228 //! 229 //! # Cargo-based setup 230 //! 231 //! For builds that are orchestrated by Cargo, you will use a build script that 232 //! runs CXX's C++ code generator and compiles the resulting C++ code along with 233 //! any other C++ code for your crate. 234 //! 235 //! The canonical build script is as follows. The indicated line returns a 236 //! [`cc::Build`] instance (from the usual widely used `cc` crate) on which you 237 //! can set up any additional source files and compiler flags as normal. 238 //! 239 //! [`cc::Build`]: https://docs.rs/cc/1.0/cc/struct.Build.html 240 //! 241 //! ```toml 242 //! # Cargo.toml 243 //! 244 //! [build-dependencies] 245 //! cxx-build = "1.0" 246 //! ``` 247 //! 248 //! ```no_run 249 //! // build.rs 250 //! 251 //! fn main() { 252 //! cxx_build::bridge("src/main.rs") // returns a cc::Build 253 //! .file("src/demo.cc") 254 //! .flag_if_supported("-std=c++11") 255 //! .compile("cxxbridge-demo"); 256 //! 257 //! println!("cargo:rerun-if-changed=src/main.rs"); 258 //! println!("cargo:rerun-if-changed=src/demo.cc"); 259 //! println!("cargo:rerun-if-changed=include/demo.h"); 260 //! } 261 //! ``` 262 //! 263 //! <br><br> 264 //! 265 //! # Non-Cargo setup 266 //! 267 //! For use in non-Cargo builds like Bazel or Buck, CXX provides an alternate 268 //! way of invoking the C++ code generator as a standalone command line tool. 269 //! The tool is packaged as the `cxxbridge-cmd` crate on crates.io or can be 270 //! built from the *gen/cmd* directory of <https://github.com/dtolnay/cxx>. 271 //! 272 //! ```bash 273 //! $ cargo install cxxbridge-cmd 274 //! 275 //! $ cxxbridge src/main.rs --header > path/to/mybridge.h 276 //! $ cxxbridge src/main.rs > path/to/mybridge.cc 277 //! ``` 278 //! 279 //! <br> 280 //! 281 //! # Safety 282 //! 283 //! Be aware that the design of this library is intentionally restrictive and 284 //! opinionated! It isn't a goal to be powerful enough to handle arbitrary 285 //! signatures in either language. Instead this project is about carving out a 286 //! reasonably expressive set of functionality about which we can make useful 287 //! safety guarantees today and maybe extend over time. You may find that it 288 //! takes some practice to use CXX bridge effectively as it won't work in all 289 //! the ways that you are used to. 290 //! 291 //! Some of the considerations that go into ensuring safety are: 292 //! 293 //! - By design, our paired code generators work together to control both sides 294 //! of the FFI boundary. Ordinarily in Rust writing your own `extern "C"` 295 //! blocks is unsafe because the Rust compiler has no way to know whether the 296 //! signatures you've written actually match the signatures implemented in the 297 //! other language. With CXX we achieve that visibility and know what's on the 298 //! other side. 299 //! 300 //! - Our static analysis detects and prevents passing types by value that 301 //! shouldn't be passed by value from C++ to Rust, for example because they 302 //! may contain internal pointers that would be screwed up by Rust's move 303 //! behavior. 304 //! 305 //! - To many people's surprise, it is possible to have a struct in Rust and a 306 //! struct in C++ with exactly the same layout / fields / alignment / 307 //! everything, and still not the same ABI when passed by value. This is a 308 //! longstanding bindgen bug that leads to segfaults in absolutely 309 //! correct-looking code ([rust-lang/rust-bindgen#778]). CXX knows about this 310 //! and can insert the necessary zero-cost workaround transparently where 311 //! needed, so go ahead and pass your structs by value without worries. This 312 //! is made possible by owning both sides of the boundary rather than just 313 //! one. 314 //! 315 //! - Template instantiations: for example in order to expose a UniquePtr\<T\> 316 //! type in Rust backed by a real C++ unique\_ptr, we have a way of using a 317 //! Rust trait to connect the behavior back to the template instantiations 318 //! performed by the other language. 319 //! 320 //! [rust-lang/rust-bindgen#778]: https://github.com/rust-lang/rust-bindgen/issues/778 321 //! 322 //! <br> 323 //! 324 //! # Builtin types 325 //! 326 //! In addition to all the primitive types (i32 <=> int32_t), the 327 //! following common types may be used in the fields of shared structs and the 328 //! arguments and returns of functions. 329 //! 330 //! <table> 331 //! <tr><th>name in Rust</th><th>name in C++</th><th>restrictions</th></tr> 332 //! <tr><td>String</td><td>rust::String</td><td></td></tr> 333 //! <tr><td>&str</td><td>rust::Str</td><td></td></tr> 334 //! <tr><td>&[T]</td><td>rust::Slice<const T></td><td><sup><i>cannot hold opaque C++ type</i></sup></td></tr> 335 //! <tr><td>&mut [T]</td><td>rust::Slice<T></td><td><sup><i>cannot hold opaque C++ type</i></sup></td></tr> 336 //! <tr><td><a href="struct.CxxString.html">CxxString</a></td><td>std::string</td><td><sup><i>cannot be passed by value</i></sup></td></tr> 337 //! <tr><td>Box<T></td><td>rust::Box<T></td><td><sup><i>cannot hold opaque C++ type</i></sup></td></tr> 338 //! <tr><td><a href="struct.UniquePtr.html">UniquePtr<T></a></td><td>std::unique_ptr<T></td><td><sup><i>cannot hold opaque Rust type</i></sup></td></tr> 339 //! <tr><td><a href="struct.SharedPtr.html">SharedPtr<T></a></td><td>std::shared_ptr<T></td><td><sup><i>cannot hold opaque Rust type</i></sup></td></tr> 340 //! <tr><td>[T; N]</td><td>std::array<T, N></td><td><sup><i>cannot hold opaque C++ type</i></sup></td></tr> 341 //! <tr><td>Vec<T></td><td>rust::Vec<T></td><td><sup><i>cannot hold opaque C++ type</i></sup></td></tr> 342 //! <tr><td><a href="struct.CxxVector.html">CxxVector<T></a></td><td>std::vector<T></td><td><sup><i>cannot be passed by value, cannot hold opaque Rust type</i></sup></td></tr> 343 //! <tr><td>*mut T, *const T</td><td>T*, const T*</td><td><sup><i>fn with a raw pointer argument must be declared unsafe to call</i></sup></td></tr> 344 //! <tr><td>fn(T, U) -> V</td><td>rust::Fn<V(T, U)></td><td><sup><i>only passing from Rust to C++ is implemented so far</i></sup></td></tr> 345 //! <tr><td>Result<T></td><td>throw/catch</td><td><sup><i>allowed as return type only</i></sup></td></tr> 346 //! </table> 347 //! 348 //! The C++ API of the `rust` namespace is defined by the *include/cxx.h* file 349 //! in <https://github.com/dtolnay/cxx>. You will need to include this header in 350 //! your C++ code when working with those types. 351 //! 352 //! The following types are intended to be supported "soon" but are just not 353 //! implemented yet. I don't expect any of these to be hard to make work but 354 //! it's a matter of designing a nice API for each in its non-native language. 355 //! 356 //! <table> 357 //! <tr><th>name in Rust</th><th>name in C++</th></tr> 358 //! <tr><td>BTreeMap<K, V></td><td><sup><i>tbd</i></sup></td></tr> 359 //! <tr><td>HashMap<K, V></td><td><sup><i>tbd</i></sup></td></tr> 360 //! <tr><td>Arc<T></td><td><sup><i>tbd</i></sup></td></tr> 361 //! <tr><td>Option<T></td><td><sup><i>tbd</i></sup></td></tr> 362 //! <tr><td><sup><i>tbd</i></sup></td><td>std::map<K, V></td></tr> 363 //! <tr><td><sup><i>tbd</i></sup></td><td>std::unordered_map<K, V></td></tr> 364 //! </table> 365 366 #![no_std] 367 #![doc(html_root_url = "https://docs.rs/cxx/1.0.91")] 368 #![deny( 369 improper_ctypes, 370 improper_ctypes_definitions, 371 missing_docs, 372 unsafe_op_in_unsafe_fn 373 )] 374 #![cfg_attr(doc_cfg, feature(doc_cfg))] 375 #![allow(non_camel_case_types)] 376 #![allow( 377 clippy::cognitive_complexity, 378 clippy::declare_interior_mutable_const, 379 clippy::doc_markdown, 380 clippy::empty_enum, 381 clippy::extra_unused_type_parameters, 382 clippy::inherent_to_string, 383 clippy::items_after_statements, 384 clippy::large_enum_variant, 385 clippy::len_without_is_empty, 386 clippy::missing_errors_doc, 387 clippy::missing_safety_doc, 388 clippy::module_inception, 389 clippy::module_name_repetitions, 390 clippy::must_use_candidate, 391 clippy::needless_doctest_main, 392 clippy::new_without_default, 393 clippy::or_fun_call, 394 clippy::ptr_arg, 395 clippy::toplevel_ref_arg, 396 clippy::transmute_undefined_repr, // clippy bug: https://github.com/rust-lang/rust-clippy/issues/8417 397 clippy::useless_let_if_seq, 398 clippy::wrong_self_convention 399 )] 400 401 #[cfg(built_with_cargo)] 402 extern crate link_cplusplus; 403 404 extern crate self as cxx; 405 406 #[doc(hidden)] 407 pub extern crate core; 408 409 #[cfg(feature = "alloc")] 410 #[doc(hidden)] 411 pub extern crate alloc; 412 413 #[cfg(not(feature = "alloc"))] 414 extern crate core as alloc; 415 416 #[cfg(feature = "std")] 417 #[doc(hidden)] 418 pub extern crate std; 419 420 // Block inadvertent use of items from libstd, which does not otherwise produce 421 // a compile-time error on edition 2018+. 422 #[cfg(not(feature = "std"))] 423 extern crate core as std; 424 425 #[cfg(not(any(feature = "alloc", cxx_experimental_no_alloc)))] 426 compile_error! { 427 r#"cxx support for no_alloc is incomplete and semver exempt; you must build with at least one of feature="std", feature="alloc", or RUSTFLAGS='--cfg cxx_experimental_no_alloc'"# 428 } 429 430 #[cfg(all(compile_error_if_alloc, feature = "alloc"))] 431 compile_error! { 432 r#"feature="alloc" is unexpectedly enabled"# 433 } 434 435 #[cfg(all(compile_error_if_std, feature = "std"))] 436 compile_error! { 437 r#"feature="std" is unexpectedly enabled"# 438 } 439 440 #[macro_use] 441 mod macros; 442 443 mod c_char; 444 mod cxx_vector; 445 mod exception; 446 mod extern_type; 447 mod fmt; 448 mod function; 449 mod hash; 450 mod lossy; 451 pub mod memory; 452 mod opaque; 453 mod result; 454 mod rust_slice; 455 mod rust_str; 456 mod rust_string; 457 mod rust_type; 458 mod rust_vec; 459 mod shared_ptr; 460 mod sip; 461 #[path = "cxx_string.rs"] 462 mod string; 463 mod symbols; 464 mod type_id; 465 mod unique_ptr; 466 mod unwind; 467 pub mod vector; 468 mod weak_ptr; 469 470 pub use crate::cxx_vector::CxxVector; 471 #[cfg(feature = "alloc")] 472 pub use crate::exception::Exception; 473 pub use crate::extern_type::{kind, ExternType}; 474 pub use crate::shared_ptr::SharedPtr; 475 pub use crate::string::CxxString; 476 pub use crate::unique_ptr::UniquePtr; 477 pub use crate::weak_ptr::WeakPtr; 478 pub use cxxbridge_macro::bridge; 479 480 /// Synonym for `CxxString`. 481 /// 482 /// To avoid confusion with Rust's standard library string you probably 483 /// shouldn't import this type with `use`. Instead, write `cxx::String`, or 484 /// import and use `CxxString`. 485 pub type String = CxxString; 486 487 /// Synonym for `CxxVector`. 488 /// 489 /// To avoid confusion with Rust's standard library vector you probably 490 /// shouldn't import this type with `use`. Instead, write `cxx::Vector<T>`, or 491 /// import and use `CxxVector`. 492 pub type Vector<T> = CxxVector<T>; 493 494 // Not public API. 495 #[doc(hidden)] 496 pub mod private { 497 pub use crate::c_char::c_char; 498 pub use crate::cxx_vector::VectorElement; 499 pub use crate::extern_type::{verify_extern_kind, verify_extern_type}; 500 pub use crate::function::FatFunction; 501 pub use crate::hash::hash; 502 pub use crate::opaque::Opaque; 503 #[cfg(feature = "alloc")] 504 pub use crate::result::{r#try, Result}; 505 pub use crate::rust_slice::RustSlice; 506 pub use crate::rust_str::RustStr; 507 #[cfg(feature = "alloc")] 508 pub use crate::rust_string::RustString; 509 pub use crate::rust_type::{ImplBox, ImplVec, RustType}; 510 #[cfg(feature = "alloc")] 511 pub use crate::rust_vec::RustVec; 512 pub use crate::shared_ptr::SharedPtrTarget; 513 pub use crate::string::StackString; 514 pub use crate::unique_ptr::UniquePtrTarget; 515 pub use crate::unwind::prevent_unwind; 516 pub use crate::weak_ptr::WeakPtrTarget; 517 pub use core::{concat, module_path}; 518 pub use cxxbridge_macro::type_id; 519 } 520 521 mod actually_private { 522 pub trait Private {} 523 } 524 525 macro_rules! chars { 526 ($($ch:ident)*) => { 527 $( 528 #[doc(hidden)] 529 pub enum $ch {} 530 )* 531 }; 532 } 533 534 chars! { 535 _0 _1 _2 _3 _4 _5 _6 _7 _8 _9 536 A B C D E F G H I J K L M N O P Q R S T U V W X Y Z 537 a b c d e f g h i j k l m n o p q r s t u v w x y z 538 __ // underscore 539 } 540 541 #[repr(transparent)] 542 struct void(core::ffi::c_void); 543