cpp-with-rust
cpp-with-rust copied to clipboard
Using cxx to mix in Rust-code with a C++ application
Minimal application mixing C++ and Rust
This example uses cxx to generate bindings between C++ and Rust, and integrates the two parts through CMake.
It is basically an inverted version of cxx's demo code, using C++ for the entry point and a MultiBuf class, while implementing a simple blobstore-library in Rust.
How it works
In lib.rs we add bridge declarations for our Rust types:
#[cxx::bridge(namespace = "org::blobstore")]
mod ffi {
// Rust types and signatures exposed to C++.
extern "Rust" {
type BlobstoreClient;
fn new_blobstore_client() -> Box<BlobstoreClient>;
fn put(&mut self, parts: Pin<&mut MultiBuf>) -> u64;
...
}
}
fn new_blobstore_client() -> Box<BlobstoreClient> {
Box::new(BlobstoreClient { blobs: HashMap::new() })
}
struct BlobstoreClient {
blobs: HashMap<u64, Blob>,
}
impl BlobstoreClient {
fn put(&mut self, mut parts: Pin<&mut MultiBuf>) -> u64 {
...
}
}
In build.rs we add logic to generate C++ bridging code from the declarations:
fn main() {
cxx_build::bridge("src/lib.rs");
println!("cargo:rerun-if-changed=src/lib.rs");
}
In CMakeLists.txt we add a custom command to trigger the Rust build:
add_custom_command(
OUTPUT ${BLOBSTORE_BRIDGE_CPP} ${BLOBSTORE_LIB}
COMMAND cargo build --manifest-path ${BLOBSTORE_CARGO_MANIFEST}
...
)
In main.cpp we include the generated C++ header, construct Rust types, and call their methods:
#include "lib.rs.h"
int main() {
auto client = org::blobstore::new_blobstore_client();
...
const auto blobid = client->put(buf);
}
The application also consumes C++ types from Rust (MultiBuf
), and leverages shared types between the two
languages (BlobMetadata
).
To learn more about the bridging layer, check out cxx's documentation.
Building and running the code
git clone [email protected]:paandahl/cpp-with-rust.git
mkdir cpp-with-rust/build
cd cpp-with-rust/build
cmake ..
cmake --build .
./cpp_with_rust
NOTE: If you are using Windows, run these commands in the Developer PowerShell for VS.
Technical notes
- As opposed to the original
cxx demo,
build.rs
only generates the C++ bridging code, without compiling it. Instead, we pass it in to the CMake build by referencing it inadd_executable()
. - For simplicity, this example always builds the Rust
code in debug mode.
See here
for suggested changes to adhere to the specified
CMAKE_BUILD_TYPE
, and moving the cargo output to within the CMake build tree.
License
The code is available under the MIT license.