I'm experimenting with this structure for a GUI application:
FLTK <--- my C++ frontend ---> my Rust library
Here FLTK is the C++ GUI framework and X ---> Y means "X calls Y". So int main() would be written in C++ and would call into FLTK for GUI stuff and into Rust for the "business logic". (Yes, I know about FLTK — Rust GUI library // Lib.rs, and I still want to experiment with this alternative approach.)
Now, I'd like to manage the C++ frontend ---> Rust library part with CXX. CXX certainly supports C++ calling Rust, but I'm not sure how to set it up to coordinate a Rust library with a C++ binary that calls into it. Is that a supported use-case? Can I achieve this with Cargo and the cc build dependency, or should I look into using something like Bazel instead?
I've read that page, but it doesn't speak to how you can write your main() in C++ and have it call Rust via a CXX bridge.
For now I'm using a "C++ sandwich", like this:
main.rs ---------+
| (CXX bridge)
v
FLTK <--- my C++ layer ---> (CXX bridge) ---> lib.rs
This actually has some advantages, since I can write command-line parsing and other non-GUI setup in Rust instead of C++. But I'm still curious whether there's a way to do without main.rs and the Rust -> C++ -> Rust double indirection here.
The extern "Rust" section of a CXX bridge declares Rust types and signatures to be made available to C++.
The CXX code generator uses your extern "Rust" section(s) to produce a C++ header file containing the corresponding C++ declarations. The generated header has the same path as the Rust source file containing the bridge, except with a .rs.h file extension.
A bridge module may contain zero or more extern "Rust" blocks.
So you could write your main() in C++ like normal, then import the foo.rs.h header to call into your Rust code.
The idea is you would compile your Rust code to a cdylib or staticlib using cargo build, then use the C++ project's build system to link it into your final executable.
That makes sense -- so an additional (non-Cargo) build system does need to be involved. With the Rust -> C++ -> Rust setup I can get by using only Cargo, so I'm inclined to stick with that.
Yeah, that's a good reason to stick with a Rust main(). People always underestimate how valuable it is to have a build system that Just Works.
It really depends on how complex your C++ is, though. I've found using the cc crate works okay for compiling simple self-contained libraries, but if your C++ pulls in dependencies or has a more "interesting" build story your build.rs script tends to get quite brittle.
You also don't get the incremental compilation something like CMake or Bazel would give you for your C++ code.