-
Notifications
You must be signed in to change notification settings - Fork 12.9k
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
Allow linking JS libraries to Emscripten target #41409
Conversation
Thanks for the pull request, and welcome! The Rust team is excited to review your changes, and you should hear from @pnkfelix (or someone else) soon. If any changes to this PR are deemed necessary, please add them as extra commits. This ensures that the reviewer can see what has changed since they last reviewed the code. Due to the way GitHub handles out-of-date commits, this should also make it reasonably obvious what issues have or haven't been addressed. Large or tricky changes may require several passes of review and changes. Please see the contribution instructions for more information. |
Awesome thanks for the PR @RReverser! This is an interesting question actually to me. The intention of So more generally, all linkage directives have a particular If we need to add support for JS libs specially I'd be tempted to add |
Idk, personally to me it seems more reasonable to reuse the existing From the code at least, it seemed that the |
Yeah it's true, and I wouldn't mind much about using |
@alexcrichton |
Ok let's see if others from @rust-lang/tools have an opinion. Any thoughts on using the @RReverser so this shows a bug on |
I'm fine with that. |
@alexcrichton It's intentional, as Emscripten doesn't perform search in We could, of course, implement such search ourselves, but I'm not sure it's worth it and seems easier just to let crates provide absolute paths on their own. |
Ok cool makes sense to me, mind changing |
Ah sure. Should I just use |
Ideally something like It may be a case where when constructing the linker object the |
Sorry, but what is ICE? |
Oh apologies! ICE == "Internal compiler error", you can explore the issue tracker for examples. |
Ah ok. |
Ok I've decided to use |
Hm does this patch work locally for your? I'd expect these lines to cause problems. |
Argh, you're probably right and I should've waited for the actual build rather than sending modifications from Github. Let me recheck everything. |
Ok fixed and actually checked that it works now. For example:
#[link(name = "hello-lib.js", kind = "framework")]
extern {
fn hello();
}
fn main() {
unsafe { hello() }
}
mergeInto(LibraryManager.library, {
hello: function() { console.log('hello world') }
}); To compile: $ ./build/x86_64-apple-darwin/stage2/bin/rustc --target=asmjs-unknown-emscripten hello.rs
$ node hello
hello world |
Btw, regarding checks: is it just me or changing a single line in the linker really requires rebuilding entire Rust from scratch? I've tried all the suggested and possible configs to avoid rebuilding stdlib, keeping stage 0, make builds incremental etc., but it either didn't compile with them or just didn't have any effect. For example, the last rebuild for the fix above took 2 hours on my machine. |
Ok everything seems to work / pass now. @alexcrichton |
Also retested with putting JS dependency in library crate, and using it as dependency in another one - something that was not possible before even with |
Looks good to me, thanks @RReverser!
Unfortunately due to the way Rust bootstraps itself any change will unconditionally require a compilation of the entire compiler at least once (typically ~1.5x depending on where the change was located). You can typically work around with with manual cleaning and manual "touch this file back into th 1990s" but it gets hazardous. I'll give a few more days for @rust-lang/tools to weigh in, but I think we're likely to merge this. |
@Diggsey Adding completely new kind with such interaction would require an overhaul of a quite big part of the compiler, while suggested solution piggybacks on an existing method already used for platform-specific functionality. Also unclear - what would be the point to specify |
@RReverser It would have no purpose on other platforms. However, other platforms may have more than one platform-specific link kind. Rather than having the compiler be aware of each platform-specific link kind, it would make more sense to teach it to recognise any platform-specific link kind, and to pass it through. |
Yeah but it still needs to know how to convert link paths to the actual linker, linkers don't just accept some generic JSON or raw link(...) metadata, it has to be normalized on Rust side. Otherwise this sounds like just link_args which already exists but doesn't work for this use case. |
Another point to consider here is that, whatever the solution is, it is not appropriate for it to be insta-stable. Even if we were to re-purpose "framework", which I think we should not, it should still be feature-gated. Perhaps "js" is not forward-compatible enough. I don't know. Adding a general platform-specific linkage mechanism as suggested by @Diggsey starts to sound RFC-worthy. Another approach would be to add a new general-purpase linker args mechanism, if |
@RReverser My preference is still to add a "js" linkage type and put it behind a feature gate. As a minor gated feature, we can try to get it in without going to a full RFC (though it is bending the rules, I think it's an obscure, and small, enough experimental thing that it doesn't matter all that much), and reevaluate it before stabilization. Will you make that change? |
Indeed, in any case I just wanted to have some feature available in nightly that users could play with - not an "insta-stable" one.
Oh yeah, I could totally just feature-gate the existing change if that was proposed earlier :)
Other than that, yeah, by now I'm happy with whichever outcome, although don't know how much work it takes to add a new linkage kind on all levels - let me try. |
Should I reuse E0455 but change the extended diagnostic message to "Linking with this |
@brson @alexcrichton Updated a PR with the suggested approach (except the question above remains, for now it just uses same error code, didn't even change the error message - which way's preferred?). |
Thanks @RReverser! This looks great to me. I think reusing the error code in this case is ok, but you can update the associated text if you'd like as well. Looks like tidy is failing I believe though? |
Friendly ping to keep this on your radar @RReverser! Looks like this tidy failure still needs to be fixed? Let us know if you need help or have any questions! ❤️
|
Yeah, thanks! But apart from that, there is one more thing I don't like about current implementation and will still look into fixing - in particular, I want to pack |
Just going to jump in here quickly and say this is sorely needed for any Emscripten target. I have a production app that we're looking at targeting with Emscripten + Rust, however the only thing that works currently is link_flags which is behind a feature gate in nightly. We can't use the nightly compiler since we want consistent builds. Anything more than the most trivial Emscripten usage is going to want to use the C API for deeper interop. |
@RReverser Looks like Travis is failing; did you have a chance to look into the static packing of |
I'm afraid this feature won't help you either then, as it will be also behind nightly feature gate (at least for a while). |
@vvanders You can probably use RUSTFLAGS to pass custom arguments to the linker:
Or for something more permanent you can put the rustflags in a project local # .cargo/config
[target.wasm32-unknown-emscripten]
rustflags = [
"-C", "link-arg=--js-library",
"-C", "link-arg=whatever",
] This should work on stable. |
Just a heads up: I'm now trying instead to bring some changes upstream in Emscripten itself which should make this PR either much easier or not needed at all. |
@japaric That did the trick, thanks! Hopefully it'll help anyone else who stumbles across this. |
@RReverser is there a place to link to for the emscripten changes as well? |
Still waiting for feedback on the issue (emscripten-core/emscripten#5221) plus there were apparently two previous PRs that tried to implement that. All of them are linked above by Github. I guess let me just close this for now to avoid confusion and reopen later with proper implementation (with static linking) either on Rust side or on Emscripten one. |
Are there any new commits base on this? |
@tigercosmos See the linked issue above. Unfortunately, it's very slow to get any contributions into Emscripten, so I put more hope into the new native Rust support for WASM (although that one is still in flux too). |
@RReverser any ideas on when this feature will be available? |
This allows crates to inject own JS functions they want to link to in Rust code, without using link_args hack which is not possible to populate from build script with computed path.
"Framework" seems to be most suitable section for such JS code.
See https://kripken.github.io/emscripten-site/docs/porting/connecting_cpp_and_javascript/Interacting-with-code.html for more details on --js-library feature.
This is a follow up to #39490.
Fixes #38492.