### Testing the JSON example Source: https://github.com/dtolnay/cxx/blob/master/book/src/binding/slice.md Command-line execution of the JSON pretty-printing example. ```console $ echo '{"fearless":"concurrency"}' | cargo run Finished dev [unoptimized + debuginfo] target(s) in 0.02s Running `target/debug/example` { "fearless": "concurrency" } ``` -------------------------------- ### Install and run cxxbridge CLI Source: https://github.com/dtolnay/cxx/blob/master/book/src/build/bazel.md Install the cxxbridge-cmd crate and use it to generate C++ header and source files from a Rust bridge file. ```console $ cargo install cxxbridge-cmd $ cxxbridge src/bridge.rs --header > path/to/bridge.rs.h $ cxxbridge src/bridge.rs > path/to/bridge.rs.cc ``` -------------------------------- ### Install cxxbridge-cmd and run cxxbridge on src/main.rs Source: https://github.com/dtolnay/cxx/blob/master/book/src/tutorial.md Commands to install the standalone CXX C++ code generator and run it on src/main.rs to output generated code to stdout. ```console cxx-demo$ cargo install cxxbridge-cmd cxx-demo$ cxxbridge src/main.rs ``` -------------------------------- ### build.rs with C++14 Standard Source: https://github.com/dtolnay/cxx/blob/master/book/src/tutorial.md An example of configuring the build script to enable C++14 features like std::make_unique. ```rust # // build.rs # # fn main() { cxx_build::bridge("src/main.rs") .file("src/blobstore.cc") .std("c++14") .compile("cxx-demo"); # } ``` -------------------------------- ### Non-Cargo setup with cxxbridge-cmd Source: https://github.com/dtolnay/cxx/blob/master/README.md Non-Cargo setup: install the cxxbridge-cmd command-line tool and run it to generate the C++ header and source files from the Rust bridge definition. The --header flag produces the header file; without it, the tool outputs the C++ implementation file. ```bash $ cargo install cxxbridge-cmd $ cxxbridge src/main.rs --header > path/to/mybridge.h $ cxxbridge src/main.rs > path/to/mybridge.cc ``` -------------------------------- ### Install cargo-expand and expand the ffi module Source: https://github.com/dtolnay/cxx/blob/master/book/src/tutorial.md Commands to install cargo-expand and run cargo expand ::ffi to view the Rust code generated by the cxx::bridge procedural macro. ```console cxx-demo$ cargo install cargo-expand cxx-demo$ cargo expand ::ffi ``` -------------------------------- ### Example: Passing a slice from C++ to Rust Source: https://github.com/dtolnay/cxx/blob/master/book/src/binding/slice.md A complete example showing how to construct a rust::Slice in C++ from a vector and pass it to a Rust function that pretty-prints JSON. ```APIDOC ## Example: Passing a slice from C++ to Rust ### Description This example demonstrates constructing a rust::Slice in C++ from a vector of bytes read from stdin, then calling a Rust function to pretty-print JSON. ### Rust Side (src/main.rs) ```rust #![no_main] // main defined in C++ by main.cc use cxx::CxxString; use std::io::{self, Write}; use std::pin::Pin; #[cxx::bridge] mod ffi { extern "Rust" { fn prettify_json(input: &[u8], output: Pin<&mut CxxString>) -> Result<()>; } } struct WriteToCxxString<'a>(Pin<&'a mut CxxString>); impl<'a> Write for WriteToCxxString<'a> { fn write(&mut self, buf: &[u8]) -> io::Result { self.0.as_mut().push_bytes(buf); Ok(buf.len()) } fn flush(&mut self) -> io::Result<()> { Ok(()) } } fn prettify_json(input: &[u8], output: Pin<&mut CxxString>) -> serde_json::Result<()> { let writer = WriteToCxxString(output); let mut deserializer = serde_json::Deserializer::from_slice(input); let mut serializer = serde_json::Serializer::pretty(writer); serde_transcode::transcode(&mut deserializer, &mut serializer) } ``` ### C++ Side (src/main.cc) ```cpp #include "example/src/main.rs.h" #include #include #include #include int main() { // Read json from stdin. std::istreambuf_iterator begin{std::cin}, end; std::vector input{begin, end}; rust::Slice slice{input.data(), input.size()}; // Prettify using serde_json and serde_transcode. std::string output; prettify_json(slice, output); // Write to stdout. std::cout << output << std::endl; } ``` ### Testing ```console $ echo '{"fearless":"concurrency"}' | cargo run Finished dev [unoptimized + debuginfo] target(s) in 0.02s Running `target/debug/example` { "fearless": "concurrency" } ``` ``` -------------------------------- ### Configure BUILD.bazel for CXX Source: https://github.com/dtolnay/cxx/blob/master/book/src/build/bazel.md Example usage of the rust_cxx_bridge macro within a BUILD.bazel file to integrate Rust and C++ targets. ```python # demo/BUILD.bazel load("@rules_cc//cc:defs.bzl", "cc_library") load("@rules_rust//rust:defs.bzl", "rust_binary") load("//tools/bazel:rust_cxx_bridge.bzl", "rust_cxx_bridge") rust_binary( name = "demo", srcs = glob(["src/**/*.rs"]), deps = [ ":blobstore-sys", ":bridge", "//:cxx", ], ) rust_cxx_bridge( name = "bridge", src = "src/main.rs", deps = [":blobstore-include"], ) cc_library( name = "blobstore-sys", srcs = ["src/blobstore.cc"], deps = [ ":blobstore-include", ":bridge/include", ], ) cc_library( name = "blobstore-include", hdrs = ["include/blobstore.h"], deps = ["//:core"], ) ``` -------------------------------- ### rust::Str Usage Example Source: https://github.com/dtolnay/cxx/blob/master/book/src/binding/str.md A complete example showing how to pass string slices between Rust and C++ using rust::Str. ```rust // src/main.rs #[cxx::bridge] mod ffi { extern "Rust" { fn r(greeting: &str); } unsafe extern "C++" { include!("example/include/greeting.h"); fn c(greeting: &str); } } fn r(greeting: &str) { println!("{}", greeting); } fn main() { ffi::c("hello from Rust"); } ``` ```cpp // include/greeting.h #pragma once #include "example/src/main.rs.h" #include "rust/cxx.h" void c(rust::Str greeting); ``` ```cpp // src/greeting.cc #include "example/include/greeting.h" #include void c(rust::Str greeting) { std::cout << greeting << std::endl; r("hello from C++"); } ``` -------------------------------- ### Cargo-based setup with cxx_build::bridge Source: https://github.com/dtolnay/cxx/blob/master/README.md Cargo-based setup for CXX: add cxx-build as a build dependency and use a build script that invokes cxx_build::bridge on the Rust source file, adds any additional C++ source files, sets the C++ standard, and compiles the bridge. The bridge call returns a cc::Build instance for further configuration. The script also emits cargo:rerun-if-changed directives for the C++ files. ```toml # Cargo.toml [build-dependencies] cxx-build = "1.0" ``` ```rust // build.rs fn main() { cxx_build::bridge("src/main.rs") // returns a cc::Build .file("src/demo.cc") .std("c++11") .compile("cxxbridge-demo"); println!("cargo:rerun-if-changed=src/demo.cc"); println!("cargo:rerun-if-changed=include/demo.h"); } ``` -------------------------------- ### Include header with default crate name prefix Source: https://github.com/dtolnay/cxx/blob/master/book/src/build/cargo.md Shows how to include a C++ header from your own crate when using the default include path. The include path starts with the crate name, so a header at `path/to/header.h` is included as `yourcratename/path/to/header.h`. ```cpp #include "yourcratename/path/to/header.h" ``` -------------------------------- ### Passing ownership with rust::Box Source: https://github.com/dtolnay/cxx/blob/master/book/src/binding/box.md An example demonstrating how to pass ownership of a Rust-allocated File object to C++ and back to a Rust callback. ```rust // src/main.rs use std::io::Write; #[cxx::bridge] mod ffi { extern "Rust" { type File; } unsafe extern "C++" { include!("example/include/example.h"); fn f( callback: fn(Box, fst: &str, snd: &str), out: Box, ); } } pub struct File(std::fs::File); fn main() { let out = std::fs::File::create("example.log").unwrap(); ffi::f( |mut out, fst, snd| { let _ = write!(out.0, "{}{}\n", fst, snd); }, Box::new(File(out)), ); } ``` ```cpp // include/example.h #pragma once #include "example/src/main.rs.h" #include "rust/cxx.h" void f(rust::Fn, rust::Str, rust::Str)> callback, rust::Box out); ``` ```cpp // include/example.cc #include "example/include/example.h" void f(rust::Fn, rust::Str, rust::Str)> callback, rust::Box out) { callback(std::move(out), "fearless", "concurrency"); } ``` -------------------------------- ### CxxString example: Rust main.rs with C++ json.h and json.cc Source: https://github.com/dtolnay/cxx/blob/master/book/src/binding/cxxstring.md Complete example showing Rust code using CxxString through the let_cxx_string! macro and C++ implementation of a toy JSON type with std::variant. The Rust main.rs defines the bridge, loads config, and indexes into the object map with a CxxString key. The C++ header and source files define the json class and load_config function that returns a unique_ptr. ```rust // src/main.rs use cxx::let_cxx_string; #[cxx::bridge] mod ffi { unsafe extern "C++" { include!("example/include/json.h"); #[cxx_name = "json"] type Json; #[cxx_name = "object"] type Object; fn isNull(self: &Json) -> bool; fn isNumber(self: &Json) -> bool; fn isString(self: &Json) -> bool; fn isArray(self: &Json) -> bool; fn isObject(self: &Json) -> bool; fn getNumber(self: &Json) -> f64; fn getString(self: &Json) -> &CxxString; fn getArray(self: &Json) -> &CxxVector; fn getObject(self: &Json) -> &Object; #[cxx_name = "at"] fn get<'a>(self: &'a Object, key: &CxxString) -> &'a Json; fn load_config() -> UniquePtr; } } fn main() { let config = ffi::load_config(); let_cxx_string!(key = "name"); println!("{}", config.getObject().get(&key).getString()); } ``` ```cpp // include/json.h #pragma once #include #include #include #include #include class json final { public: static const json null; using number = double; using string = std::string; using array = std::vector; using object = std::map; json() noexcept = default; json(const json &) = default; json(json &&) = default; template json(T &&...value) : value(std::forward(value)...) {} bool isNull() const; bool isNumber() const; bool isString() const; bool isArray() const; bool isObject() const; number getNumber() const; const string &getString() const; const array &getArray() const; const object &getObject() const; private: std::variant value; }; using object = json::object; std::unique_ptr load_config(); ``` ```cpp // include/json.cc #include "example/include/json.h" #include #include const json json::null{}; bool json::isNull() const { return std::holds_alternative(value); } bool json::isNumber() const { return std::holds_alternative(value); } bool json::isString() const { return std::holds_alternative(value); } bool json::isArray() const { return std::holds_alternative(value); } bool json::isObject() const { return std::holds_alternative(value); } json::number json::getNumber() const { return std::get(value); } const json::string &json::getString() const { return std::get(value); } const json::array &json::getArray() const { return std::get(value); } const json::object &json::getObject() const { return std::get(value); } std::unique_ptr load_config() { return std::make_unique( std::in_place_type, std::initializer_list>{ {"name", "cxx-example"}, {"edition", 2021.}, {"repository", json::null}}); } ``` -------------------------------- ### rust::Str Source: https://github.com/dtolnay/cxx/blob/master/book/src/binding/str.md Documentation for the rust::Str class, including constructors, member functions, operators, and usage examples. ```APIDOC ## rust::Str ### Description Represents a borrowed UTF-8 string, analogous to `&str` in Rust. It is used as a function argument or return value in C++ when interfacing with Rust code. ### Constructors - `Str() noexcept` - Default constructor. - `Str(const Str &) noexcept` - Copy constructor. - `Str(const String &) noexcept` - Constructs from a `rust::String`. - `Str(const std::string &)` - Constructs from a `std::string`. Throws `std::invalid_argument` if not UTF-8. - `Str(const char *)` - Constructs from a null-terminated C string. Throws `std::invalid_argument` if not UTF-8. - `Str(const char *, size_t)` - Constructs from a byte buffer with explicit length. Throws `std::invalid_argument` if not UTF-8. ### Assignment Operators - `Str &operator=(const Str &) & noexcept` - Copy assignment. ### Conversion Operators - `explicit operator std::string() const` - Converts to `std::string`. - `explicit operator std::string_view() const` (C++17 or later) - Converts to `std::string_view`. ### Member Functions - `const char *data() const noexcept` - Returns a pointer to the underlying data. Note: no null terminator. - `size_t size() const noexcept` - Returns the length in bytes. - `size_t length() const noexcept` - Returns the length in bytes, same as `size()`. - `bool empty() const noexcept` - Returns `true` if the string is empty. - `const_iterator begin() const noexcept` - Returns an iterator to the beginning. - `const_iterator end() const noexcept` - Returns an iterator to the end. - `const_iterator cbegin() const noexcept` - Returns a const iterator to the beginning. - `const_iterator cend() const noexcept` - Returns a const iterator to the end. - `void swap(Str &) noexcept` - Swaps the contents with another `Str`. ### Comparison Operators - `bool operator==(const Str &) const noexcept` - Equality comparison. - `bool operator!=(const Str &) const noexcept` - Inequality comparison. - `bool operator<(const Str &) const noexcept` - Less-than comparison. - `bool operator<=(const Str &) const noexcept` - Less-than-or-equal comparison. - `bool operator>(const Str &) const noexcept` - Greater-than comparison. - `bool operator>=(const Str &) const noexcept` - Greater-than-or-equal comparison. ### Free Functions - `std::ostream &operator<<(std::ostream &, const Str &)` - Stream insertion operator for output. ### Notes - `rust::Str` behaves like `&str`; it is a borrow and C++ must be mindful of lifetimes. - Do not use `const rust::Str &`; use `rust::Str` by value. ### Restrictions - Allowed as function argument or return value. - Not supported in shared structs yet. - `&mut str` is not supported yet. ### Example ```cpp // include/greeting.h #pragma once #include "example/src/main.rs.h" #include "rust/cxx.h" void c(rust::Str greeting); ``` ```cpp // src/greeting.cc #include "example/include/greeting.h" #include void c(rust::Str greeting) { std::cout << greeting << std::endl; r("hello from C++"); } ``` ``` -------------------------------- ### Console output of cargo run for cxx-demo Source: https://github.com/dtolnay/cxx/blob/master/book/src/tutorial.md Shows the expected output when running the example with cargo run. The program compiles and runs, printing a blobid value. ```console cxx-demo$ cargo run Compiling cxx-demo v0.1.0 Finished dev [unoptimized + debuginfo] target(s) in 0.41s Running `target/debug/cxx-demo` blobid = 9851996977040795552 ``` -------------------------------- ### Example: Pretty-printing JSON using rust::Slice Source: https://github.com/dtolnay/cxx/blob/master/book/src/binding/slice.md A demonstration of passing data from C++ to Rust via rust::Slice to perform JSON pretty-printing. The Rust side uses serde_json and serde_transcode, while the C++ side reads from stdin. ```rust // src/main.rs #![no_main] // main defined in C++ by main.cc use cxx::CxxString; use std::io::{self, Write}; use std::pin::Pin; #[cxx::bridge] mod ffi { extern "Rust" { fn prettify_json(input: &[u8], output: Pin<&mut CxxString>) -> Result<()>; } } struct WriteToCxxString<'a>(Pin<&'a mut CxxString>); impl<'a> Write for WriteToCxxString<'a> { fn write(&mut self, buf: &[u8]) -> io::Result { self.0.as_mut().push_bytes(buf); Ok(buf.len()) } fn flush(&mut self) -> io::Result<()> { Ok(()) } } fn prettify_json(input: &[u8], output: Pin<&mut CxxString>) -> serde_json::Result<()> { let writer = WriteToCxxString(output); let mut deserializer = serde_json::Deserializer::from_slice(input); let mut serializer = serde_json::Serializer::pretty(writer); serde_transcode::transcode(&mut deserializer, &mut serializer) } ``` ```cpp // src/main.cc #include "example/src/main.rs.h" #include #include #include #include int main() { // Read json from stdin. std::istreambuf_iterator begin{std::cin}, end; std::vector input{begin, end}; rust::Slice slice{input.data(), input.size()}; // Prettify using serde_json and serde_transcode. std::string output; prettify_json(slice, output); // Write to stdout. std::cout << output << std::endl; } ``` -------------------------------- ### C++ implementation of new_blobstore_client (src/blobstore.cc) Source: https://github.com/dtolnay/cxx/blob/master/book/src/binding/uniqueptr.md Implements new_blobstore_client to return a std::make_unique(). Includes the header. ```cpp // src/blobstore.cc #include "example/include/blobstore.h" std::unique_ptr new_blobstore_client() { return std::make_unique(); } ``` -------------------------------- ### Basic build.rs Configuration Source: https://github.com/dtolnay/cxx/blob/master/book/src/tutorial.md A standard build script that invokes the cxx-build generator and specifies source files to compile. ```rust // build.rs fn main() { cxx_build::bridge("src/main.rs") .file("src/blobstore.cc") .compile("cxx-demo"); println!("cargo:rerun-if-changed=src/blobstore.cc"); println!("cargo:rerun-if-changed=include/blobstore.h"); } ``` -------------------------------- ### C++ Source File src/blobstore.cc Source: https://github.com/dtolnay/cxx/blob/master/book/src/tutorial.md Implements the BlobstoreClient constructor and the factory function defined in the header. ```cpp // src/blobstore.cc #include "cxx-demo/include/blobstore.h" BlobstoreClient::BlobstoreClient() {} std::unique_ptr new_blobstore_client() { return std::unique_ptr(new BlobstoreClient()); } ``` -------------------------------- ### C++ header for BlobstoreClient (include/blobstore.h) Source: https://github.com/dtolnay/cxx/blob/master/book/src/binding/uniqueptr.md Declares the BlobstoreClient class and the new_blobstore_client function returning std::unique_ptr. Includes for unique_ptr. ```cpp // include/blobstore.h #pragma once #include class BlobstoreClient; std::unique_ptr new_blobstore_client(); ``` -------------------------------- ### Canonical build.rs using cxx_build::bridge Source: https://github.com/dtolnay/cxx/blob/master/book/src/build/cargo.md The canonical build script for CXX. Calls `cxx_build::bridge("src/main.rs")` which returns a `cc::Build` instance, then adds a C++ source file, sets the C++ standard to C++11, and compiles the library. The `rerun-if-changed` lines are optional but recommended to avoid recompiling C++ when only non-C++ files change. ```rust // build.rs fn main() { cxx_build::bridge("src/main.rs") // returns a cc::Build .file("src/demo.cc") .std("c++11") .compile("cxxbridge-demo"); println!("cargo:rerun-if-changed=src/demo.cc"); println!("cargo:rerun-if-changed=include/demo.h"); } ``` -------------------------------- ### Example: passing rust::String by value in a shared struct and function return Source: https://github.com/dtolnay/cxx/blob/master/book/src/binding/string.md Complete example showing rust::String used as a function argument and return value across the FFI boundary. The Rust bridge declares a shared struct ConcatRequest with two String fields and an unsafe extern "C++" function concat; the C++ header declares the function and the implementation concatenates the fields by converting them to std::string because operator overloads are not yet available on rust::String. ```rust // src/main.rs #[cxx::bridge] mod ffi { struct ConcatRequest { fst: String, snd: String, } unsafe extern "C++" { include!("example/include/concat.h"); fn concat(r: ConcatRequest) -> String; } } fn main() { let concatenated = ffi::concat(ffi::ConcatRequest { fst: "fearless".to_owned(), snd: "concurrency".to_owned(), }); println!("concatenated: {:?}", concatenated); } ``` ```cpp // include/concat.h #pragma once #include "example/src/main.rs.h" #include "rust/cxx.h" rust::String concat(ConcatRequest r); ``` ```cpp // src/concat.cc #include "example/include/concat.h" rust::String concat(ConcatRequest r) { // The full suite of operator overloads hasn't been added // yet on rust::String, but we can get it done like this: return std::string(r.fst) + std::string(r.snd); } ``` -------------------------------- ### C++ header example/include/example.h Source: https://github.com/dtolnay/cxx/blob/master/book/src/binding/sharedptr.md Declares the Object class with constructor and destructor, and the create_shared_ptr function that returns a std::shared_ptr. This header is included by the Rust bridge. ```cpp // include/example.h #pragma once #include class Object { public: Object(); ~Object(); }; std::shared_ptr create_shared_ptr(); ``` -------------------------------- ### C++ implementation src/example.cc Source: https://github.com/dtolnay/cxx/blob/master/book/src/binding/sharedptr.md Implements the Object constructor and destructor with console output, and create_shared_ptr returning a std::make_shared. This shows the lifecycle messages printed when the shared_ptr is created and destroyed. ```cpp // src/example.cc #include "example/include/example.h" #include Object::Object() { std::cout << "construct Object" << std::endl; } Object::~Object() { std::cout << "~Object" << std::endl; } std::shared_ptr create_shared_ptr() { return std::make_shared(); } ``` -------------------------------- ### Enum with repr(i32) and mixed discriminants Source: https://github.com/dtolnay/cxx/blob/master/book/src/shared.md Shows a CXX bridge enum with a repr attribute to force a specific integer representation. Variants without explicit discriminants get the previous discriminant plus one, and the first variant defaults to zero. ```rust #[cxx::bridge] mod ffi { #[repr(i32)] enum Enum { Zero, One, Five = 5, Six, } } ``` -------------------------------- ### Include header with custom include_prefix Source: https://github.com/dtolnay/cxx/blob/master/book/src/build/cargo.md Shows the include path after setting `CFG.include_prefix` to `"my/project"`. The header at `path/to/header.h` is now included as `my/project/path/to/header.h`. ```cpp #include "my/project/path/to/header.h" ``` -------------------------------- ### Explicit UniquePtr instantiation with impl UniquePtr {} Source: https://github.com/dtolnay/cxx/blob/master/book/src/extern-c++.md Adds an explicit template instantiation `impl UniquePtr {}` inside the bridge module that defines A but does not otherwise use UniquePtr. This requests the specific template instantiation at that location in the Rust crate hierarchy, resolving the trait error from the previous example. ```rust #[cxx::bridge] mod ffi1 { extern "C++" { include!("path/to/header.h"); type A; type B; fn get_b() -> UniquePtr; } impl UniquePtr {} // explicit instantiation } ``` -------------------------------- ### Unify extern type across bridges with `type Demo = crate::file1::ffi::Demo` Source: https://github.com/dtolnay/cxx/blob/master/book/src/extern-c++.md Two bridges in different files (possibly different crates) both use the same C++ type `example::Demo`. `file2.rs` aliases its `Demo` to `crate::file1::ffi::Demo` so the two Rust types are identical, allowing a `Demo` returned by `file1::ffi::create_demo` to be passed to `file2::ffi::take_ref_demo`. ```rust // file1.rs #[cxx::bridge(namespace = "example")] pub mod ffi { unsafe extern "C++" { type Demo; fn create_demo() -> UniquePtr; } } ``` ```rust // file2.rs #[cxx::bridge(namespace = "example")] pub mod ffi { unsafe extern "C++" { type Demo = crate::file1::ffi::Demo; fn take_ref_demo(demo: &Demo); } } ``` -------------------------------- ### Exporting system library header directories Source: https://github.com/dtolnay/cxx/blob/master/book/src/build/cargo.md Use CFG.exported_header_dirs to expose system library include paths, such as those from pkg-config, to downstream crates. ```rust // build.rs use cxx_build::CFG; use std::path::PathBuf; fn main() { let python3 = pkg_config::probe_library("python3").unwrap(); let python_include_paths = python3.include_paths.iter().map(PathBuf::as_path); CFG.exported_header_dirs.extend(python_include_paths); cxx_build::bridge("src/bridge.rs").compile("demo"); } ``` -------------------------------- ### Pass char* argv[] from Rust to C++ using raw pointers Source: https://github.com/dtolnay/cxx/blob/master/book/src/binding/rawptr.md Complete example of passing a C-style argv array from Rust to C++ via raw pointers. The C++ header declares parseArgs, the C++ source prints the arguments, and the Rust main converts OsString arguments to CString, builds a null-terminated argv vector, and calls the unsafe extern function. The C function must not retain the pointers after the call. ```cpp // include/args.h #pragma once void parseArgs(int argc, char *argv[]); ``` ```cpp // src/args.cc #include "example/include/args.h" #include void parseArgs(int argc, char *argv[]) { std::cout << argc << std::endl; for (int i = 0; i < argc; i++) { std::cout << '"' << argv[i] << '"' << std::endl; } } ``` ```rust // src/main.rs use std::env; use std::ffi::CString; use std::os::raw::c_char; use std::os::unix::ffi::OsStrExt; use std::ptr; #[cxx::bridge] mod ffi { extern "C++" { include!("example/include/args.h"); unsafe fn parseArgs(argc: i32, argv: *mut *mut c_char); } } fn main() { // Convert from OsString to nul-terminated CString, truncating each argument // at the first inner nul byte if present. let args: Vec = env::args_os() .map(|os_str| { let bytes = os_str.as_bytes(); CString::new(bytes).unwrap_or_else(|nul_error| { let nul_position = nul_error.nul_position(); let mut bytes = nul_error.into_vec(); bytes.truncate(nul_position); CString::new(bytes).unwrap() }) }) .collect(); // Convert from Vec of owned strings to Vec<*mut c_char> of // borrowed string pointers. // // Once extern type stabilizes (https://github.com/rust-lang/rust/issues/43467) // and https://internals.rust-lang.org/t/pre-rfc-make-cstr-a-thin-pointer/6258 // is implemented, and CStr pointers become thin, we can sidestep this step // by accumulating the args as Vec> up front, then simply casting // from *mut [Box] to *mut [*mut CStr] to *mut *mut c_char. let argc = args.len(); let mut argv: Vec<*mut c_char> = Vec::with_capacity(argc + 1); for arg in &args { argv.push(arg.as_ptr() as *mut c_char); } argv.push(ptr::null_mut()); // Nul terminator. unsafe { ffi::parseArgs(argc as i32, argv.as_mut_ptr()); } // The CStrings go out of scope here. C function must not have held on to // the pointers beyond this point. } ``` -------------------------------- ### C++: Implementation of BlobstoreClient in blobstore.cc Source: https://github.com/dtolnay/cxx/blob/master/book/src/tutorial.md Implements the BlobstoreClient methods, including put, tag, and metadata. The metadata method constructs a BlobMetadata struct and populates its size and tags fields from the internal blob storage. ```cpp // src/blobstore.cc #include "cxx-demo/include/blobstore.h" #include "cxx-demo/src/main.rs.h" #include #include #include #include #include // Toy implementation of an in-memory blobstore. // // In reality the implementation of BlobstoreClient could be a large // complex C++ library. class BlobstoreClient::impl { friend BlobstoreClient; using Blob = struct { std::string data; std::set tags; }; std::unordered_map blobs; }; BlobstoreClient::BlobstoreClient() : impl(new class BlobstoreClient::impl) {} ... ...// Upload a new blob and return a blobid that serves as a handle to the blob. ...uint64_t BlobstoreClient::put(MultiBuf &buf) const { ... // Traverse the caller's chunk iterator. ... std::string contents; ... while (true) { ... auto chunk = next_chunk(buf); ... if (chunk.size() == 0) { ... break; ... } ... contents.append(reinterpret_cast(chunk.data()), chunk.size()); ... } ... ... // Insert into map and provide caller the handle. ... auto blobid = std::hash{}(contents); ... impl->blobs[blobid] = {std::move(contents), {}}; ... return blobid; ...} // Add tag to an existing blob. void BlobstoreClient::tag(uint64_t blobid, rust::Str tag) const { impl->blobs[blobid].tags.emplace(tag); } // Retrieve metadata about a blob. BlobMetadata BlobstoreClient::metadata(uint64_t blobid) const { BlobMetadata metadata{}; auto blob = impl->blobs.find(blobid); if (blob != impl->blobs.end()) { metadata.size = blob->second.data.size(); std::for_each(blob->second.tags.cbegin(), blob->second.tags.cend(), [&](auto &t) { metadata.tags.emplace_back(t); }); } return metadata; } ... ...std::unique_ptr new_blobstore_client() { ... return std::make_unique(); ...} ``` -------------------------------- ### Console: Running the demo with cargo run Source: https://github.com/dtolnay/cxx/blob/master/book/src/tutorial.md Shows the expected output when running the demo with cargo run. The output includes a blobid and the tags list containing "rust". ```console cxx-demo$ cargo run Running `target/debug/cxx-demo` blobid = 9851996977040795552 tags = ["rust"] ``` -------------------------------- ### Rearranging exported header layouts Source: https://github.com/dtolnay/cxx/blob/master/book/src/build/cargo.md Demonstrates how to copy local headers into a specific directory structure within OUT_DIR and export that directory to downstream crates. ```rust // build.rs use cxx_build::CFG; use std::path::Path; use std::{env, fs}; fn main() { let out_dir = env::var_os("OUT_DIR").unwrap(); let headers = Path::new(&out_dir).join("headers"); CFG.exported_header_dirs.push(&headers); // We contain `include/myheader.h` locally, but // downstream will use `#include "foo/v1/public.h"` let foo = headers.join("foo").join("v1"); fs::create_dir_all(&foo).unwrap(); fs::copy("include/myheader.h", foo.join("public.h")).unwrap(); cxx_build::bridge("src/bridge.rs").compile("demo"); } ``` -------------------------------- ### Include header from a dependency crate Source: https://github.com/dtolnay/cxx/blob/master/book/src/build/cargo.md Shows how to include a header from a direct dependency. Use the dependency's crate name (or its include_prefix if changed) followed by the relative path. Note: cross-crate imports only work for direct dependencies, and the dependency must have a `links` key in its Cargo.toml. ```cpp #include "dependencycratename/path/to/their/header.h` ``` -------------------------------- ### Generate C++ bindings with cxxbridge Source: https://github.com/dtolnay/cxx/blob/master/book/src/build/other.md Use the cxxbridge command to generate the C++ bindings code from a Rust bridge source file. The first command produces the header file, and the second produces the implementation file. The cxxbridge tool is available as the cxxbridge-cmd crate or can be built from the bridge/cmd directory of the CXX repository. ```console $ cxxbridge src/bridge.rs --header > path/to/bridge.rs.h $ cxxbridge src/bridge.rs > path/to/bridge.rs.cc ``` -------------------------------- ### Add cxx and cxx-build dependencies to Cargo.toml Source: https://github.com/dtolnay/cxx/blob/master/README.md Add the cxx and cxx-build crates to your Cargo.toml. The cxx crate provides the runtime and macros, while cxx-build is used as a build dependency to generate the FFI bindings. ```toml [dependencies] cxx = "1.0" [build-dependencies] cxx-build = "1.0" ```