Workflow

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. VSCode autocompletion of autocxx APIs

As you'll see, it's also essential when autocxx can't produce bindings for some reason.

What if 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:

VSCode showing an error for an API where autocxx couldn't generate bindings

This is why it's crucial to use an IDE with autocxx.

How can I see what bindings autocxx has generated?

Options:

  • Use an IDE. (Did we mention, you should use an IDE?)
  • Run cargo doc --document-private-items.
  • Use cargo expand.

How to work around cases where autocxx can't generate bindings

Your options are:

  • Write extra C++ functions with simpler parameters or return types, and generate bindings to them, instead.
  • Write some manual #[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);

Mixing manual and automated bindings

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);
}

My build entirely failed

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.

Enabling autocompletion in a rust-analyzer IDE

You'll need to enable both:

  • Rust-analyzer: Proc Macro: Enable
  • Rust-analyzer: Experimental: Proc Attr Macros

Next steps

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.