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

supporting new non-emscripten target #15

Closed
steveklabnik opened this issue Nov 26, 2017 · 11 comments
Closed

supporting new non-emscripten target #15

steveklabnik opened this issue Nov 26, 2017 · 11 comments

Comments

@steveklabnik
Copy link

I'd love to see support for https://www.hellorust.com/news/native-wasm-target.html in cargo-web; I think it's going to be an even bigger target than the emscripten one.

@chrysn
Copy link
Contributor

chrysn commented Nov 29, 2017

(These are comments from someone without a full understanding of the Rust toolchain, so if I'm utterly on the wrong path here, please just let me know and further ignore this entry).

I toyed around with this idea a bit by adding a --target-wasm-unknown option, making triplet_or_default return wasm32-unknown-unknown if set and bypassing check_for_emcc in those cases. That resulted in a wasm file that was served by cargo web start --target-wasm-unknown and could return integers when instantiated and having one of its exported functions called.

The two next issues I see there are that

  • The builtin start function hangs somewhere deep inside (dirty-patched out with a no-op #[start]). I'm still looking into where that comes from, as I haven't seen the same kind of trouble with rustc-built wasm32-unknown-unknown scripts.
  • Where will the JS wrapper code come from? With emscripten, it's produced as an output from the toolchain. wasm32-unknown-unknown only produces the binary module, and stdweb's webcore module will want to write the code of js! sections (or something to pick it up for exec-ing) somewhere. Who will describe that interface, and which component will be responsible for putting that code into a JavaScript file that'll then be served alongside the wasm file? Can/should the macros write out to a file?

@chrysn
Copy link
Contributor

chrysn commented Nov 29, 2017

The first issue seems to be an actual Rust bug (see rust-lang/rust#46367 -- workaround: run with --release); with that, my patched branch of cargo-web can now serve -unknown-unknown crates provided they ship a bespoke index.html.

@koute
Copy link
Owner

koute commented Nov 29, 2017

I'll probably get to this in a few days myself, but it's nice someone else is taking a stab!

Where will the JS wrapper code come from?

@chrysn: Yes, well, that's the million dollar question. (:

Right now this is definitely an open question; AFAIK for the js! macro to work you probably have to generate a .js file alongside the wasm, as wasm can indeed call into JS, but only if JS itself explicitly exports its methods to wasm. That will probably require at least some support from the Rust compiler itself. (...in theory it could be done externally, but that would be so hacky I don't really want to go there)

That said, I'd quite welcome any work you've already done on cargo-web for this and will be glad to merge it if you create a PR.

@badboy
Copy link

badboy commented Nov 29, 2017

We got you covered, at least we want to provide the necessary wrapper implementations. A js! macro would actually be not too complicated (for now it could be implemented by calling an extern function which evals the code)

@koute
Copy link
Owner

koute commented Nov 29, 2017

@badboy Yeah, at first a simple eval function would be enough for experimenting with having js! working, which is exactly what I was thinking of doing. I could (for now) hardcode this into cargo-web just to get something going.

@chrysn
Copy link
Contributor

chrysn commented Nov 30, 2017

AFAICT @badboy's wasm-experiments only wrap JS->Rust calls while eval would be Rust->JS. Let me see whether I can conjure something up. In the meantime, see #16 for a minimal pull request (probably more of a discussion starter, but feel free to merge if you deem it suitable).

@chrysn
Copy link
Contributor

chrysn commented Dec 3, 2017

Transporting JS derived from Rust to populate the importObject is indeed tricky. So far, I've inspected all files that rustc can --emit, and only the MIR (unsuitable for automated processing) contains #[used] const strings with potential JS code. That approach should have been used for generating a table entry for each JS fragment emitted from Rust, and they could have been transported in a dedicated section into the object file. They wouldn't be present in the WASM file (because that's linked and the respective section is not part of the linker script, if such a thing exists in the toolchain), but could be read by cargo web and inserted into the importObject. That might all get easier when there is a linker involved in the whole process.

Asking the question of how often we'll actually need custom callbacks (which IMO would be superior to just going through exec every time), I discovered that wasm32-unknown-unknown already uses some callbacks and defines them in a dedicated .js file. I'm looking into how this can be shipped via cargo web, because most probably it should -- at least the function definitions, because otherwise, anything that calls (10.0_f32).acos() will throw a linker error in the browser with the default index.html.

@koute
Copy link
Owner

koute commented Dec 11, 2017

@chrysn I've figured out how to relatively easily extract JS snippets from wasm bytecode and automatically generate an .js file with them, and I've already made a lot of progress, so you can expect full support for wasm in both stdweb and cargo-web Very Soon™. (:

@koute
Copy link
Owner

koute commented Dec 16, 2017

I'm happy to announce wasm32-unknown-unknown is now supported!

@chrysn For now I've had to delete the math function imports which you've contributed; I'd love to add those again, but I have no idea what actually requires them - perhaps you know how I could make the compiler generate code that requires them?

@koute koute closed this as completed Dec 16, 2017
@chrysn
Copy link
Contributor

chrysn commented Dec 17, 2017

@koute, my example program:

pub extern "C" fn divide(modulus: f32) -> () {
    demo::eval("console.log('Hello, World!');");
    let x = 10.2_f64 % (modulus as f64);
    demo::eval(&format!("console.log({});", x));
}

currently gives: LinkError: import object field 'fmod' is not a Function

The classical floating point functions are often statically optimized, so testing needs to ensure that they are not; the trig functions (eg. atan) aren't even optimized away, so you can test them w/o enforcing run-time evaluation.

@koute
Copy link
Owner

koute commented Dec 17, 2017

@chrysn Thanks!

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

4 participants