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

Producing wasm-binary if there's main.rs #74

Closed
akritrime opened this issue Mar 23, 2018 · 16 comments
Closed

Producing wasm-binary if there's main.rs #74

akritrime opened this issue Mar 23, 2018 · 16 comments

Comments

@akritrime
Copy link

akritrime commented Mar 23, 2018

Currently, the only way to execute rust code is via exposing a function and then calling it on js side. It would be nice to be able to do something like this:
main.rs

#![feature(proc_macro)]

extern crate wasm_bindgen;

use wasm_bindgen::prelude::*;

#[wasm_bindgen]
extern {
    #[wasm_bindgen(js_namespace = console)]
    fn log(s: &str);
}

fn main() {
    log("Hello from Rust");
}

Then using the cli to generate the required js and including the js directly in the html to execute it, instead of going through an intermediate state of needing to manually write another js file.

@alexcrichton
Copy link
Contributor

This is sort of related to https://github.com/rust-lang-nursery/rust-wasm/issues/18 as the wasm feature here we'd leverage is the start section but the Rust compiler, as of today, doesn't support this feature. I think that's definitely worth supporting though! (I'm not sure it would require anything on wasm-bindgen's side of things though)

@akritrime
Copy link
Author

But until the start situation is sorted on the compiler side, maybe the wasm-bindgen tool can treat the main function as any other exported function and re-export it in the generated wasm and then add a line to js where its executed like wasm.main() in the js code itself?

@alexcrichton
Copy link
Contributor

Oh certainly! That was actually a bug in wasm-gc which I pushed/published yesterday. Wasm-bindgen internally uses wasm-gc, so updating dependencies should hopefully fix that bug!

@akritrime
Copy link
Author

Nice. main is now exported and can be executed like any other function from a wasm module(Note: the generated JS file doesn't export it though). How about appending a line like wasm.main && wasm.main() so it checks and executes the function?

@alexcrichton
Copy link
Contributor

Hm perhaps! I think I might prefer though to use the start feature of wasm and expose that through rustc, as I think that's probably the best way to model this with wasm natively

@akritrime
Copy link
Author

Hmmm, I can understand. Using the start feature definitely feels like the right way.

@alexcrichton
Copy link
Contributor

In the meantime while we're waiting for rustc to catch up though I'd be totally down for doing something like #[wasm_bindgen(start)]

@akritrime
Copy link
Author

akritrime commented Apr 7, 2018

Sorry for the late reply, I got busy with exams and stuff. But I think the #[wasm_bindgen(start)] is a really nice idea.

@alexcrichton
Copy link
Contributor

I implemented this today but I don't think it's necessarily workable. The cyclic dependency between the JS and wasm emitted means that the JS is basically unusable so you can't call imports, but that's pretty non-obvious when writing the wasm.

Until that's fixed I'd personally be a bit hesitant to land this.

@joshtriplett
Copy link
Contributor

I'd love to have this available, such that the js file automatically calls the tagged main/start function as soon as it finishes loading the wasm.

@LaylBongers
Copy link

Same, writing applications entirely in Rust should preferably not need extra bootstrapping code hand-written.

@Boscop
Copy link

Boscop commented Nov 20, 2018

@LaylConway I definitely agree.
@alexcrichton
Would it then be possible to use the normal main function as start (#[wasm_bindgen(main)]), maybe even by default somehow?

@chpio
Copy link

chpio commented Nov 21, 2018

Would it then be possible to use the normal main function as start (#[wasm_bindgen(main)]), maybe even by default somehow?

is this even possible in wasm? you can't have a "normal" main function which would normally host the main loop, but in wasm you setup things in the "main" function and return from it, returning the control to the browser/runtime-environment.

@alexcrichton
Copy link
Contributor

This is definitely possible for us to do, and it largely just hasn't had anyone backing the effort needed to implement it yet!

I believe a rough implementation strategy for this would look like:

  • We'll likely want to leverage the fact that rustc produces a main exported symbol for binaries
  • In wasm-bindgen we can probably just either add #[wasm_bindgen(main)] or automatically hook up the main symbol to the start section. (I'd prefer the latter)
  • We'll need to handle the fact that the main symbol has arguments and a return value, but the start function can have neither.

We may wish to optionally update the main symbol generation for rustc itself, using no arguments and no return value (making it suitable for a start symbol), but that may be a bit more contentious.

@chpio
Copy link

chpio commented Nov 26, 2018

This is definitely possible for us to do, and it largely just hasn't had anyone backing the effort needed to implement it yet!

How would you do that? By using something to break out of the main fn without calling the destructors like emscripten (code)?

@alexcrichton
Copy link
Contributor

@chpio that's a good point yeah, and while Rust has a different set of issues than C/C++ it's definitely true that the libstd initialization function, when it exits, performs global cleanup it assumes won't ever be necessary again.

So actually now that I think about this, I think it's not as clear that we can implement this in the standard library. In the standard library we'd have to bake in the concept of a "wasm main exiting isn't the end of the world, there's no definite end of the world!", but that's not necessarily an easy decision to make.

Instead in the meantime it may be best to simply stick with #[wasm_bindgen(main)]. That has the downside of still requiring crate-type = ["cdylib"] in Cargo.toml, but it provides a way for us to experiment with this today!

alexcrichton added a commit to alexcrichton/wasm-bindgen that referenced this issue Nov 28, 2018
This commit adds a new attribute to `#[wasm_bindgen]`: `start`. The
`start` attribute can be used to indicate that a function should be
executed when the module is loaded, configuring the `start` function of
the wasm executable. While this doesn't necessarily literally configure
the `start` section, it does its best!

Only one crate in a crate graph may indicate `#[wasm_bindgen(start)]`,
so it's not recommended to be used in libraries but only end-user
applications. Currently this still must be used with the `crate-type =
["cdylib"]` annotation in `Cargo.toml`.

The implementation here is somewhat tricky because of the circular
dependency between our generated JS and the wasm file that we emit. This
circular dependency makes running initialization routines (like the
`start` shim) particularly fraught with complications because one may
need to run before the other but bundlers may not necessarily respect
it. Workarounds have been implemented for various emission strategies,
for example calling the start function directly after exports are wired
up with `--no-modules` and otherwise working around what appears to be
a Webpack bug with initializers running in a different order than we'd
like. In any case, this in theory doesn't show up to the end user!

Closes rustwasm#74
alexcrichton added a commit to alexcrichton/wasm-bindgen that referenced this issue Nov 28, 2018
This commit adds a new attribute to `#[wasm_bindgen]`: `start`. The
`start` attribute can be used to indicate that a function should be
executed when the module is loaded, configuring the `start` function of
the wasm executable. While this doesn't necessarily literally configure
the `start` section, it does its best!

Only one crate in a crate graph may indicate `#[wasm_bindgen(start)]`,
so it's not recommended to be used in libraries but only end-user
applications. Currently this still must be used with the `crate-type =
["cdylib"]` annotation in `Cargo.toml`.

The implementation here is somewhat tricky because of the circular
dependency between our generated JS and the wasm file that we emit. This
circular dependency makes running initialization routines (like the
`start` shim) particularly fraught with complications because one may
need to run before the other but bundlers may not necessarily respect
it. Workarounds have been implemented for various emission strategies,
for example calling the start function directly after exports are wired
up with `--no-modules` and otherwise working around what appears to be
a Webpack bug with initializers running in a different order than we'd
like. In any case, this in theory doesn't show up to the end user!

Closes rustwasm#74
alexcrichton added a commit to alexcrichton/wasm-bindgen that referenced this issue Nov 29, 2018
This commit adds a new attribute to `#[wasm_bindgen]`: `start`. The
`start` attribute can be used to indicate that a function should be
executed when the module is loaded, configuring the `start` function of
the wasm executable. While this doesn't necessarily literally configure
the `start` section, it does its best!

Only one crate in a crate graph may indicate `#[wasm_bindgen(start)]`,
so it's not recommended to be used in libraries but only end-user
applications. Currently this still must be used with the `crate-type =
["cdylib"]` annotation in `Cargo.toml`.

The implementation here is somewhat tricky because of the circular
dependency between our generated JS and the wasm file that we emit. This
circular dependency makes running initialization routines (like the
`start` shim) particularly fraught with complications because one may
need to run before the other but bundlers may not necessarily respect
it. Workarounds have been implemented for various emission strategies,
for example calling the start function directly after exports are wired
up with `--no-modules` and otherwise working around what appears to be
a Webpack bug with initializers running in a different order than we'd
like. In any case, this in theory doesn't show up to the end user!

Closes rustwasm#74
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

6 participants