| {{#title Other build systems — Rust ♡ C++}} |
| # Some other build system |
| |
| You will need to achieve at least these three things: |
| |
| - Produce the CXX-generated C++ bindings code. |
| - Compile the generated C++ code. |
| - Link the resulting objects together with your other C++ and Rust objects. |
| |
| *Not all build systems are created equal. If you're hoping to use a build system |
| from the '90s, especially if you're hoping to overlaying the limitations of 2 or |
| more build systems (like automake+cargo) and expect to solve them |
| simultaneously, then be mindful that your expectations are set accordingly and |
| seek sympathy from those who have imposed the same approach on themselves.* |
| |
| ### Producing the generated code |
| |
| CXX's Rust code generation automatically happens when the `#[cxx::bridge]` |
| procedural macro is expanded during the normal Rust compilation process, so no |
| special build steps are required there. |
| |
| But the C++ side of the bindings needs to be generated. Your options are: |
| |
| - Use the `cxxbridge` command, which is a standalone command line interface to |
| the CXX C++ code generator. Wire up your build system to compile and invoke |
| this tool. |
| |
| ```console |
| $ cxxbridge src/bridge.rs --header > path/to/bridge.rs.h |
| $ cxxbridge src/bridge.rs > path/to/bridge.rs.cc |
| ``` |
| |
| It's packaged as the `cxxbridge-cmd` crate on crates.io or can be built from |
| the *gen/cmd/* directory of the CXX GitHub repo. |
| |
| - Or, build your own code generator frontend on top of the [cxx-gen] crate. This |
| is currently unofficial and unsupported. |
| |
| [cxx-gen]: https://docs.rs/cxx-gen |
| |
| ### Compiling C++ |
| |
| However you like. We can provide no guidance. |
| |
| ### Linking the C++ and Rust together |
| |
| When linking a binary which contains mixed Rust and C++ code, you will have to |
| choose between using the Rust toolchain (`rustc`) or the C++ toolchain which you |
| may already have extensively tuned. |
| |
| The generated C++ code and the Rust code generated by the procedural macro both |
| depend on each other. Simple examples may only require one or the other, but in |
| general your linking will need to handle both directions. For some linkers, such |
| as llvm-ld, this is not a problem at all. For others, such as GNU ld, flags like |
| `--start-lib`/`--end-lib` may help. |
| |
| Rust does not generate simple standalone `.o` files, so you can't just throw the |
| Rust-generated code into your existing C++ toolchain linker. Instead you need to |
| choose one of these options: |
| |
| * Use `rustc` as the final linker. Pass any non-Rust libraries using `-L |
| <directory>` and `-l<library>` rustc arguments, and/or `#[link]` directives in |
| your Rust code. If you need to link against C/C++ `.o` files you can use |
| `-Clink-arg=file.o`. |
| |
| * Use your C++ linker. In this case, you first need to use `rustc` and/or |
| `cargo` to generate a _single_ Rust `staticlib` target and pass that into your |
| foreign linker invocation. |
| |
| * If you need to link multiple Rust subsystems, you will need to generate a |
| _single_ `staticlib` perhaps using lots of `extern crate` statements to |
| include multiple Rust `rlib`s. Multiple Rust `staticlib` files are likely |
| to conflict. |
| |
| Passing Rust `rlib`s directly into your non-Rust linker is not supported (but |
| apparently sometimes works). |
| |
| See the [Rust reference's *Linkage*][linkage] page for some general information |
| here. |
| |
| [linkage]: https://doc.rust-lang.org/reference/linkage.html |
| |
| The following open rust-lang issues might hold more recent guidance or |
| inspiration: [rust-lang/rust#73632], [rust-lang/rust#73295]. |
| |
| [rust-lang/rust#73632]: https://github.com/rust-lang/rust/issues/73632 |
| [rust-lang/rust#73295]: https://github.com/rust-lang/rust/issues/73295 |