Add simple C++ to Rust interop example with Makefile build script - #29
Conversation
Signed-off-by: Kelechi Ebiri <ebiritg@gmail.com>
Signed-off-by: Kelechi Ebiri <ebiritg@gmail.com>
| // `no_mangle` is marked unsafe because it controls the symbol name at link time. | ||
| #[unsafe(no_mangle)] | ||
| pub extern "C" fn add(left: i32, right: i32) -> i32 { | ||
| left + right |
There was a problem hiding this comment.
Hello I'm Ethan. One of the co-mentors with Outreachy. It looks like this successfully calls Rust from C++ which is great. It's often the case in interop that we need to both call Rust from C++ and call C++ from Rust. What would it take to extend this example so that our Rust code calls into C++?
There was a problem hiding this comment.
Hi @thunderseethe To support calling C++ from Rust, my understanding is that I would need to define a C++ function (exposed with C ABI) and then declare it in Rust using an extern block, calling it via unsafe.
I’m thinking of extending the current example with a small C++ function (e.g. multiply) and invoking it from the Rust code to demonstrate bidirectional interop.
Signed-off-by: Kelechi Ebiri <ebiritg@gmail.com>
teor2345
left a comment
There was a problem hiding this comment.
Here's how to fix the CI failures
| fn multiply(a: i32, b: i32) -> i32; | ||
| } | ||
|
|
||
|
|
There was a problem hiding this comment.
Part of CI is failing because the formatting is slightly different to standard, try running cargo fmt --all
| all: | ||
| cd rust && cargo build --release | ||
|
|
||
| g++ cpp/main.cpp -Lrust/target/release -lrustlib -o main |
There was a problem hiding this comment.
Part of CI is failing because of linker order. Most linkers expect all functions provided early on the command line, and the users of those functions listed later.
There's a circular dependency here, because:
- main.cpp needs to be listed first so it can find
add - but
rustlibneeds to be listed first so it can fundmultiply
This can be fixed using library groups:
https://stackoverflow.com/questions/9380363/resolving-circular-dependencies-by-linking-the-same-library-twice
Signed-off-by: Kelechi Ebiri <ebiritg@gmail.com>
|
Hi @teor2345 I've added --start-group/--end-group to the Makefile to handle the circular dependency for the full build. But CI jobs 1 and 2 also fail because they run cargo build and cargo test on the Rust crate alone, where multiply isn't available. Should I add a build.rs that compiles the C++ code so the Rust crate can build standalone, or is there a better way to structure this? |
Huh, yeah, that is an issue. For library builds, all the symbols don't need to be defined, so you're fine not having multiply. For test builds, it's a binary, so it needs all the symbols. Your options are:
I think the last option is the simplest, but I'm happy to guide you through whichever one you want. |
|
Ok, cool. I'd like to try the build.rs approach since it feels most relevant to the project's focus on build system integration. I'd appreciate guidance on that if you're willing! |
Signed-off-by: Kelechi Ebiri <ebiritg@gmail.com>
Signed-off-by: Kelechi Ebiri <ebiritg@gmail.com>
teor2345
left a comment
There was a problem hiding this comment.
Thank you, this is a useful example of circular dependencies in code and tests.
Add example demonstrating C++ calling Rust via C ABI and Makefile