Description
Input C
struct Packet
{
long long x;
float y;
};
double frob(struct Packet packet);```
Bindgen Invocation
bindgen::Builder::default()
// The input header we would like to generate
// bindings for.
.header("src/frobber.h")
// Specify clang options
.clang_arg("-fvisibility=default") // Needed for WebAssembly as per https://github.com/rust-lang/rust-bindgen/issues/2589
.clang_arg("--target=wasm32-unknown-unknown")
.allowlist_function("frob")
// Tell cargo to invalidate the built crate whenever any of the
// included header files changed.
.parse_callbacks(Box::new(bindgen::CargoCallbacks))
// Finish the builder and generate the bindings.
.generate()
// Unwrap the Result and panic on failure.
.unwrap()
.write_to_file("src/frobber_bindings.rs")
.unwrap();
Actual Results
Major caveat below!
extern "C" {
pub fn frob(packet: Packet) -> f64;
}
Under normal circumstances, the actual results are exactly what I would expect. However, when linking under wasm32-unknown-unknown
I get these results:
= note: rust-lld: error: function signature mismatch: frob
>>> defined as (i64, f32) -> f64 in C:\dev\wasm_link_test\target\wasm32-unknown-unknown\release\deps\wasm_link_test.wasm_link_test.4f5e81ff432209fe-cgu.2.rcgu.o
>>> defined as (i32) -> f64 in C:\dev\wasm_link_test\target\wasm32-unknown-unknown\release\build\wasm_link_test-2cc6822d683d0def\out\libfrobber.a(frobber.o)
These results would suggest that Rust is passing the Packet
object by value by breaking it up and passing each parameter as independent values. Manually tweaking the generated bindings to to pass packet
by references (as per "Expected results" below).
All this said, I don't understand why a problem like this would be specific to WebAssembler. Pretty much every ABI on every platform I've worked with involves passing non-trivial structs by value using a hidden reference. So based on my understanding of this problem, I'd expect this issue to affect all platforms (which is clearly not happening).
I have read your disclaimer regarding certain C++ ABIs (e.g. - Itanium and MSVC). For this reason I was keen on demonstrating this problem with normal C code.
Expected Results
Not really what I would expect of course, but this seems to sidestep the problem
extern "C" {
pub fn frob(packet: &Packet) -> f64;
}