Name |
Date |
Size |
#Lines |
LOC |
||
---|---|---|---|---|---|---|
.. | - | - | ||||
.devcontainer/ | 12-May-2024 | - | 47 | 41 | ||
.github/ | 12-May-2024 | - | 189 | 166 | ||
.vscode/ | 12-May-2024 | - | 72 | 67 | ||
book/ | 12-May-2024 | - | 4,917 | 4,002 | ||
demo/ | 12-May-2024 | - | 258 | 191 | ||
flags/ | 12-May-2024 | - | 250 | 205 | ||
gen/ | 12-May-2024 | - | 6,872 | 5,607 | ||
include/ | 12-May-2024 | - | 1,112 | 886 | ||
macro/ | 12-May-2024 | - | 3,087 | 2,766 | ||
src/ | 12-May-2024 | - | 4,305 | 2,879 | ||
syntax/ | 12-May-2024 | - | 6,217 | 5,510 | ||
tests/ | 12-May-2024 | - | 4,550 | 3,737 | ||
third-party/ | 12-May-2024 | - | 2,594 | 2,322 | ||
tools/ | 12-May-2024 | - | 206 | 172 | ||
.bazelignore | D | 12-May-2024 | 26 | 3 | 2 | |
.bazelrc | D | 12-May-2024 | 110 | 3 | 2 | |
.buckconfig | D | 12-May-2024 | 497 | 18 | 15 | |
.clang-format | D | 12-May-2024 | 61 | 3 | 2 | |
.clang-tidy | D | 12-May-2024 | 620 | 19 | 18 | |
.clippy.toml | D | 12-May-2024 | 16 | 2 | 1 | |
.gitattributes | D | 12-May-2024 | 76 | 3 | 2 | |
.gitignore | D | 12-May-2024 | 107 | 11 | 10 | |
.gitmodules | D | 12-May-2024 | 118 | 4 | 3 | |
.watchmanconfig | D | 12-May-2024 | 36 | 4 | 3 | |
BUCK | D | 12-May-2024 | 2 KiB | 93 | 87 | |
BUILD | D | 12-May-2024 | 2.1 KiB | 90 | 82 | |
BUILD.gn | D | 12-May-2024 | 1.5 KiB | 51 | 46 | |
Cargo.toml | D | 12-May-2024 | 1.5 KiB | 53 | 44 | |
LICENSE-APACHE | D | 12-May-2024 | 9.5 KiB | 177 | 150 | |
LICENSE-MIT | D | 12-May-2024 | 1,023 | 24 | 21 | |
OAT.xml | D | 12-May-2024 | 4.2 KiB | 67 | 13 | |
README.OpenSource | D | 12-May-2024 | 357 | 12 | 11 | |
README.md | D | 12-May-2024 | 16.9 KiB | 389 | 299 | |
README_zh.md | D | 12-May-2024 | 14 KiB | 430 | 338 | |
WORKSPACE | D | 12-May-2024 | 708 | 26 | 16 | |
build.rs | D | 12-May-2024 | 869 | 33 | 29 | |
compile_flags.txt | D | 12-May-2024 | 11 | 2 | 1 | |
cpp_call_rust.png | D | 12-May-2024 | 96.2 KiB | |||
rust_call_cpp.png | D | 12-May-2024 | 11 KiB |
README.OpenSource
1[ 2 { 3 "Name": "cxx", 4 "License": "Apache License 2.0, MIT", 5 "License File": "LICENSE-APACHE, LICENSE-MIT", 6 "Version Number": "1.0.91", 7 "Owner": "fangting12@huawei.com", 8 "Upstream URL": "https://github.com/dtolnay/cxx", 9 "Description": "A Rust library that provides a safe and easy way to call C++ code from Rust." 10 } 11] 12
README.md
1CXX — safe FFI between Rust and C++ 2========================================= 3 4[<img alt="github" src="https://img.shields.io/badge/github-dtolnay/cxx-8da0cb?style=for-the-badge&labelColor=555555&logo=github" height="20">](https://github.com/dtolnay/cxx) 5[<img alt="crates.io" src="https://img.shields.io/crates/v/cxx.svg?style=for-the-badge&color=fc8d62&logo=rust" height="20">](https://crates.io/crates/cxx) 6[<img alt="docs.rs" src="https://img.shields.io/badge/docs.rs-cxx-66c2a5?style=for-the-badge&labelColor=555555&logo=docs.rs" height="20">](https://docs.rs/cxx) 7[<img alt="build status" src="https://img.shields.io/github/actions/workflow/status/dtolnay/cxx/ci.yml?branch=master&style=for-the-badge" height="20">](https://github.com/dtolnay/cxx/actions?query=branch%3Amaster) 8 9This library provides a **safe** mechanism for calling C++ code from Rust and 10Rust code from C++, not subject to the many ways that things can go wrong when 11using bindgen or cbindgen to generate unsafe C-style bindings. 12 13This doesn't change the fact that 100% of C++ code is unsafe. When auditing a 14project, you would be on the hook for auditing all the unsafe Rust code and 15*all* the C++ code. The core safety claim under this new model is that auditing 16just the C++ side would be sufficient to catch all problems, i.e. the Rust side 17can be 100% safe. 18 19```toml 20[dependencies] 21cxx = "1.0" 22 23[build-dependencies] 24cxx-build = "1.0" 25``` 26 27*Compiler support: requires rustc 1.60+ and c++11 or newer*<br> 28*[Release notes](https://github.com/dtolnay/cxx/releases)* 29 30<br> 31 32## Guide 33 34Please see **<https://cxx.rs>** for a tutorial, reference material, and example 35code. 36 37<br> 38 39## Overview 40 41The idea is that we define the signatures of both sides of our FFI boundary 42embedded together in one Rust module (the next section shows an example). From 43this, CXX receives a complete picture of the boundary to perform static analyses 44against the types and function signatures to uphold both Rust's and C++'s 45invariants and requirements. 46 47If everything checks out statically, then CXX uses a pair of code generators to 48emit the relevant `extern "C"` signatures on both sides together with any 49necessary static assertions for later in the build process to verify 50correctness. On the Rust side this code generator is simply an attribute 51procedural macro. On the C++ side it can be a small Cargo build script if your 52build is managed by Cargo, or for other build systems like Bazel or Buck we 53provide a command line tool which generates the header and source file and 54should be easy to integrate. 55 56The resulting FFI bridge operates at zero or negligible overhead, i.e. no 57copying, no serialization, no memory allocation, no runtime checks needed. 58 59The FFI signatures are able to use native types from whichever side they please, 60such as Rust's `String` or C++'s `std::string`, Rust's `Box` or C++'s 61`std::unique_ptr`, Rust's `Vec` or C++'s `std::vector`, etc in any combination. 62CXX guarantees an ABI-compatible signature that both sides understand, based on 63builtin bindings for key standard library types to expose an idiomatic API on 64those types to the other language. For example when manipulating a C++ string 65from Rust, its `len()` method becomes a call of the `size()` member function 66defined by C++; when manipulating a Rust string from C++, its `size()` member 67function calls Rust's `len()`. 68 69<br> 70 71## Example 72 73In this example we are writing a Rust application that wishes to take advantage 74of an existing C++ client for a large-file blobstore service. The blobstore 75supports a `put` operation for a discontiguous buffer upload. For example we 76might be uploading snapshots of a circular buffer which would tend to consist of 772 chunks, or fragments of a file spread across memory for some other reason. 78 79A runnable version of this example is provided under the *demo* directory of 80this repo. To try it out, run `cargo run` from that directory. 81 82```rust 83#[cxx::bridge] 84mod ffi { 85 // Any shared structs, whose fields will be visible to both languages. 86 struct BlobMetadata { 87 size: usize, 88 tags: Vec<String>, 89 } 90 91 extern "Rust" { 92 // Zero or more opaque types which both languages can pass around but 93 // only Rust can see the fields. 94 type MultiBuf; 95 96 // Functions implemented in Rust. 97 fn next_chunk(buf: &mut MultiBuf) -> &[u8]; 98 } 99 100 unsafe extern "C++" { 101 // One or more headers with the matching C++ declarations. Our code 102 // generators don't read it but it gets #include'd and used in static 103 // assertions to ensure our picture of the FFI boundary is accurate. 104 include!("demo/include/blobstore.h"); 105 106 // Zero or more opaque types which both languages can pass around but 107 // only C++ can see the fields. 108 type BlobstoreClient; 109 110 // Functions implemented in C++. 111 fn new_blobstore_client() -> UniquePtr<BlobstoreClient>; 112 fn put(&self, parts: &mut MultiBuf) -> u64; 113 fn tag(&self, blobid: u64, tag: &str); 114 fn metadata(&self, blobid: u64) -> BlobMetadata; 115 } 116} 117``` 118 119Now we simply provide Rust definitions of all the things in the `extern "Rust"` 120block and C++ definitions of all the things in the `extern "C++"` block, and get 121to call back and forth safely. 122 123Here are links to the complete set of source files involved in the demo: 124 125- [demo/src/main.rs](demo/src/main.rs) 126- [demo/build.rs](demo/build.rs) 127- [demo/include/blobstore.h](demo/include/blobstore.h) 128- [demo/src/blobstore.cc](demo/src/blobstore.cc) 129 130To look at the code generated in both languages for the example by the CXX code 131generators: 132 133```console 134 # run Rust code generator and print to stdout 135 # (requires https://github.com/dtolnay/cargo-expand) 136$ cargo expand --manifest-path demo/Cargo.toml 137 138 # run C++ code generator and print to stdout 139$ cargo run --manifest-path gen/cmd/Cargo.toml -- demo/src/main.rs 140``` 141 142<br> 143 144## Details 145 146As seen in the example, the language of the FFI boundary involves 3 kinds of 147items: 148 149- **Shared structs** — their fields are made visible to both languages. 150 The definition written within cxx::bridge is the single source of truth. 151 152- **Opaque types** — their fields are secret from the other language. 153 These cannot be passed across the FFI by value but only behind an indirection, 154 such as a reference `&`, a Rust `Box`, or a `UniquePtr`. Can be a type alias 155 for an arbitrarily complicated generic language-specific type depending on 156 your use case. 157 158- **Functions** — implemented in either language, callable from the other 159 language. 160 161Within the `extern "Rust"` part of the CXX bridge we list the types and 162functions for which Rust is the source of truth. These all implicitly refer to 163the `super` module, the parent module of the CXX bridge. You can think of the 164two items listed in the example above as being like `use super::MultiBuf` and 165`use super::next_chunk` except re-exported to C++. The parent module will either 166contain the definitions directly for simple things, or contain the relevant 167`use` statements to bring them into scope from elsewhere. 168 169Within the `extern "C++"` part, we list types and functions for which C++ is the 170source of truth, as well as the header(s) that declare those APIs. In the future 171it's possible that this section could be generated bindgen-style from the 172headers but for now we need the signatures written out; static assertions will 173verify that they are accurate. 174 175Your function implementations themselves, whether in C++ or Rust, *do not* need 176to be defined as `extern "C"` ABI or no\_mangle. CXX will put in the right shims 177where necessary to make it all work. 178 179<br> 180 181## Comparison vs bindgen and cbindgen 182 183Notice that with CXX there is repetition of all the function signatures: they 184are typed out once where the implementation is defined (in C++ or Rust) and 185again inside the cxx::bridge module, though compile-time assertions guarantee 186these are kept in sync. This is different from [bindgen] and [cbindgen] where 187function signatures are typed by a human once and the tool consumes them in one 188language and emits them in the other language. 189 190[bindgen]: https://github.com/rust-lang/rust-bindgen 191[cbindgen]: https://github.com/eqrion/cbindgen/ 192 193This is because CXX fills a somewhat different role. It is a lower level tool 194than bindgen or cbindgen in a sense; you can think of it as being a replacement 195for the concept of `extern "C"` signatures as we know them, rather than a 196replacement for a bindgen. It would be reasonable to build a higher level 197bindgen-like tool on top of CXX which consumes a C++ header and/or Rust module 198(and/or IDL like Thrift) as source of truth and generates the cxx::bridge, 199eliminating the repetition while leveraging the static analysis safety 200guarantees of CXX. 201 202But note in other ways CXX is higher level than the bindgens, with rich support 203for common standard library types. Frequently with bindgen when we are dealing 204with an idiomatic C++ API we would end up manually wrapping that API in C-style 205raw pointer functions, applying bindgen to get unsafe raw pointer Rust 206functions, and replicating the API again to expose those idiomatically in Rust. 207That's a much worse form of repetition because it is unsafe all the way through. 208 209By using a CXX bridge as the shared understanding between the languages, rather 210than `extern "C"` C-style signatures as the shared understanding, common FFI use 211cases become expressible using 100% safe code. 212 213It would also be reasonable to mix and match, using CXX bridge for the 95% of 214your FFI that is straightforward and doing the remaining few oddball signatures 215the old fashioned way with bindgen and cbindgen, if for some reason CXX's static 216restrictions get in the way. Please file an issue if you end up taking this 217approach so that we know what ways it would be worthwhile to make the tool more 218expressive. 219 220<br> 221 222## Cargo-based setup 223 224For builds that are orchestrated by Cargo, you will use a build script that runs 225CXX's C++ code generator and compiles the resulting C++ code along with any 226other C++ code for your crate. 227 228The canonical build script is as follows. The indicated line returns a 229[`cc::Build`] instance (from the usual widely used `cc` crate) on which you can 230set up any additional source files and compiler flags as normal. 231 232[`cc::Build`]: https://docs.rs/cc/1.0/cc/struct.Build.html 233 234```toml 235# Cargo.toml 236 237[build-dependencies] 238cxx-build = "1.0" 239``` 240 241```rust 242// build.rs 243 244fn main() { 245 cxx_build::bridge("src/main.rs") // returns a cc::Build 246 .file("src/demo.cc") 247 .flag_if_supported("-std=c++11") 248 .compile("cxxbridge-demo"); 249 250 println!("cargo:rerun-if-changed=src/main.rs"); 251 println!("cargo:rerun-if-changed=src/demo.cc"); 252 println!("cargo:rerun-if-changed=include/demo.h"); 253} 254``` 255 256<br> 257 258## Non-Cargo setup 259 260For use in non-Cargo builds like Bazel or Buck, CXX provides an alternate way of 261invoking the C++ code generator as a standalone command line tool. The tool is 262packaged as the `cxxbridge-cmd` crate on crates.io or can be built from the 263*gen/cmd* directory of this repo. 264 265```bash 266$ cargo install cxxbridge-cmd 267 268$ cxxbridge src/main.rs --header > path/to/mybridge.h 269$ cxxbridge src/main.rs > path/to/mybridge.cc 270``` 271 272<br> 273 274## Safety 275 276Be aware that the design of this library is intentionally restrictive and 277opinionated! It isn't a goal to be powerful enough to handle arbitrary 278signatures in either language. Instead this project is about carving out a 279reasonably expressive set of functionality about which we can make useful safety 280guarantees today and maybe extend over time. You may find that it takes some 281practice to use CXX bridge effectively as it won't work in all the ways that you 282are used to. 283 284Some of the considerations that go into ensuring safety are: 285 286- By design, our paired code generators work together to control both sides of 287 the FFI boundary. Ordinarily in Rust writing your own `extern "C"` blocks is 288 unsafe because the Rust compiler has no way to know whether the signatures 289 you've written actually match the signatures implemented in the other 290 language. With CXX we achieve that visibility and know what's on the other 291 side. 292 293- Our static analysis detects and prevents passing types by value that shouldn't 294 be passed by value from C++ to Rust, for example because they may contain 295 internal pointers that would be screwed up by Rust's move behavior. 296 297- To many people's surprise, it is possible to have a struct in Rust and a 298 struct in C++ with exactly the same layout / fields / alignment / everything, 299 and still not the same ABI when passed by value. This is a longstanding 300 bindgen bug that leads to segfaults in absolutely correct-looking code 301 ([rust-lang/rust-bindgen#778]). CXX knows about this and can insert the 302 necessary zero-cost workaround transparently where needed, so go ahead and 303 pass your structs by value without worries. This is made possible by owning 304 both sides of the boundary rather than just one. 305 306- Template instantiations: for example in order to expose a UniquePtr\<T\> type 307 in Rust backed by a real C++ unique\_ptr, we have a way of using a Rust trait 308 to connect the behavior back to the template instantiations performed by the 309 other language. 310 311[rust-lang/rust-bindgen#778]: https://github.com/rust-lang/rust-bindgen/issues/778 312 313<br> 314 315## Builtin types 316 317In addition to all the primitive types (i32 <=> int32_t), the following 318common types may be used in the fields of shared structs and the arguments and 319returns of functions. 320 321<table> 322<tr><th>name in Rust</th><th>name in C++</th><th>restrictions</th></tr> 323<tr><td>String</td><td>rust::String</td><td></td></tr> 324<tr><td>&str</td><td>rust::Str</td><td></td></tr> 325<tr><td>&[T]</td><td>rust::Slice<const T></td><td><sup><i>cannot hold opaque C++ type</i></sup></td></tr> 326<tr><td>&mut [T]</td><td>rust::Slice<T></td><td><sup><i>cannot hold opaque C++ type</i></sup></td></tr> 327<tr><td><a href="https://docs.rs/cxx/1.0/cxx/struct.CxxString.html">CxxString</a></td><td>std::string</td><td><sup><i>cannot be passed by value</i></sup></td></tr> 328<tr><td>Box<T></td><td>rust::Box<T></td><td><sup><i>cannot hold opaque C++ type</i></sup></td></tr> 329<tr><td><a href="https://docs.rs/cxx/1.0/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> 330<tr><td><a href="https://docs.rs/cxx/1.0/cxx/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> 331<tr><td>[T; N]</td><td>std::array<T, N></td><td><sup><i>cannot hold opaque C++ type</i></sup></td></tr> 332<tr><td>Vec<T></td><td>rust::Vec<T></td><td><sup><i>cannot hold opaque C++ type</i></sup></td></tr> 333<tr><td><a href="https://docs.rs/cxx/1.0/cxx/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> 334<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> 335<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> 336<tr><td>Result<T></td><td>throw/catch</td><td><sup><i>allowed as return type only</i></sup></td></tr> 337</table> 338 339The C++ API of the `rust` namespace is defined by the *include/cxx.h* file in 340this repo. You will need to include this header in your C++ code when working 341with those types. 342 343The following types are intended to be supported "soon" but are just not 344implemented yet. I don't expect any of these to be hard to make work but it's a 345matter of designing a nice API for each in its non-native language. 346 347<table> 348<tr><th>name in Rust</th><th>name in C++</th></tr> 349<tr><td>BTreeMap<K, V></td><td><sup><i>tbd</i></sup></td></tr> 350<tr><td>HashMap<K, V></td><td><sup><i>tbd</i></sup></td></tr> 351<tr><td>Arc<T></td><td><sup><i>tbd</i></sup></td></tr> 352<tr><td>Option<T></td><td><sup><i>tbd</i></sup></td></tr> 353<tr><td><sup><i>tbd</i></sup></td><td>std::map<K, V></td></tr> 354<tr><td><sup><i>tbd</i></sup></td><td>std::unordered_map<K, V></td></tr> 355</table> 356 357<br> 358 359## Remaining work 360 361This is still early days for CXX; I am releasing it as a minimum viable product 362to collect feedback on the direction and invite collaborators. Please check the 363open issues. 364 365Especially please report issues if you run into trouble building or linking any 366of this stuff. I'm sure there are ways to make the build aspects friendlier or 367more robust. 368 369Finally, I know more about Rust library design than C++ library design so I 370would appreciate help making the C++ APIs in this project more idiomatic where 371anyone has suggestions. 372 373<br> 374 375#### License 376 377<sup> 378Licensed under either of <a href="LICENSE-APACHE">Apache License, Version 3792.0</a> or <a href="LICENSE-MIT">MIT license</a> at your option. 380</sup> 381 382<br> 383 384<sub> 385Unless you explicitly state otherwise, any contribution intentionally submitted 386for inclusion in this project by you, as defined in the Apache-2.0 license, 387shall be dual licensed as above, without any additional terms or conditions. 388</sub> 389
README_zh.md
1CXX — Rust和C++之间的安全FFI 2========================================= 3 4[<img alt="github" src="https://img.shields.io/badge/github-dtolnay/CXX-8da0cb?style=for-the-badge&labelColor=555555&logo=github" height="20">](https://github.com/dtolnay/CXX) 5[<img alt="crates.io" src="https://img.shields.io/crates/v/CXX.svg?style=for-the-badge&color=fc8d62&logo=rust" height="20">](https://crates.io/crates/CXX) 6[<img alt="docs.rs" src="https://img.shields.io/badge/docs.rs-CXX-66c2a5?style=for-the-badge&labelColor=555555&logo=docs.rs" height="20">](https://docs.rs/cxx) 7[<img alt="build status" src="https://img.shields.io/github/actions/workflow/status/dtolnay/CXX/ci.yml" height="20">](https://github.com/dtolnay/CXX) 8 9 10## 引入背景 11 12 13CXX工具提供了一种安全的互相调用机制,可以实现rust和C++的互相调用。 14 15CXX通过FFI(Foreign Function Interface)和函数签名的形式来实现接口和类型声明,并对类型和函数签名进行静态分析,以维护Rust和C++的不变量和要求。 16 17<br> 18 19## CXX工具在OH上的使用指导 20 21### C++调用Rust接口 22 231. 在Rust侧文件lib.rs里mod ffi写清楚需要调用的C++接口,并将接口包含在extern "Rust"里面,暴露给C++侧使用。 24 25 ```rust 26 //! #[cxx::bridge] 27 #[cxx::bridge] 28 mod ffi{ 29 #![allow(dead_code)] 30 #[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] 31 struct Shared { 32 z: usize, 33 } 34 extern "Rust"{ 35 fn print_message_in_rust(); 36 fn r_return_primitive() -> usize; 37 fn r_return_shared() -> Shared; 38 fn r_return_rust_string() -> String; 39 fn r_return_sum(_: usize, _: usize) -> usize; 40 } 41 } 42 43 fn print_message_in_rust(){ 44 println!("Here is a test for cpp call Rust."); 45 } 46 fn r_return_shared() -> ffi::Shared { 47 println!("Here is a message from Rust,test for ffi::Shared:"); 48 ffi::Shared { z: 1996 } 49 } 50 fn r_return_primitive() -> usize { 51 println!("Here is a message from Rust,test for usize:"); 52 1997 53 } 54 fn r_return_rust_string() -> String { 55 println!("Here is a message from Rust,test for String"); 56 "Hello World!".to_owned() 57 } 58 fn r_return_sum(n1: usize, n2: usize) -> usize { 59 println!("Here is a message from Rust,test for {} + {} is:",n1 ,n2); 60 n1 + n2 61 } 62 63 ``` 64 652. C++侧将cxx工具转换出来的lib.rs.h包含进来,就可以使用C++侧的接口。 66 67 ```c++ 68 #include <iostream> 69 #include "build/rust/tests/test_cxx/src/lib.rs.h" 70 71 int main(int argc, const char* argv[]) 72 { 73 int a = 2021; 74 int b = 4; 75 print_message_in_rust(); 76 std::cout << r_return_primitive() << std::endl; 77 std::cout << r_return_shared().z << std::endl; 78 std::cout << std::string(r_return_rust_string()) << std::endl; 79 std::cout << r_return_sum(a, b) << std::endl; 80 return 0; 81 } 82 ``` 83 843. 添加构建文件BUILD.gn。rust_cxx底层调用CXX工具将lib.rs文件转换成lib.rs.h和lib.rs.cc文件,ohos_rust_static_ffi实现Rust侧源码的编译,ohos_executable实现C++侧代码的编译。 85 86 ``` 87 import("//build/ohos.gni") 88 import("//build/templates/rust/rust_cxx.gni") 89 90 rust_cxx("test_cxx_exe_gen") { 91 sources = [ "src/lib.rs" ] 92 } 93 94 ohos_rust_static_ffi("test_cxx_examp_rust") { 95 sources = [ "src/lib.rs" ] 96 deps = [ "//build/rust:cxx_rustdeps" ] 97 } 98 99 ohos_executable("test_cxx_exe") { 100 sources = [ "main.cpp" ] 101 sources += get_target_outputs(":test_cxx_exe_gen") 102 103 include_dirs = [ "${target_gen_dir}" ] 104 deps = [ 105 ":test_cxx_examp_rust", 106 ":test_cxx_exe_gen", 107 "//build/rust:cxx_cppdeps", 108 ] 109 } 110 ``` 111 112**调测验证** 113 114 115 116### Rust调用C++ 117 1181. 添加头文件client_blobstore.h。 119 120 ```c++ 121 #ifndef BUILD_RUST_TESTS_CLIENT_BLOBSTORE_H 122 #define BUILD_RUST_TESTS_CLIENT_BLOBSTORE_H 123 #include <memory> 124 #include "third_party/rust/cxx/include/cxx.h" 125 126 namespace nsp_org { 127 namespace nsp_blobstore { 128 struct MultiBufs; 129 struct Metadata_Blob; 130 131 class client_blobstore { 132 public: 133 client_blobstore(); 134 uint64_t put_buf(MultiBufs &buf) const; 135 void add_tag(uint64_t blobid, rust::Str add_tag) const; 136 Metadata_Blob get_metadata(uint64_t blobid) const; 137 138 private: 139 class impl; 140 std::shared_ptr<impl> impl; 141 }; 142 143 std::unique_ptr<client_blobstore> blobstore_client_new(); 144 } // namespace nsp_blobstore 145 } // namespace nsp_org 146 #endif 147 ``` 148 1492. 添加cpp文件client_blobstore.cpp。 150 151 ```c++ 152 #include <algorithm> 153 #include <functional> 154 #include <set> 155 #include <string> 156 #include <unordered_map> 157 #include "src/main.rs.h" 158 #include "build/rust/tests/test_cxx_rust/include/client_blobstore.h" 159 160 namespace nsp_org { 161 namespace nsp_blobstore { 162 // Toy implementation of an in-memory nsp_blobstore. 163 // 164 // In reality the implementation of client_blobstore could be a large complex C++ 165 // library. 166 class client_blobstore::impl { 167 friend client_blobstore; 168 using Blob = struct { 169 std::string data; 170 std::set<std::string> tags; 171 }; 172 std::unordered_map<uint64_t, Blob> blobs; 173 }; 174 175 client_blobstore::client_blobstore() : impl(new class client_blobstore::impl) {} 176 177 // Upload a new blob and return a blobid that serves as a handle to the blob. 178 uint64_t client_blobstore::put_buf(MultiBufs &buf) const 179 { 180 std::string contents; 181 182 // Traverse the caller's res_chunk iterator. 183 // 184 // In reality there might be sophisticated batching of chunks and/or parallel 185 // upload implemented by the nsp_blobstore's C++ client. 186 while (true) { 187 auto res_chunk = next_chunk(buf); 188 if (res_chunk.size() == 0) { 189 break; 190 } 191 contents.append(reinterpret_cast<const char *>(res_chunk.data()), res_chunk.size()); 192 } 193 194 // Insert into map and provide caller the handle. 195 auto res = std::hash<std::string> {} (contents); 196 impl->blobs[res] = {std::move(contents), {}}; 197 return res; 198 } 199 200 // Add add_tag to an existing blob. 201 void client_blobstore::add_tag(uint64_t blobid, rust::Str add_tag) const 202 { 203 impl->blobs[blobid].tags.emplace(add_tag); 204 } 205 206 // Retrieve get_metadata about a blob. 207 Metadata_Blob client_blobstore::get_metadata(uint64_t blobid) const 208 { 209 Metadata_Blob get_metadata {}; 210 auto blob = impl->blobs.find(blobid); 211 if (blob != impl->blobs.end()) { 212 get_metadata.size = blob->second.data.size(); 213 std::for_each(blob->second.tags.cbegin(), blob->second.tags.cend(), 214 [&](auto &t) { get_metadata.tags.emplace_back(t); }); 215 } 216 return get_metadata; 217 } 218 219 std::unique_ptr<client_blobstore> blobstore_client_new() 220 { 221 return std::make_unique<client_blobstore>(); 222 } 223 } // namespace nsp_blobstore 224 } // namespace nsp_org 225 226 ``` 227 2283. main.rs文件,在main.rs文件的ffi里面,通过宏include!将头文件client_blobstore.h引入进来,从而在Rust的main函数里面就可以通过ffi的方式调用C++的接口。 229 230 ```rust 231 //! test_cxx_rust 232 #[cxx::bridge(namespace = "nsp_org::nsp_blobstore")] 233 mod ffi { 234 // Shared structs with fields visible to both languages. 235 struct Metadata_Blob { 236 size: usize, 237 tags: Vec<String>, 238 } 239 240 // Rust types and signatures exposed to C++. 241 extern "Rust" { 242 type MultiBufs; 243 244 fn next_chunk(buf: &mut MultiBufs) -> &[u8]; 245 } 246 247 // C++ types and signatures exposed to Rust. 248 unsafe extern "C++" { 249 include!("build/rust/tests/test_cxx_rust/include/client_blobstore.h"); 250 251 type client_blobstore; 252 253 fn blobstore_client_new() -> UniquePtr<client_blobstore>; 254 fn put_buf(&self, parts: &mut MultiBufs) -> u64; 255 fn add_tag(&self, blobid: u64, add_tag: &str); 256 fn get_metadata(&self, blobid: u64) -> Metadata_Blob; 257 } 258 } 259 260 // An iterator over contiguous chunks of a discontiguous file object. 261 // 262 // Toy implementation uses a Vec<Vec<u8>> but in reality this might be iterating 263 // over some more complex Rust data structure like a rope, or maybe loading 264 // chunks lazily from somewhere. 265 /// pub struct MultiBufs 266 pub struct MultiBufs { 267 chunks: Vec<Vec<u8>>, 268 pos: usize, 269 } 270 /// pub fn next_chunk 271 pub fn next_chunk(buf: &mut MultiBufs) -> &[u8] { 272 let next = buf.chunks.get(buf.pos); 273 buf.pos += 1; 274 next.map_or(&[], Vec::as_slice) 275 } 276 277 /// fn main() 278 fn main() { 279 let client = ffi::blobstore_client_new(); 280 281 // Upload a blob. 282 let chunks = vec![b"fearless".to_vec(), b"concurrency".to_vec()]; 283 let mut buf = MultiBufs { chunks, pos: 0 }; 284 let blobid = client.put_buf(&mut buf); 285 println!("This is a test for Rust call cpp:"); 286 println!("blobid = {}", blobid); 287 288 // Add a add_tag. 289 client.add_tag(blobid, "rust"); 290 291 // Read back the tags. 292 let get_metadata = client.get_metadata(blobid); 293 println!("tags = {:?}", get_metadata.tags); 294 } 295 ``` 296 2974. 添加构建文件BUILD.gn。使用CXX将main.rs转换成lib.rs.h和lib.rs.cc,同时将产物作为test_cxx_rust_staticlib的源码,编译Rust源码main.rs并将test_cxx_rust_staticlib依赖进来。 298 299 ``` 300 import("//build/ohos.gni") 301 302 rust_cxx("test_cxx_rust_gen") { 303 sources = [ "src/main.rs" ] 304 } 305 306 ohos_static_library("test_cxx_rust_staticlib") { 307 sources = [ "src/client_blobstore.cpp" ] 308 sources += get_target_outputs(":test_cxx_rust_gen") 309 include_dirs = [ 310 "${target_gen_dir}", 311 "//third_party/rust/cxx/v1/crate/include", 312 "include", 313 ] 314 deps = [ 315 ":test_cxx_rust_gen", 316 "//build/rust:cxx_cppdeps", 317 ] 318 } 319 320 ohos_rust_executable("test_cxx_rust") { 321 sources = [ "src/main.rs" ] 322 deps = [ 323 ":test_cxx_rust_staticlib", 324 "//build/rust:cxx_rustdeps", 325 ] 326 } 327 ``` 328 329**调测验证** 330 331 332<br> 333 334 335 336## 与bindgen的对比 337 338bindgen主要用来实现rust代码对c接口的单向调用;CXX工具可以实现rust和C++的互相调用。 339 340<br> 341 342## 基于cargo的构建 343 344对于由Cargo的构建,需要使用一个构建脚本来运行CXX的C++代码生成器。 345 346典型的构建脚本如下: 347 348[`cc::Build`]: https://docs.rs/cc/1.0/cc/struct.Build.html 349 350```toml 351# Cargo.toml 352 353[build-dependencies] 354CXX-build = "1.0" 355``` 356 357```rust 358// build.rs 359 360fn main() { 361 CXX_build::bridge("src/main.rs") // returns a cc::Build 362 .file("src/demo.cc") 363 .flag_if_supported("-std=C++11") 364 .compile("cxxbridge-demo"); 365 366 println!("cargo:rerun-if-changed=src/main.rs"); 367 println!("cargo:rerun-if-changed=src/demo.cc"); 368 println!("cargo:rerun-if-changed=include/demo.h"); 369} 370``` 371 372<br> 373 374## 基于非cargo的构建 375 376对于在非Cargo构建中的使用,如Bazel或Buck,CXX提供了另一种方式产生C++侧的头文件和源代码文件,作为一个独立的命令行工具使用。 377 378```bash 379$ cargo install cxxbridge-cmd 380$ cxxbridge src/main.rs --header > path/to/mybridge.h 381$ cxxbridge src/main.rs > path/to/mybridge.cc 382``` 383 384<br> 385 386 387## 内置类型 388 389除了所有的原生类型(i32 <=> int32_t)之外,还有以下常见类型可用于共享结构的字段以及函数的参数和返回值。 390 391<table> 392<tr><th>name in Rust</th><th>name in C++</th><th>restrictions</th></tr> 393<tr><td>String</td><td>rust::String</td><td></td></tr> 394<tr><td>&str</td><td>rust::Str</td><td></td></tr> 395<tr><td>&[T]</td><td>rust::Slice<const T></td><td><sup><i>cannot hold opaque C++ type</i></sup></td></tr> 396<tr><td>&mut [T]</td><td>rust::Slice<T></td><td><sup><i>cannot hold opaque C++ type</i></sup></td></tr> 397<tr><td><a href="https://docs.rs/cxx/1.0/CXX/struct.CXXString.html">CXXString</a></td><td>std::string</td><td><sup><i>cannot be passed by value</i></sup></td></tr> 398<tr><td>Box<T></td><td>rust::Box<T></td><td><sup><i>cannot hold opaque C++ type</i></sup></td></tr> 399<tr><td><a href="https://docs.rs/cxx/1.0/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> 400<tr><td><a href="https://docs.rs/cxx/1.0/CXX/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> 401<tr><td>[T; N]</td><td>std::array<T, N></td><td><sup><i>cannot hold opaque C++ type</i></sup></td></tr> 402<tr><td>Vec<T></td><td>rust::Vec<T></td><td><sup><i>cannot hold opaque C++ type</i></sup></td></tr> 403<tr><td><a href="https://docs.rs/cxx/1.0/CXX/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> 404<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> 405<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> 406<tr><td>Result<T></td><td>throw/catch</td><td><sup><i>allowed as return type only</i></sup></td></tr> 407</table> 408 409`rust`命名空间的C++ API是由*include/CXX.h*文件定义的。使用这些类型时种类的时候,需要C++代码中包含这个头文件。 410 411以下类型很快被支持,只是还没有实现。 412 413<table> 414<tr><th>name in Rust</th><th>name in C++</th></tr> 415<tr><td>BTreeMap<K, V></td><td><sup><i>tbd</i></sup></td></tr> 416<tr><td>HashMap<K, V></td><td><sup><i>tbd</i></sup></td></tr> 417<tr><td>Arc<T></td><td><sup><i>tbd</i></sup></td></tr> 418<tr><td>Option<T></td><td><sup><i>tbd</i></sup></td></tr> 419<tr><td><sup><i>tbd</i></sup></td><td>std::map<K, V></td></tr> 420<tr><td><sup><i>tbd</i></sup></td><td>std::unordered_map<K, V></td></tr> 421</table> 422 423<br> 424 425## 开发者贡献 426 427当前CXX工具还没有达到普遍使用阶段,在使用该工具的过程中有任何问题欢迎开发者在社区issue中反馈。 428 429<br> 430