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.
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.
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.
- 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.
The code is available under the MIT license.