Is there a reason the Rust-exported functions aren't marked with `extern "C"`?
Is there a reason the Rust-exported functions aren't marked with `extern "C"`?
Regarding the declarations: this would only be necessary if processed in C++ context, to change the name mangling/linkage features of the declarations. For portability sometimes authors hide these behind "ifdef __cplusplus" barriers, but it's not really critical here.
Regarding the definitions: "Exposing a C ABI in Rust" from the article describes this in detail. For the most part, "#[no_mangle]" has the same effect that "extern "C"" has on linkage/mangling in C++.
As far as I know, `#[no_mangle]` disables name-mangling but doesn't change the ABI of a function. That's what `extern "C"` is for in Rust -- to declare a function with the C ABI. You can have a Rust ABI function with an unmangled name (what it looks is done in the post) and you can have a C ABI function in Rust with a mangled name (by using `extern "C"` but not `#[no_mangle]` -- for example for C callbacks).
Based on my limited understanding of C++, `extern "c"` in C++ is equivalent to using both `#[no_mangle]` and `pub extern "C"` in Rust. I would guess that much of the time failing to specify a C ABI would work out fine unless you try to accept or pass non-FFI types (enums, references, etc) but I'm not sure.
It's confusing as hell. There was a thread about the mixed up semantics somewhat recently on the internals forum: https://internals.rust-lang.org/t/no-no-mangle/3973 (edit: and also https://internals.rust-lang.org/t/precise-semantics-of-no-ma...).
If you look at the LLVM IR generated from https://is.gd/Hfup3X you can see that the extern "C" fn differs in that it's given a `nounwind` attribute, among other things.
Thanks for the tip btw I think this means I have a bug in my code. ;)
#[no_mangle]
pub extern unsafe fn lsm_view_from_json(bytes: *const u8, len: c_uint,
err_out: *mut CError) -> *mut View
{
...
} typedef struct { int x[500]; } bigthing;
bigthing MyFunction();
and a program using that library: int main() {
bigthing x = MyFunction();
}
C has no choice but to have MyFunction allocate a couple kilobytes on the stack and have main copy the structure from the stack to where it should eventually go. The equivalent Rust code, however, can pass the address of the object x to MyFunction, as if it were actually void MyFunction(bigstruct &output).If you have a #[no_mangle] but not extern function in Rust, the Rust compiler will generate code for that function that looks for this secret by-reference argument and fills it in. When you call it from C (or something that calls functions in a C-like manner, like Python's cffi), it won't be setting up the call like that at all, and it will expect to read the result off the stack like a C function would have done.
(I don't think there's a lot of use for #[no_mangle] without extern. The best I can think of is that, if you have a Rust application that dynamically loads a Rust library and runs a function from it, you don't have access to the mangling algorithm, once you find the function you'll call it according to the Rust ABI. But even that is risky since the Rust ABI can change between compiler versions; you're still better off shoveling things through the C ABI.)
What sort of C implementation (ABI, compiler, etc.) are you thinking of here? gcc (x86, x86-64, ARM) is perfectly capable of doing the exact optimization that you describe Rust being able to do.
I guess the trick here is that "C" really means "platform ABI" and isn't inherently about a language or a compiler.
I do know that if you bind to a function that is linked in that you need it.
https://internals.rust-lang.org/t/precise-semantics-of-no-ma...