| David Tolnay | 7db7369 | 2019-10-20 14:51:12 -0400 | [diff] [blame] | 1 | //! This library provides a **safe** mechanism for calling C++ code from Rust |
| 2 | //! and Rust code from C++, not subject to the many ways that things can go |
| 3 | //! wrong when using bindgen or cbindgen to generate unsafe C-style bindings. |
| 4 | //! |
| David Tolnay | ccd3975 | 2020-01-08 09:33:51 -0800 | [diff] [blame] | 5 | //! This doesn't change the fact that 100% of C++ code is unsafe. When auditing |
| 6 | //! a project, you would be on the hook for auditing all the unsafe Rust code |
| 7 | //! and *all* the C++ code. The core safety claim under this new model is that |
| 8 | //! auditing just the C++ side would be sufficient to catch all problems, i.e. |
| 9 | //! the Rust side can be 100% safe. |
| 10 | //! |
| David Tolnay | 7db7369 | 2019-10-20 14:51:12 -0400 | [diff] [blame] | 11 | //! <br> |
| 12 | //! |
| 13 | //! *Compiler support: requires rustc 1.42+ (beta on January 30, stable on March |
| 14 | //! 12)* |
| 15 | //! |
| 16 | //! <br> |
| 17 | //! |
| 18 | //! # Overview |
| 19 | //! |
| 20 | //! The idea is that we define the signatures of both sides of our FFI boundary |
| 21 | //! embedded together in one Rust module (the next section shows an example). |
| 22 | //! From this, CXX receives a complete picture of the boundary to perform static |
| 23 | //! analyses against the types and function signatures to uphold both Rust's and |
| 24 | //! C++'s invariants and requirements. |
| 25 | //! |
| 26 | //! If everything checks out statically, then CXX uses a pair of code generators |
| 27 | //! to emit the relevant `extern "C"` signatures on both sides together with any |
| 28 | //! necessary static assertions for later in the build process to verify |
| 29 | //! correctness. On the Rust side this code generator is simply an attribute |
| 30 | //! procedural macro. On the C++ side it can be a small Cargo build script if |
| 31 | //! your build is managed by Cargo, or for other build systems like Bazel or |
| 32 | //! Buck we provide a command line tool which generates the header and source |
| 33 | //! file and should be easy to integrate. |
| 34 | //! |
| 35 | //! The resulting FFI bridge operates at zero or negligible overhead, i.e. no |
| 36 | //! copying, no serialization, no memory allocation, no runtime checks needed. |
| 37 | //! |
| 38 | //! The FFI signatures are able to use native types from whichever side they |
| 39 | //! please, such as Rust's `String` or C++'s `std::string`, Rust's `Box` or |
| 40 | //! C++'s `std::unique_ptr`, Rust's `Vec` or C++'s `std::vector`, etc in any |
| 41 | //! combination. CXX guarantees an ABI-compatible signature that both sides |
| 42 | //! understand, based on builtin bindings for key standard library types to |
| 43 | //! expose an idiomatic API on those types to the other language. For example |
| 44 | //! when manipulating a C++ string from Rust, its `len()` method becomes a call |
| 45 | //! of the `size()` member function defined by C++; when manipulation a Rust |
| 46 | //! string from C++, its `size()` member function calls Rust's `len()`. |
| 47 | //! |
| 48 | //! <br> |
| 49 | //! |
| 50 | //! # Example |
| 51 | //! |
| 52 | //! A runnable version of this example is provided under the *demo-rs* directory |
| 53 | //! of https://github.com/dtolnay/cxx (with the C++ side of the implementation |
| 54 | //! in the *demo-cxx* directory). To try it out, jump into demo-rs and run |
| 55 | //! `cargo run`. |
| 56 | //! |
| 57 | //! ```no_run |
| 58 | //! #[cxx::bridge] |
| 59 | //! mod ffi { |
| 60 | //! // Any shared structs, whose fields will be visible to both languages. |
| 61 | //! struct SharedThing { |
| 62 | //! z: i32, |
| 63 | //! y: Box<ThingR>, |
| 64 | //! x: UniquePtr<ThingC>, |
| 65 | //! } |
| 66 | //! |
| 67 | //! extern "C" { |
| 68 | //! // One or more headers with the matching C++ declarations. Our code |
| 69 | //! // generators don't read it but it gets #include'd and used in static |
| 70 | //! // assertions to ensure our picture of the FFI boundary is accurate. |
| 71 | //! include!("demo-cxx/demo.h"); |
| 72 | //! |
| 73 | //! // Zero or more opaque types which both languages can pass around but |
| 74 | //! // only C++ can see the fields. |
| 75 | //! type ThingC; |
| 76 | //! |
| 77 | //! // Functions implemented in C++. |
| 78 | //! fn make_demo(appname: &str) -> UniquePtr<ThingC>; |
| 79 | //! fn get_name(thing: &ThingC) -> &CxxString; |
| 80 | //! fn do_thing(state: SharedThing); |
| 81 | //! } |
| 82 | //! |
| 83 | //! extern "Rust" { |
| 84 | //! // Zero or more opaque types which both languages can pass around but |
| 85 | //! // only Rust can see the fields. |
| 86 | //! type ThingR; |
| 87 | //! |
| 88 | //! // Functions implemented in Rust. |
| 89 | //! fn print_r(r: &ThingR); |
| 90 | //! } |
| 91 | //! } |
| 92 | //! # |
| 93 | //! # pub struct ThingR(usize); |
| 94 | //! # |
| 95 | //! # fn print_r(r: &ThingR) { |
| 96 | //! # println!("called back with r={}", r.0); |
| 97 | //! # } |
| 98 | //! # |
| 99 | //! # fn main() {} |
| 100 | //! ``` |
| 101 | //! |
| 102 | //! Now we simply provide C++ definitions of all the things in the `extern "C"` |
| 103 | //! block and Rust definitions of all the things in the `extern "Rust"` block, |
| 104 | //! and get to call back and forth safely. |
| 105 | //! |
| 106 | //! Here are links to the complete set of source files involved in the demo: |
| 107 | //! |
| 108 | //! - [demo-rs/src/main.rs](https://github.com/dtolnay/cxx/blob/master/demo-rs/src/main.rs) |
| 109 | //! - [demo-rs/build.rs](https://github.com/dtolnay/cxx/blob/master/demo-rs/build.rs) |
| 110 | //! - [demo-cxx/demo.h](https://github.com/dtolnay/cxx/blob/master/demo-cxx/demo.h) |
| 111 | //! - [demo-cxx/demo.cc](https://github.com/dtolnay/cxx/blob/master/demo-cxx/demo.cc) |
| 112 | //! |
| 113 | //! To look at the code generated in both languages for the example by the CXX |
| 114 | //! code generators: |
| 115 | //! |
| 116 | //! ```console |
| 117 | //! # run Rust code generator and print to stdout |
| 118 | //! # (requires https://github.com/dtolnay/cargo-expand) |
| 119 | //! $ cargo expand --manifest-path demo-rs/Cargo.toml |
| 120 | //! |
| 121 | //! # run C++ code generator and print to stdout |
| 122 | //! $ cargo run --manifest-path cmd/Cargo.toml -- demo-rs/src/main.rs |
| 123 | //! ``` |
| 124 | //! |
| 125 | //! <br> |
| 126 | //! |
| 127 | //! # Details |
| 128 | //! |
| 129 | //! As seen in the example, the language of the FFI boundary involves 3 kinds of |
| 130 | //! items: |
| 131 | //! |
| 132 | //! - **Shared structs** — their fields are made visible to both |
| 133 | //! languages. The definition written within cxx::bridge is the single source |
| 134 | //! of truth. |
| 135 | //! |
| 136 | //! - **Opaque types** — their fields are secret from the other language. |
| 137 | //! These cannot be passed across the FFI by value but only behind an |
| 138 | //! indirection, such as a reference `&`, a Rust `Box`, or a `UniquePtr`. Can |
| 139 | //! be a type alias for an arbitrarily complicated generic language-specific |
| 140 | //! type depending on your use case. |
| 141 | //! |
| 142 | //! - **Functions** — implemented in either language, callable from the |
| 143 | //! other language. |
| 144 | //! |
| 145 | //! Within the `extern "C"` part of the CXX bridge we list the types and |
| 146 | //! functions for which C++ is the source of truth, as well as the header(s) |
| 147 | //! that declare those APIs. In the future it's possible that this section could |
| 148 | //! be generated bindgen-style from the headers but for now we need the |
| 149 | //! signatures written out; static assertions will verify that they are |
| 150 | //! accurate. |
| 151 | //! |
| 152 | //! Within the `extern "Rust"` part, we list types and functions for which Rust |
| 153 | //! is the source of truth. These all implicitly refer to the `super` module, |
| 154 | //! the parent module of the CXX bridge. You can think of the two items listed |
| 155 | //! in the example above as being like `use super::ThingR` and `use |
| 156 | //! super::print_r` except re-exported to C++. The parent module will either |
| 157 | //! contain the definitions directly for simple things, or contain the relevant |
| 158 | //! `use` statements to bring them into scope from elsewhere. |
| 159 | //! |
| 160 | //! Your function implementations themselves, whether in C++ or Rust, *do not* |
| 161 | //! need to be defined as `extern "C"` ABI or no\_mangle. CXX will put in the |
| 162 | //! right shims where necessary to make it all work. |
| 163 | //! |
| 164 | //! <br> |
| 165 | //! |
| 166 | //! # Comparison vs bindgen and cbindgen |
| 167 | //! |
| 168 | //! Notice that with CXX there is repetition of all the function signatures: |
| 169 | //! they are typed out once where the implementation is defined (in C++ or Rust) |
| 170 | //! and again inside the cxx::bridge module, though compile-time assertions |
| 171 | //! guarantee these are kept in sync. This is different from [bindgen] and |
| 172 | //! [cbindgen] where function signatures are typed by a human once and the tool |
| 173 | //! consumes them in one language and emits them in the other language. |
| 174 | //! |
| 175 | //! [bindgen]: https://github.com/rust-lang/rust-bindgen |
| 176 | //! [cbindgen]: https://github.com/eqrion/cbindgen/ |
| 177 | //! |
| 178 | //! This is because CXX fills a somewhat different role. It is a lower level |
| 179 | //! tool than bindgen or cbindgen in a sense; you can think of it as being a |
| 180 | //! replacement for the concept of `extern "C"` signatures as we know them, |
| 181 | //! rather than a replacement for a bindgen. It would be reasonable to build a |
| 182 | //! higher level bindgen-like tool on top of CXX which consumes a C++ header |
| 183 | //! and/or Rust module (and/or IDL like Thrift) as source of truth and generates |
| 184 | //! the cxx::bridge, eliminating the repetition while leveraging the static |
| 185 | //! analysis safety guarantees of CXX. |
| 186 | //! |
| 187 | //! But note in other ways CXX is higher level than the bindgens, with rich |
| 188 | //! support for common standard library types. Frequently with bindgen when we |
| 189 | //! are dealing with an idiomatic C++ API we would end up manually wrapping that |
| 190 | //! API in C-style raw pointer functions, applying bindgen to get unsafe raw |
| 191 | //! pointer Rust functions, and replicating the API again to expose those |
| 192 | //! idiomatically in Rust. That's a much worse form of repetition because it is |
| 193 | //! unsafe all the way through. |
| 194 | //! |
| 195 | //! By using a CXX bridge as the shared understanding between the languages, |
| 196 | //! rather than `extern "C"` C-style signatures as the shared understanding, |
| 197 | //! common FFI use cases become expressible using 100% safe code. |
| 198 | //! |
| 199 | //! It would also be reasonable to mix and match, using CXX bridge for the 95% |
| 200 | //! of your FFI that is straightforward and doing the remaining few oddball |
| 201 | //! signatures the old fashioned way with bindgen and cbindgen, if for some |
| 202 | //! reason CXX's static restrictions get in the way. Please file an issue if you |
| 203 | //! end up taking this approach so that we know what ways it would be worthwhile |
| 204 | //! to make the tool more expressive. |
| 205 | //! |
| 206 | //! <br> |
| 207 | //! |
| 208 | //! # Cargo-based setup |
| 209 | //! |
| 210 | //! For builds that are orchestrated by Cargo, you will use a build script that |
| 211 | //! runs CXX's C++ code generator and compiles the resulting C++ code along with |
| 212 | //! any other C++ code for your crate. |
| 213 | //! |
| 214 | //! The canonical build script is as follows. The indicated line returns a |
| 215 | //! [`cc::Build`] instance (from the usual widely used `cc` crate) on which you |
| 216 | //! can set up any additional source files and compiler flags as normal. |
| 217 | //! |
| 218 | //! [`cc::Build`]: https://docs.rs/cc/1.0/cc/struct.Build.html |
| 219 | //! |
| 220 | //! ```no_run |
| 221 | //! // build.rs |
| 222 | //! |
| 223 | //! fn main() { |
| 224 | //! cxx::Build::new() |
| 225 | //! .bridge("src/main.rs") // returns a cc::Build |
| 226 | //! .file("../demo-cxx/demo.cc") |
| 227 | //! .flag("-std=c++11") |
| 228 | //! .compile("cxxbridge-demo"); |
| 229 | //! |
| 230 | //! println!("cargo:rerun-if-changed=src/main.rs"); |
| 231 | //! println!("cargo:rerun-if-changed=../demo-cxx/demo.h"); |
| 232 | //! println!("cargo:rerun-if-changed=../demo-cxx/demo.cc"); |
| 233 | //! } |
| 234 | //! ``` |
| 235 | //! |
| 236 | //! <br><br> |
| 237 | //! |
| 238 | //! # Non-Cargo setup |
| 239 | //! |
| 240 | //! For use in non-Cargo builds like Bazel or Buck, CXX provides an alternate |
| 241 | //! way of invoking the C++ code generator as a standalone command line tool. |
| 242 | //! The tool is packaged as the `cxxbridge-cmd` crate on crates.io or can be |
| 243 | //! built from the *cmd* directory of https://github.com/dtolnay/cxx. |
| 244 | //! |
| 245 | //! ```bash |
| 246 | //! $ cargo install cxxbridge-cmd |
| 247 | //! |
| 248 | //! $ cxxbridge src/main.rs --header > path/to/mybridge.h |
| 249 | //! $ cxxbridge src/main.rs > path/to/mybridge.cc |
| 250 | //! ``` |
| 251 | //! |
| 252 | //! <br> |
| 253 | //! |
| 254 | //! # Safety |
| 255 | //! |
| 256 | //! Be aware that the design of this library is intentionally restrictive and |
| 257 | //! opinionated! It isn't a goal to be powerful enough to handle arbitrary |
| 258 | //! signatures in either language. Instead this project is about carving out a |
| 259 | //! reasonably expressive set of functionality about which we can make useful |
| 260 | //! safety guarantees today and maybe extend over time. You may find that it |
| 261 | //! takes some practice to use CXX bridge effectively as it won't work in all |
| 262 | //! the ways that you are used to. |
| 263 | //! |
| 264 | //! Some of the considerations that go into ensuring safety are: |
| 265 | //! |
| 266 | //! - By design, our paired code generators work together to control both sides |
| 267 | //! of the FFI boundary. Ordinarily in Rust writing your own `extern "C"` |
| 268 | //! blocks is unsafe because the Rust compiler has no way to know whether the |
| 269 | //! signatures you've written actually match the signatures implemented in the |
| 270 | //! other language. With CXX we achieve that visibility and know what's on the |
| 271 | //! other side. |
| 272 | //! |
| 273 | //! - Our static analysis detects and prevents passing types by value that |
| 274 | //! shouldn't be passed by value from C++ to Rust, for example because they |
| 275 | //! may contain internal pointers that would be screwed up by Rust's move |
| 276 | //! behavior. |
| 277 | //! |
| 278 | //! - To many people's surprise, it is possible to have a struct in Rust and a |
| 279 | //! struct in C++ with exactly the same layout / fields / alignment / |
| 280 | //! everything, and still not the same ABI when passed by value. This is a |
| 281 | //! longstanding bindgen bug that leads to segfaults in absolutely |
| 282 | //! correct-looking code ([rust-lang/rust-bindgen#778]). CXX knows about this |
| 283 | //! and can insert the necessary zero-cost workaround transparently where |
| 284 | //! needed, so go ahead and pass your structs by value without worries. This |
| 285 | //! is made possible by owning both sides of the boundary rather than just |
| 286 | //! one. |
| 287 | //! |
| 288 | //! - Template instantiations: for example in order to expose a UniquePtr\<T\> |
| 289 | //! type in Rust backed by a real C++ unique\_ptr, we have a way of using a |
| 290 | //! Rust trait to connect the behavior back to the template instantiations |
| 291 | //! performed by the other language. |
| 292 | //! |
| 293 | //! [rust-lang/rust-bindgen#778]: https://github.com/rust-lang/rust-bindgen/issues/778 |
| 294 | //! |
| 295 | //! <br> |
| 296 | //! |
| 297 | //! # Builtin types |
| 298 | //! |
| 299 | //! In addition to all the primitive types (i32 ⟷ int32_t), the following common |
| 300 | //! types may be used in the fields of shared structs and the arguments and |
| 301 | //! returns of functions. |
| 302 | //! |
| 303 | //! <table> |
| 304 | //! <tr><th>name in Rust</th><th>name in C++</th><th>restrictions</th></tr> |
| 305 | //! <tr><td>String</td><td>cxxbridge::RustString</td><td></td></tr> |
| 306 | //! <tr><td>&str</td><td>cxxbridge::RustStr</td><td></td></tr> |
| David Tolnay | e43b737 | 2020-01-08 08:46:20 -0800 | [diff] [blame] | 307 | //! <tr><td><a href="https://docs.rs/cxx/0.1/cxx/struct.CxxString.html">CxxString</a></td><td>std::string</td><td><sup><i>cannot be passed by value</i></sup></td></tr> |
| David Tolnay | 7db7369 | 2019-10-20 14:51:12 -0400 | [diff] [blame] | 308 | //! <tr><td>Box<T></td><td>cxxbridge::RustBox<T></td><td><sup><i>cannot hold opaque C++ type</i></sup></td></tr> |
| David Tolnay | e43b737 | 2020-01-08 08:46:20 -0800 | [diff] [blame] | 309 | //! <tr><td><a href="https://docs.rs/cxx/0.1/cxx/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> |
| David Tolnay | 7db7369 | 2019-10-20 14:51:12 -0400 | [diff] [blame] | 310 | //! <tr><td></td><td></td><td></td></tr> |
| 311 | //! </table> |
| 312 | //! |
| 313 | //! The C++ API of the `cxxbridge` namespace is defined by the |
| 314 | //! *include/cxxbridge.h* file in https://github.com/dtolnay/cxx. You will need |
| 315 | //! to include this header in your C++ code when working with those types. |
| 316 | //! |
| 317 | //! The following types are intended to be supported "soon" but are just not |
| 318 | //! implemented yet. I don't expect any of these to be hard to make work but |
| 319 | //! it's a matter of designing a nice API for each in its non-native language. |
| 320 | //! |
| 321 | //! <table> |
| 322 | //! <tr><th>name in Rust</th><th>name in C++</th></tr> |
| David Tolnay | 84f232e | 2020-01-08 12:22:56 -0800 | [diff] [blame] | 323 | //! <tr><td>&[T]</td><td><sup><i>tbd</i></sup></td></tr> |
| 324 | //! <tr><td>Vec<T></td><td><sup><i>tbd</i></sup></td></tr> |
| 325 | //! <tr><td>BTreeMap<K, V></td><td><sup><i>tbd</i></sup></td></tr> |
| 326 | //! <tr><td>HashMap<K, V></td><td><sup><i>tbd</i></sup></td></tr> |
| 327 | //! <tr><td><sup><i>tbd</i></sup></td><td>std::vector<T></td></tr> |
| 328 | //! <tr><td><sup><i>tbd</i></sup></td><td>std::map<K, V></td></tr> |
| 329 | //! <tr><td><sup><i>tbd</i></sup></td><td>std::unordered_map<K, V></td></tr> |
| David Tolnay | 7db7369 | 2019-10-20 14:51:12 -0400 | [diff] [blame] | 330 | //! </table> |
| 331 | |
| 332 | #![deny(improper_ctypes)] |
| 333 | #![allow( |
| 334 | clippy::large_enum_variant, |
| 335 | clippy::missing_safety_doc, |
| 336 | clippy::module_inception, |
| 337 | clippy::new_without_default, |
| 338 | clippy::or_fun_call, |
| 339 | clippy::ptr_arg, |
| 340 | clippy::toplevel_ref_arg, |
| 341 | clippy::transmute_ptr_to_ptr, |
| 342 | clippy::useless_let_if_seq |
| 343 | )] |
| 344 | |
| David Tolnay | af60e23 | 2020-01-24 15:22:09 -0800 | [diff] [blame^] | 345 | extern crate link_cplusplus; |
| 346 | |
| David Tolnay | 7db7369 | 2019-10-20 14:51:12 -0400 | [diff] [blame] | 347 | mod cxx_string; |
| 348 | mod error; |
| 349 | mod gen; |
| 350 | mod opaque; |
| 351 | mod paths; |
| 352 | mod rust_str; |
| 353 | mod rust_string; |
| 354 | mod syntax; |
| 355 | mod unique_ptr; |
| 356 | mod unwind; |
| 357 | |
| 358 | pub use crate::cxx_string::CxxString; |
| 359 | pub use crate::unique_ptr::UniquePtr; |
| 360 | pub use cxxbridge_macro::bridge; |
| 361 | |
| 362 | // Not public API. |
| 363 | #[doc(hidden)] |
| 364 | pub mod private { |
| 365 | pub use crate::opaque::Opaque; |
| 366 | pub use crate::rust_str::RustStr; |
| 367 | pub use crate::rust_string::RustString; |
| 368 | pub use crate::unique_ptr::UniquePtrTarget; |
| 369 | pub use crate::unwind::catch_unwind; |
| 370 | } |
| 371 | |
| 372 | use crate::error::Result; |
| 373 | use std::fs; |
| 374 | use std::io::{self, Write}; |
| 375 | use std::path::Path; |
| 376 | use std::process; |
| 377 | |
| 378 | /// The CXX code generator for constructing and compiling C++ code. |
| 379 | /// |
| 380 | /// This is intended to be used from Cargo build scripts to execute CXX's |
| 381 | /// C++ code generator, set up any additional compiler flags depending on |
| 382 | /// the use case, and make the C++ compiler invocation. |
| 383 | /// |
| 384 | /// <br> |
| 385 | /// |
| 386 | /// # Example |
| 387 | /// |
| 388 | /// Example of a canonical Cargo build script that builds a CXX bridge: |
| 389 | /// |
| 390 | /// ```no_run |
| 391 | /// // build.rs |
| 392 | /// |
| 393 | /// fn main() { |
| 394 | /// cxx::Build::new() |
| 395 | /// .bridge("src/main.rs") |
| 396 | /// .file("../demo-cxx/demo.cc") |
| 397 | /// .flag("-std=c++11") |
| 398 | /// .compile("cxxbridge-demo"); |
| 399 | /// |
| 400 | /// println!("cargo:rerun-if-changed=src/main.rs"); |
| 401 | /// println!("cargo:rerun-if-changed=../demo-cxx/demo.h"); |
| 402 | /// println!("cargo:rerun-if-changed=../demo-cxx/demo.cc"); |
| 403 | /// } |
| 404 | /// ``` |
| 405 | /// |
| 406 | /// A runnable working setup with this build script is shown in the |
| 407 | /// *demo-rs* and *demo-cxx* directories of |
| 408 | /// [https://github.com/dtolnay/cxx](https://github.com/dtolnay/cxx). |
| 409 | /// |
| 410 | /// <br> |
| 411 | /// |
| 412 | /// # Alternatives |
| 413 | /// |
| 414 | /// For use in non-Cargo builds like Bazel or Buck, CXX provides an |
| 415 | /// alternate way of invoking the C++ code generator as a standalone command |
| 416 | /// line tool. The tool is packaged as the `cxxbridge-cmd` crate. |
| 417 | /// |
| 418 | /// ```bash |
| 419 | /// $ cargo install cxxbridge-cmd # or build it from the repo |
| 420 | /// |
| 421 | /// $ cxxbridge src/main.rs --header > path/to/mybridge.h |
| 422 | /// $ cxxbridge src/main.rs > path/to/mybridge.cc |
| 423 | /// ``` |
| 424 | #[must_use] |
| 425 | pub struct Build { |
| 426 | _private: (), |
| 427 | } |
| 428 | |
| 429 | impl Build { |
| 430 | /// Begin with a [`cc::Build`] in its default configuration. |
| 431 | pub fn new() -> Self { |
| 432 | Build { _private: () } |
| 433 | } |
| 434 | |
| 435 | /// This returns a [`cc::Build`] on which you should continue to set up |
| 436 | /// any additional source files or compiler flags, and lastly call its |
| 437 | /// [`compile`] method to execute the C++ build. |
| 438 | /// |
| 439 | /// [`compile`]: https://docs.rs/cc/1.0.49/cc/struct.Build.html#method.compile |
| 440 | #[must_use] |
| 441 | pub fn bridge(&self, rust_source_file: impl AsRef<Path>) -> cc::Build { |
| 442 | match try_generate_bridge(rust_source_file.as_ref()) { |
| 443 | Ok(build) => build, |
| 444 | Err(err) => { |
| 445 | let _ = writeln!(io::stderr(), "\n\ncxxbridge error: {}\n\n", err); |
| 446 | process::exit(1); |
| 447 | } |
| 448 | } |
| 449 | } |
| 450 | } |
| 451 | |
| 452 | fn try_generate_bridge(rust_source_file: &Path) -> Result<cc::Build> { |
| 453 | let header = gen::do_generate_header(rust_source_file); |
| 454 | let header_path = paths::out_with_extension(rust_source_file, ".h")?; |
| 455 | fs::create_dir_all(header_path.parent().unwrap())?; |
| 456 | fs::write(&header_path, header)?; |
| 457 | paths::symlink_header(&header_path, rust_source_file); |
| 458 | |
| 459 | let bridge = gen::do_generate_bridge(rust_source_file); |
| 460 | let bridge_path = paths::out_with_extension(rust_source_file, ".cc")?; |
| 461 | fs::write(&bridge_path, bridge)?; |
| 462 | let mut build = paths::cc_build(); |
| 463 | build.file(&bridge_path); |
| 464 | |
| 465 | Ok(build) |
| 466 | } |