Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Should there be an extern "wasm" ABI? #29

Closed
fitzgen opened this issue Jan 19, 2018 · 61 comments
Closed

Should there be an extern "wasm" ABI? #29

fitzgen opened this issue Jan 19, 2018 · 61 comments

Comments

@fitzgen
Copy link
Member

fitzgen commented Jan 19, 2018

It would make compile-time errors if you tried to pass something that can't be passed across FFI boundaries in wasm, but can in C, such as structs.

Maybe this already exists and I'm ignorant of it?

Anyways, if feels weird to expose wasm APIs with extern "C".

@pepyakin
Copy link
Member

pepyakin commented Jan 19, 2018

I see why are you stating that structs can't pass accross FFI boundaries: wasm can't hold any values other than i32, i64, f32, f64.
However, "real" architectures usually can't either: on these architectures compiler should split structures between registers or spill into the memory.
So, I don't think that "wasm" is a another ABI.

@fitzgen
Copy link
Member Author

fitzgen commented Jan 19, 2018

Other ABIs have defined rules for how to split structs up, and how their parts cross the boundary. Both sides of FFI can agree on how to split up and paste back together structs.

AIUI, wasm does not have any such rules, and so you cannot pass structs across the boundary because there is no guarantees that both sides will agree on what is being passed and how. For wasm, it would be incorrect for the compiler to allow structs to be used in FFI.

@pepyakin
Copy link
Member

Interesting, I thought contrary to that (at least, in cases where on both sides code is produced by LLVM).

@alexcrichton
Copy link
Contributor

An interesting question! Makes me wonder a bit more in general about ABI implications in Rust right now.

At the base leve @pepyakin's right, we can only deal with some integers/floats, but another aspect we're not exposing today is the "two level import" where you import from a module and then an item in that module.

That leads me to two questions:

  • How do we expose the "two level import" mechanism? Do we want to do this at the language level? Do we want to do this via attributes? A postprocessing for Rust? Note that all extern imports are implicitly lumped into an env module, but I wouldn't want that to be the case forever.

  • What types do we want to allow in imports? Only wasm allowed types? All types and let LLVM figure it out? Wasm, unlike other platforms like x86, (AFAIK) doesn't have a "stable ABI" so when we pass a struct Foo around there's no guarantee it's the same as what anyone else does. In that sense I might be inclined to take a very conservative stance for now and restrict imports to just the wasm types until there's a stable ABI that LLVM is implementing.

There's also the question of ABI strings ("wasm" and "C") and I'm somewhat tempted to forbid "C" and require "wasm" on the wasm target...

@fitzgen
Copy link
Member Author

fitzgen commented Jan 19, 2018

See also rust-lang/rust#47599

@fitzgen
Copy link
Member Author

fitzgen commented Jan 19, 2018

What types do we want to allow in imports? Only wasm allowed types? ... I might be inclined to take a very conservative stance for now and restrict imports to just the wasm types until there's a stable ABI that LLVM is implementing.

This is what I'd expect.

@pepyakin
Copy link
Member

But what if I would like to actually link to a C code?
Everywhere I would use extern "C", but when I would compile to rust I should use extern "wasm"?

@alexcrichton
Copy link
Contributor

@pepyakin that's true but I also personally have no model for what that even means. Today wasm (in rust at least) has no compilation units, but linking to C code implies some degree of compilation units. In that sense it's difficult to envision what's happening here...

One perhaps reasonable way to rationalize this could be:

  • Once we have compilation units, it sounds like they may not be tied to the wasm format. Maybe a stable C ABI will start to emerge? In the meantime LLVM may be the only compiler so we could be good. Perhaps at this point we could say that compilation units communicate over extern "C".
  • We would then say that extern "wasm" is how you actually import functions from the wasm file itself. These imports cannot be resolved by other compilation units.

That I imagine would help solve communicating with C (assuming everythign works out, again that doesn't really exist yet!) while also being clear about what you're importing from the environment.

Perhaps then...

#[module = "foo"] // required for `extern "wasm"`
extern "wasm" {
    fn bar() -> i32; // imported from module "foo"

    // fn baz() -> i8; // illegal
}

extern "C" {
    fn another(); // generates a link error if unresolved and final `.wasm` file is created
}

@sunfishcode
Copy link

Yes; we are expecting a stable C ABI to emerge for wasm eventually. In fact, most of the C ABI details in clang are pretty stable already.

The one upcoming C ABI change that is I know of is that when wasm gets multiple return values, clang will likely switch to passing and returning "small-ish" structs by value (rather than byval/sret in LLVM). After that, it's likely that wasm's C ABI will be stable.

@pepyakin
Copy link
Member

Sounds reasonable!
Also, we shouldn't forget about exports side (approach described by you should work with them well).

Once we have compilation units, it sounds like they may not be tied to the wasm format. Maybe a stable C ABI will start to emerge? In the meantime LLVM may be the only compiler so we could be good. Perhaps at this point we could say that compilation units communicate over extern "C".

There is some demand for linking against bare wast files (e.g. produced by wat2wasm), and I don't know if it is will be supported by LLD. But I guess it should.

@alexcrichton
Copy link
Contributor

@sunfishcode ah while you're here, do you know if there's an idea of how to specify wasm imports from C? (imports that get hooked into the ES module system, that is)

@est31
Copy link

est31 commented Jan 19, 2018

If there is we could see this as an opportunity to remove the requirement on the #[no_mangle] tag: rust-lang/rust#46294

@sunfishcode
Copy link

@alexcrichton Yeah, there are ongoing discussions. The rough theory is:

  • env is what you get by default if you don't specify an import module. Symbols in env are either resolved at link time, or the linker determines the library that will satisfy them and substitutes it (two-level namespacing). No env symbols remain after linking.
  • rename env to something less likely to collide with user names
  • add a wasm-specific attribute, which for C/C++ might look like __attribute__((import_module("foo"))), for specifying an explicit module name. Functions only, for now. These names would be left untouched by the linker.

@alexcrichton
Copy link
Contributor

@sunfishcode ok cool, thanks!

That actually aligns pretty well with what I had in mind already, and should work perfectly for us!

@est31
Copy link

est31 commented Jan 21, 2018

There's also the question of ABI strings ("wasm" and "C") and I'm somewhat tempted to forbid "C" and require "wasm" on the wasm target...

To add to this: I personally tend to avoid writing out the "C": extern fn foo is much nicer. On wasm, this could mean extern "wasm" .

@sunfishcode
Copy link

I've now posted https://reviews.llvm.org/D42520 which is an LLVM patch implementing __attribute__((import_module("foo"))) (C/C++), "wasm-import-module"="foo" (LLVM IR), and .import_module somefunc, foo (LLVM .s files), and renaming env, along what I described above.

@alexcrichton
Copy link
Contributor

Awesome, thanks for the update @sunfishcode!

@alexcrichton
Copy link
Contributor

Thinking about this a bit I'd like to bikeshed some possibilities for how we can expose this in Rust. I think there's a big difference in the "desired end state" from what we have today where the wasm module imports/exports are conflated with imports/exports from codegen units. In other words, I think we'll want to consider a sort of "two level namespace" along the lines of:

#[no_mangle]
pub extern fn foo() {} // exports today, will not export tomorrow

extern {
    fn bar(); // import from the module today, won't tomorrow.
}

So with that in mind I'd like to bikeshed two syntaxes for this.

Add a "wasm" ABI

We could take a route of adding the "wasm" ABI as a string. It would validate that only valid datatypes (u32, u64, f32, f64) are contained in the signature and otherwise wouldn't do much else. The above would then be written as:

#[no_mangle]
pub extern "wasm" fn foo() {} // wasm module export with name `foo`

#[wasm_module = "baz"]
extern "wasm" {
    fn bar(); // wasm module import from `baz` the name of `bar`
}

An upside of this approach is that it's somewhat "clean" but a downside is that it still deals with things like #[no_mangle] and pub for exports and requires some sort of attribute (or thing) like #[wasm_module] to declare what module imports come from.

Only special attributes

A different approach could be to basically just add wasm-specific attributes. This wouldn't change the ABI per se but we could do something like:

#[wasm_export] // implies `no_mangle`
pub fn foo() {} 

#[wasm_module = "baz"]
extern {
    fn bar();
}

We'd still verify that valid datatypes show up in the signature (only u32, u64, f32, f64) but this wouldn't be changing the ABI and rather just adding special attributes


Thoughts on this? Other ideas on how to surface imports/exports in Rust?

@fitzgen
Copy link
Member Author

fitzgen commented Jan 29, 2018

We could take a route of adding the "wasm" ABI as a string. It would validate that only valid datatypes (u32, u64, f32, f64) are contained in the signature and otherwise wouldn't do much else

Would we allow pointers and usize in the "wasm" abi? That would certainly be convenient, but I also understand if folks don't feel great about implicitly converting pointers to usize across the "wasm" ABI boundary. It is something that works right now, though.

#[wasm_module = "baz"]
extern {
    fn bar();
}

Are you imagining this with the future dynamic wasm linking, or with statically linking multiple .wasm objects together into a single .wasm, or at module instantiation time, or...? What does wasm_module = "baz" mean here? What is "baz"?

Given what is supported now, I would expect this

extern {
    fn bar(); // import from the module today, won't tomorrow.
}

to turn into something like this

#[wasm_import] // we expect to import this at instantiation time, not link to another `.wasm` providing it.
extern "wasm" {
    fn bar();
}

Thoughts on this? Other ideas on how to surface imports/exports in Rust?

Other than the above confusion, this is 💯

@alexcrichton
Copy link
Contributor

@fitzgen

Would we allow pointers and usize in the "wasm" abi?

Perhaps yeah! I'd personally lean initially towards the ultra-conservative stance of "no" but I'd be fine going in either direction.

Are you imagining this with the future dynamic wasm linking, or with statically linking multiple .wasm objects together into a single .wasm, or at module instantiation time, or...?

Ah so to clarify, wasm-the-specification supports something which we're not exporting in Rust right now which is two-level imports. Sort of like in JS where you can do:

import { foo } from 'bar';

the module you're importing from here is bar and the name you're importing is foo. In Rust right now the module is always env and the name is configurable (it's what you write down in the extern block). The #[wasm_module] attribute I was alluding to was intended to configure the module name here.

So today you'd write:

extern {
    fn foo();
}

which in JS would be equivalent to:

import { foo } from 'env';

which isn't actually what we want! Instead what I'm thinking we'd do is:

#[wasm_module = "bar"]
extern {
    fn foo();
}

which is equivalent to our original js:

import { foo } from 'bar';

Does that help clear things up?

@fitzgen
Copy link
Member Author

fitzgen commented Jan 30, 2018

Does that help clear things up?

Yep!

@mgattozzi
Copy link
Contributor

I feel conflicted on this. On the one hand I like the first one more because

#[no_mangle]
pub extern "wasm" fn foo() {}

is consistent with our current code doing:

#[no_mangle]
pub extern "c" fn foo() {}

I would think we would want to err on the side of consistency for now because it would "Just make sense" to what Rustaceans already know.

That being said I find the:

#[wasm_export]
pub fn foo() {}

To have less noisy syntax and more clearly state what's going in the code, especially for people who might be new to Rust and aren't set in the current FFI conventions. I don't know what I want yet personally out of those choices.

Maybe we could do a compromise:

#[wasm_export]
pub fn foo() {}

implies:

#[no_mangle]
pub extern "wasm" fn foo() {}

and both as valid choices and let the user choose how they want to define it. This does lead to more maintenance burden but we could just have #[wasm_export] just be a proc_macro that desugars to the pub extern syntax.

I do think that this:

#[wasm_module = "bar"]
extern {
    fn foo();
}

would be great to avoid putting everything in env as one module.

@CryZe
Copy link

CryZe commented Jan 30, 2018

Just to clarify a few things

#[no_mangle]
pub extern "C" fn foo(...) { ... }

will continue to work just like it does right now, right? Otherwise this proposal will completely wreck my use case.

@alexcrichton
Copy link
Contributor

@mgattozzi yeah one thing I'm also not sure about with the "wasm" ABI is I'm not sure if we actually want it to be a full-blown ABI. But maybe because we're validating types it is indeed an ABI? I'm not sure...

@CryZe I do think we will break that one way or another, yes. Right now we're mixing up linker-like symbols with imports/exports from the wasm module. The intention of this issue/proposal is to make it more explicitly what's happening at the wasm import/export layer (and don't conflate it with symbols).

The functionality isn't being lost though! While today you'd write:

#[no_mangle]
pub extern "C" fn foo() {}

that'd be equivalent to tomorrow's

#[wasm_export]
pub fn foo() {}

(depending on the syntax we settle on)

@CryZe
Copy link

CryZe commented Jan 30, 2018

I have a C API that I compile to various targets (39 targets including the WASM target atm). Requiring me to have a full on copy of this C API just for the WASM target is not maintainable for me (that's like 500 exported symbols). So it would be preferable to have a solution that works across various targets, like keeping the behavior of the extern "C" functions, or allowing extern "C" with #[wasm_export] and ignoring that attribute for the other targets.

@alexcrichton
Copy link
Contributor

Aha an excellent point @CryZe, thanks for the info!

To me that's the nail in the coffin to do:

#[wasm_export] // implies `no_mangle`, only works with `"C"` ABI functions
pub extern fn foo() {} 

#[wasm_module = "baz"]
extern { // must be "C" ABI
    fn bar();
}

We could ignore the #[wasm_*] attributes on other targets for sure, but I think it makes sense to start with the C ABI as the definition for "what crosses the module boundary".

@CryZe note that it's also being considered that we should validate signatures with #[wasm_export]. For example wasm today only allows u32/u64/f32/f64 at the actual lowest layer. Would this cause problems for you? @fitzgen pointed out that we could also relax this to pointers/usize as well to make it a bit nicer.

@mgattozzi
Copy link
Contributor

@alexcrichton I think we should do at least some kind of validation if we can. Unlike #[no_std] removing the std library there's not much we can do to prevent people from using primitives they shouldn't beyond stopping the compiler from finishing the compile. I think this is good behavior to have. I have a feeling we should allow pointers as that's usually how to deal with passing foreign types to other languages but, maybe we can add it at a later date once we get the actual ABI (I think we can call it that in this case) started and hash out the specifics more. We generally go for conservative implementation first than iterate.

@fitzgen
Copy link
Member Author

fitzgen commented Jan 30, 2018

I am sympathetic to making cross platform externs work. I think

#[cfg_attr(target_arch = "wasm32", wasm_import)]

should do the trick:

  • allowing reuse of the extern declarations, and

  • letting rustc determine whether this extern is for importing functions at wasm module instantiation time vs something provided by another .wasm that we will eventually link to.

@fitzgen pointed out that we could also relax this to pointers/usize as well to make it a bit nicer.

Note that this works today, so it is more about if we want it not to work anymore.

Also, despite using extern "C", will we check for and allow only scalars? What happens if I try and pass a repr(C) struct across the wasm ABI boundary? I think this should be a compilation error, even though it wouldn't be for an extern "C" function on other targets.

@Pauan
Copy link

Pauan commented Mar 12, 2018

So, after thinking about this some more, there's two different ways of handling u32:

  1. In host environments that have native u32 support it should convert u32 to i32 (since as @pepyakin said, in those environments signed-ness doesn't matter). Similarly it should convert u64 into i64.

  2. However, for JavaScript it should convert from u32 to f64.

So because the conversion depends upon the host environment, my current thinking is that Rust should simply forbid passing u32 and u64 to WebAssembly.

If the programmer knows that the host environment supports native u32 / u64 then they can use foo as i32 or foo as i64 before passing to WebAssembly.

And in the case of JavaScript the programmer can use foo as f64 before passing to WebAssembly.

This also gives more flexibility: if the JavaScript code does a conversion from i32 to u32 (using foo >>> 0), then the programmer should use foo as i32 when passing to JavaScript.

But if the JavaScript code expects a non-negative Number (without conversion), then the programmer should use foo as f64 when passing to JavaScript.

alexcrichton referenced this issue in alexcrichton/rust Mar 13, 2018
This commit adds a new attribute to the Rust compiler specific to the wasm
target (and no other targets). The `#[wasm_import_module]` attribute is used to
specify the module that a name is imported from, and is used like so:

    #[wasm_import_module = "./foo.js"]
    extern {
        fn some_js_function();
    }

Here the import of the symbol `some_js_function` is tagged with the `./foo.js`
module in the wasm output file. Wasm-the-format includes two fields on all
imports, a module and a field. The field is the symbol name (`some_js_function`
above) and the module has historically unconditionally been `"env"`. I'm not
sure if this `"env"` convention has asm.js or LLVM roots, but regardless we'd
like the ability to configure it!

The proposed ES module integration with wasm (aka a wasm module is "just another
ES module") requires that the import module of wasm imports is interpreted as an
ES module import, meaning that you'll need to encode paths, NPM packages, etc.
As a result, we'll need this to be something other than `"env"`!

Unfortunately neither our version of LLVM nor LLD supports custom import modules
(aka anything not `"env"`). My hope is that by the time LLVM 7 is released both
will have support, but in the meantime this commit adds some primitive
encoding/decoding of wasm files to the compiler. This way rustc postprocesses
the wasm module that LLVM emits to ensure it's got all the imports we'd like to
have in it.

Eventually I'd ideally like to unconditionally require this attribute to be
placed on all `extern { ... }` blocks. For now though it seemed prudent to add
it as an unstable attribute, so for now it's not required (as that'd force usage
of a feature gate). Hopefully it doesn't take too long to "stabilize" this!

cc rust-lang-nursery/rust-wasm#29
@alexcrichton
Copy link
Contributor

I've sent a PR to rust-lang/rust to implement #[wasm_import_module]

@Pauan
Copy link

Pauan commented Mar 14, 2018

I just found this. It's a part of the host bindings proposal, so it's not standardized yet, but it provides a mechanism for wasm to import/export u32 (and other types like JS Strings).

So that makes me even more convinced that right now we shouldn't allow for u32 in wasm import/export. If that host binding proposal gets accepted, then we can consider allowing u32, but until then we should keep our options open.

alexcrichton referenced this issue in alexcrichton/rust Mar 18, 2018
This commit adds a new attribute to the Rust compiler specific to the wasm
target (and no other targets). The `#[wasm_import_module]` attribute is used to
specify the module that a name is imported from, and is used like so:

    #[wasm_import_module = "./foo.js"]
    extern {
        fn some_js_function();
    }

Here the import of the symbol `some_js_function` is tagged with the `./foo.js`
module in the wasm output file. Wasm-the-format includes two fields on all
imports, a module and a field. The field is the symbol name (`some_js_function`
above) and the module has historically unconditionally been `"env"`. I'm not
sure if this `"env"` convention has asm.js or LLVM roots, but regardless we'd
like the ability to configure it!

The proposed ES module integration with wasm (aka a wasm module is "just another
ES module") requires that the import module of wasm imports is interpreted as an
ES module import, meaning that you'll need to encode paths, NPM packages, etc.
As a result, we'll need this to be something other than `"env"`!

Unfortunately neither our version of LLVM nor LLD supports custom import modules
(aka anything not `"env"`). My hope is that by the time LLVM 7 is released both
will have support, but in the meantime this commit adds some primitive
encoding/decoding of wasm files to the compiler. This way rustc postprocesses
the wasm module that LLVM emits to ensure it's got all the imports we'd like to
have in it.

Eventually I'd ideally like to unconditionally require this attribute to be
placed on all `extern { ... }` blocks. For now though it seemed prudent to add
it as an unstable attribute, so for now it's not required (as that'd force usage
of a feature gate). Hopefully it doesn't take too long to "stabilize" this!

cc rust-lang-nursery/rust-wasm#29
alexcrichton referenced this issue in alexcrichton/rust Mar 22, 2018
This commit adds a new attribute to the Rust compiler specific to the wasm
target (and no other targets). The `#[wasm_import_module]` attribute is used to
specify the module that a name is imported from, and is used like so:

    #[wasm_import_module = "./foo.js"]
    extern {
        fn some_js_function();
    }

Here the import of the symbol `some_js_function` is tagged with the `./foo.js`
module in the wasm output file. Wasm-the-format includes two fields on all
imports, a module and a field. The field is the symbol name (`some_js_function`
above) and the module has historically unconditionally been `"env"`. I'm not
sure if this `"env"` convention has asm.js or LLVM roots, but regardless we'd
like the ability to configure it!

The proposed ES module integration with wasm (aka a wasm module is "just another
ES module") requires that the import module of wasm imports is interpreted as an
ES module import, meaning that you'll need to encode paths, NPM packages, etc.
As a result, we'll need this to be something other than `"env"`!

Unfortunately neither our version of LLVM nor LLD supports custom import modules
(aka anything not `"env"`). My hope is that by the time LLVM 7 is released both
will have support, but in the meantime this commit adds some primitive
encoding/decoding of wasm files to the compiler. This way rustc postprocesses
the wasm module that LLVM emits to ensure it's got all the imports we'd like to
have in it.

Eventually I'd ideally like to unconditionally require this attribute to be
placed on all `extern { ... }` blocks. For now though it seemed prudent to add
it as an unstable attribute, so for now it's not required (as that'd force usage
of a feature gate). Hopefully it doesn't take too long to "stabilize" this!

cc rust-lang-nursery/rust-wasm#29
@alexcrichton
Copy link
Contributor

It's now possible in nightly to specify the module of an import via the #[wasm_import_module] attribute.

I'm personally sort of tempted to close this as "done" otherwise rather than implement a check for types in the ABI and perhaps investigate a lint at a later date

@nikgraf
Copy link

nikgraf commented Jun 16, 2018

@alexcrichton I was going through this tutorial and noticed the note at the top. Does the recent PR change anything for the tutorial here https://rustwasm.github.io/book/js-ffi.html?

What does #[wasm_import_module] exactly do?

@DrSensor
Copy link

For example, is it possible to add/use Math.random() using #[wasm_import_module]?

@fitzgen
Copy link
Member Author

fitzgen commented Jun 18, 2018

@DrSensor , #[wasm_bindgen(wasm_import_module = "...")] controls the ECMAScript module from which the binding is imported. By default, modules are not used and the global scope is where imports are plucked from.

Essentially, it is whether the generated JS glue looks like

// default
const importedThing = window.importedThing;

vs

// using #[wasm_bindgen(wasm_import_module = "./foo")]
import { importedThing } from "./foo";

For importing Math.random, you would use #[wasm_bindgen(js_namespace = Math)] because Math is an object on the global, not an ECMAScript module. See https://github.com/rustwasm/wasm-bindgen/tree/master/examples/math for an example.

@alexcrichton
Copy link
Contributor

It's been awhile since this has come up again and I think in the meantime we've ended up with what seems like a good balance between the various concerns here. Notably the current state of play is:

  • No new ABI string is introduced for wasm
  • Currently there is no restriction on types used in wasm's ABI, eventually we'll follow the standard of C/Clang/LLVM once it's available.
  • Exporting a symbol on wasm is the same as exporting it on other platforms, it's pub, reachable, and with an extern indicator.
  • Importing symbols work the same way as other platforms, with the addition of the #[link(wasm_import_module = "..")] (soon to be merged) to customize the import module.

Otherwise in the meantime tools like wasm-bindgen and wasm-pack hide all these details from the user so it's not too too important for ergonomics.

With all that, I'm gonna close this!

@dvc94ch
Copy link

dvc94ch commented Nov 18, 2021

I wonder if this should be reconsidered. The reason being I think it's useful to use the wasm abi for building ffi's to gc'ed languages.

It's possible to write completely safe ffi apis that express ownership/lifetimes and are ergonomic to write. An example would look like this:

#[repr(C)]
pub struct Str<'a> {
    ptr: NonNull<u8>,
    len: usize,
    marker: PhantomData<&'a str>,
}

#[no_mangle]
pub extern "C" fn ffi_new_greeter(greeting: Str<'_>) -> FfiResult<Box<Greeter>> {
    catch_panic(move || {
        Ok(Box::new(Greeter::new(greeting.as_ref().to_string())))
    })
}

however when binding it on the other end in gc'ed languages it requires two allocations to call this method, one to allocate the byte buffer, and one to allocate the Str struct, and then the *Str is passed to the runtime provided callc mechanism.

on wasm32, especially interesting with -Ctarget_feature=+multivalue, the struct would be passed as two i32 avoiding the allocation. generating bindings for this in other languages would likely also get easier over time as wasm becomes more ubiquos.

@memoryruins
Copy link

I wonder if this should be reconsidered.

@dvc94ch looks like it may have been. #![feature(wasm_abi)] was added this April rust-lang/rust#83763

@dvc94ch
Copy link

dvc94ch commented Nov 22, 2021

interesting. for now I decided to go with parsing and generating code for "rust header" files after studying various projects for generating ffi interfaces and bindings. I expect ffi-gen to be released in the next couple of weeks.

@dvc94ch
Copy link

dvc94ch commented Dec 7, 2021

Just released the first version of ffi-gen with support for dart/flutter/node/browser. Still a little lite on documentation, there are cases that can misscompile if you aren't familiar with the internals and errors are very poor. However I think it's currently the best solution out there if you want to create a rust library with bindings to multiple languages. We've already migrated our api to ffi-gen.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests