C++ is complex, and autocxx
can't ingest everything.
First tip - use an IDE. Type annotation and autocompletion is incredibly helpful in an autocxx
context, where you may be dealing with UniquePtr<T>
and Option<&T>
and Pin<&mut T>
very often.
As you'll see, it's also essential when autocxx
can't produce bindings for some reason.
autocxx
can't generate bindings?This bit is important.
When you use autocxx
, you'll ask it to generate Rust bindings for C++ types or functions using generate!
directives.
If you ask to generate bindings for a specific function, and it can't: the build will fail.
If you ask to generate bindings for an entire type, autocxx
will generate bindings for as many methods as possible. For those methods where it can't generate bindings, it will instead generate some placeholder function or struct with documentation explaining what went wrong:
This is why it's crucial to use an IDE with autocxx
.
autocxx
has generated?Options:
cargo doc --document-private-items
.cargo expand
.autocxx
can't generate bindingsYour options are:
#[cxx::bridge]
bindings - see below.Usually, you can solve problems by writing a bit of additional C++ code. For example, supposing autocxx can't understand your type Sandwich<Ham>
. Instead it will give you a fairly useless opaque type such as Sandwich_Ham
. You can write additional C++ functions to unpack the opaque type into something useful:
const Ham& get_filling(const Sandwich<Ham>& ham_sandwich);
autocxx
uses cxx
underneath, and its build process will happily spot and process manually-crafted cxx::bridge
mods which you include in your Rust source code. A common pattern could be to use autocxx
to generate all the bindings possible, then hand-craft a cxx::bridge
mod for the remainder where autocxx
falls short.
To do this, you'll need to use the ability of one cxx::bridge mod to refer to types from another, for example:
autocxx::include_cpp! { #include "foo.h" safety!(unsafe_ffi) generate!("take_A") generate!("A") } #[cxx::bridge] mod ffi2 { unsafe extern "C++" { include!("foo.h"); type A = crate::ffi::A; fn give_A() -> UniquePtr<A>; // in practice, autocxx could happily do this } } fn main() { let a = ffi2::give_A(); assert_eq!(ffi::take_A(&a), autocxx::c_int(5)); }
In the example above, we're referring from manual bindings to automated bindings.
You can also do it the other way round using extern_cpp_opaque_type!
:
autocxx::include_cpp! { #hexathorpe include "input.h" safety!(unsafe_ffi) generate!("handle_a") generate!("create_a") extern_cpp_opaque_type!("A", ffi2::A) } #[cxx::bridge] pub mod ffi2 { unsafe extern "C++" { include!("input.h"); type A; } impl UniquePtr<A> {} } fn main() { let a = ffi::create_a(); ffi::handle_a(&a); }
autocxx
should nearly always successfully parse the C++ codebase and generate some APIs. It's reliant on bindgen
, but bindgen
is excellent and rarely bails out entirely.
If it does, you may be able to use the block!
macro.
We'd appreciate a minimized bug report of the troublesome code - see contributing.
You'll need to enable both:
Now you've read what can go wrong with autocxx
, and how to diagnose problems - the next step is to give it a try! Treat the rest of this manual as a reference.