Open elichai opened 4 years ago
@tlively has made a lot of progress on the emscripten side of things, and I think can update on the status there.
Currently the wasm32-unknown-emscripten and asmjs-unknown-emscripten targets are the only targets that can be linked with C code because all the other wasm targets use a different ABI for compatibility with wasm-bindgen. Unfortunately, I’m the only one maintaining the emscripten targets in Rust and I don’t have a lot of time to spend on it, so I’ve mostly just been trying to fix critical bugs as I become aware of them. I’ll take a look at the one you linked to above.
I am also struggling to compile simple c libraries like imgui to wasm. @alexcrichton maybe you could help us, and share couple of words on how to build wasm32-unknown-unknown with wasi sysroot, or some other way? Or building rust+C to wasm is a lost cause for near future?
If you want to integrate Rust and C on the web your best bet is likely going to be Emscripten. The next best bet is going to be using WASI (and wasi-sdk), but that requires getting a WASI implementation working on the best which isn't always as available. Finally you can try to get wasm32-unknown-unknown working. While that's technically possible for C/C++ there aren't really any maintained toolchains targeting that for C/C++, so you're on your own making such a toolchain.
Well, wasm32-emscripten target doesn't get much love from rust community either. Anyway, thanks for reply, it's nice to know status of these things.
Hi, I'm a WebAssembly DevRel at Google and thought I'd chime as I've actively worked with both Rust (including wasm-bindgen) and Emscripten at various points.
Admittedly, this is a simple demo, but, as far as I can tell, wasm32-unknown-emscripten
target works fine for combined Rust + C code.
Of course, you can't expect to use both #[wasm_bindgen]
and Emscripten bindings at the same time - you need to choose a single tool that will be providing runtime bindings and generating the JavaScript wrapper - but as long as one side is a "driver" and another contains pure portable code, things should work.
Is there a specific API or minimal code sample you could show that you're struggling with?
Wow, thanks for offering help. My problem is compiling imgui-rs crate to wasm32-unknown-unknown target, i have no idea how to solve this, because my c++ knowledge is pretty limited. As of emsripten, stuff like https://github.com/rust-lang/rust/issues/66916 doesn't give much confidence. Also stdweb, which supports emscripten target, seems abandoned (no activity for 8 months). Also, I do you use wasm_bindgen quite extensively. For example, how would i replace wasm-bindgen-futures crate and work with js promises from inside rust, if i choose to use wasm32-unknown-emscripten?
I can't say much about cargo-web TBH because while I've seen it, personally never used it. In example above you can see that I'm just using regular cargo build
command instead.
As of emsripten, stuff like rust-lang/rust#66916 doesn't give much confidence.
I haven't seen that error, and given that 1) it's from half a year ago and 2) examples I've tried work fine, I suspect it might have been some temporary issue that has been resolved since.
Also, I do you use wasm_bindgen quite extensively. For example, how would i replace wasm-bindgen-futures crate and work with js promises from inside rust, if i choose to use wasm32-unknown-emscripten?
Right, unfortunately, you can't, since these are two different toolchains. You need to either deal with Web APIs and JS values from Emscripten, or from Rust, but not both.
I've experimented in the past with using Embind in Rust (shameless plug: https://www.youtube.com/watch?v=zxIbTfsOJZE), but not too long afterwards wasm-bindgen appeared and it wasn't clear if there are benefits to using both, so never made it into a full package. Either way, if really necessary, it should be possible to build your own bindings from Rust to Emscripten's APIs or vice versa, but that would be complicated.
It might be easier to understand what issues you're running into with wasm32-unknown-unknown
for your particular library, but that's probably best discussed in an issue on imgui-rs
repo where author could chime in too and probably help out.
Yeah, i probably could successfully compile rust with emscripten, but wasm-bindgen absence seems like a showstopper.
It might be easier to understand what issues you're running into with wasm32-unknown-unknown for your particular library, but that's probably best discussed in an issue on imgui-rs repo where author could chime in too and probably help out.
The thing is, my issues aren't specific to this library. When you compile any c library that uses standard headers like stdio.h or string.h you get compilation errors. https://github.com/servo/rust-stb-image/issues/94 https://github.com/alexcrichton/cc-rs/issues/378#issuecomment-469331613 I tried manually inserting headers from wasi-libc, and including them into cc build, but then i got linking errors like
note: rust-lld: error: unable to find library -lstdc++
Imgui doesn't really need any os-specific stuff to work, i've seen it compiled with emscripten on the web, but i have no idea how to make it work with wasm32-unknown-unknown.
When you compile any c library that uses standard headers like stdio.h or string.h you get compilation errors.
Yeah that's true, for that you need some minimal stdlib and it's quite unfortunate that wasm32-unknown-unknown
in Clang doesn't include any.
That said, this situation is not unique to WebAssembly, but also happens in embedded targets which often don't have full stdlib either. I've found that often enough you can send PRs and make upstream code rely only on portable headers. E.g. you can see this commit on libdeflate where I made some of the headers-related changes: https://github.com/ebiggers/libdeflate/commit/27d5a74f03a8f01aca0e63235bfce5670da963a2
Alternatively, in other cases, you can build C / C++ against wasm32-wasi
target instead. If you know that you won't be calling any actual I/O APIs anyway and only need the basics like string.h
, then this is often a simple enough option that just works.
I've found that often enough you can send PRs and make upstream code rely only on portable headers.
It's probably possible, but it seems like too much work to do for the whole imgui.
If you know that you won't be calling any actual I/O APIs anyway and only need the basics like string.h, then this is often a simple enough option that just works.
Well, i just tried to build imgui-rs to wasm32-wasi, and i get exactly the same errors about not having string.h and friends :) Also if i could compile to wasm32-wasi, could i run it inside browser?
Well, i just tried to build imgui-rs to wasm32-wasi, and i get exactly the same errors about not having string.h and friends :)
That's weird, wasm32-wasi definitely has these libraries. Did you install and use WASI SDK that was mentioned above?
Also if i could compile to wasm32-wasi, could i run it inside browser?
As I said, only if you're sure that no I/O will be called and you only need basic headers and functions, otherwise things get a bit more complicated.
That's weird, wasm32-wasi definitely has these libraries. Did you install and use WASI SDK that was mentioned above?
I simply used cargo wasi build, and got the same stdlib errors. Forgive my ignorance, but i'm not sure how would i use wasi sdk to build rust+c code?
Well, i just tried to build imgui-rs to wasm32-wasi, and i get exactly the same errors about not having string.h and friends :)
That's weird, wasm32-wasi definitely has these libraries. Did you install and use WASI SDK that was mentioned above?
So does Emscripten, for that matter. The tricky bit here seems to be that the rust toolchain driver projects do not know how to properly build C/C++ libraries targeting Emscripten (or WASI??). It's more effort, but it should work to build the C/C++ static library separately using Emscripten then pass that library to rustc to link in.
So does Emscripten, for that matter.
Yeah but the difference is that Emscripten also generates surrounding runtime JS code, which we explicitly don't need or want in this case, so WASI SDK is a more lightweight option.
It's more effort, but it should work to build the C/C++ static library separately using Emscripten then pass that library to rustc to link in
according to this https://github.com/rustwasm/wasm-pack/issues/621#issuecomment-481703973 emscripten compiler would be incompatible with wasm32-unknown-unknown target my goal is to build wasm32-unknown-unknown (or wasi?) target, use wasm-bindgen, and still have the ability to link to c library.
WASI SDK is a more lightweight option.
As far as i understand, i should use clang directly to build imgui cpp source code with sysroot from wasi-sdk, and later link that to rust? Can you give me more specific instructions please?
I just tried to build wasm32-wasi target passing --sysroot=[path_to_my_build_of_wasi_sysroot] flag to cc::Build, and still i get
my goal is to build wasm32-unknown-unknown (or wasi?) target, use wasm-bindgen, and still have the ability to link to c library.
You cannot do this.
The only way to mix Rust and C code when targeting WebAssembly is to use the wasm32-unknown-emscripten target. You cannot use wasm-bindgen when you do that because wasm-bindgen is fundamentally incompatible with C. Using WASI will not work. There is no workaround. There are long term plans to make wasm32-unknown-unknown and wasm32-wasi compatible with C, but there is no ETA for that.
Source: https://github.com/rust-lang/rust/blob/master/src/librustc_target/abi/call/mod.rs#L599-L601
The only way to mix Rust and C code when targeting WebAssembly is to use the wasm32-unknown-emscripten target. You cannot use wasm-bindgen when you do that because wasm-bindgen is fundamentally incompatible with C.
This is definitely not true. As I mentioned above, you can go the other way around as well, as long as your C / C++ is not doing any I/O that requires corresponding JS bindings - this is the only limitation that is hard to work around.
See the libdeflate
example above as well which is written in C, but I've used it in a Rust project with wasm-bindgen in Squoosh.
Here's a slightly modified variation of my example above, that uses wasm-bindgen instead of Emscripten for JS interactions, but still combines Rust + C in the same way:
@RReverser only the wasm32-unknown-emscripten target uses the real C ABI for FFI. All the other targets, including WASI, use the different wasm32_bindgen_compat ABI. You've been lucky that your C interop has happened to work, but in general this will not be the case.
@tlively Ah, I've missed that nuance. From looking at implementation, it seems that the primary difference is in layout of aggregate parameters / results (structs by value and such)? That's probably why I've never run into issues with it before, but I agree it's risky.
I have a PR to document this problem that points back to this issue here: https://github.com/rustwasm/wasm-bindgen/pull/2209.
FWIW, I have, for many months now, been building a project that uses ring with its "wasm32_c" feature, using clang-10 as the compiler. I had to be careful to not pass structures by value between C and Rust due to the ABI issue, but it has been working great up until I tried to upgrade to clang-11. When using clang-11 as the C compiler, the generated .wasm files all have imports from "env" for the C symbols that were previously resolved to the static library within ring.
I am curious what has changed in clang-11 that would stop things from working.
@briansmith I don't know offhand of any changes that would cause something like that to break. Can you provide before and after commands that I could run to reproduce the problem?
https://github.com/rust-lang/rust/pull/79998 landed, meaning this should be supported/working for the wasm32-wasi target, though not yet for wasm32-unknown-unknown.
@TheBlueMatt Thanks for linking to that discussion, very interesting. I hope the wasm-bindgen changes @devsnek is working on will work out and we'll get C ABI fixed for wasm32-unknown-unknown without waiting for the multi-value ABI update 🤞
rust-lang/rust#79998 landed, meaning this should be supported/working for the wasm32-wasi target, though not yet for wasm32-unknown-unknown.
What is the reason Why is wasm32-wasi is being treated differently from wasm32-unknown-unknown?
I have a project that doesn't use wasm-bindgen at all directly, because it is an rlib that is used by other projects that use wasm-bindgen. I don't see the advantage of having the fix for wasm32-unknown-unknown being in wasm-bindgen given that projects that don't use wasm-bindgen also need this fixed.
@devsnek just wrote in this PR for wasm-bindgen (https://github.com/rust-lang/rust-bindgen/pull/1952#issuecomment-758868681):
We landed a fix for wasm32-wasi in rustc, so this is now only needed for wasm32-unknown-unknown. Since I'm personally targeting wasi, it is unlikely that I will finish this PR.
Without knowing the motivation for wanting to fix wasm32-unknown-unknown a different way, it seems in the abstract that it seems wasteful to have a completely different fix for wasm32-unknown-unknown than wasn32-wasi.
What is the reason Why is wasm32-wasi is being treated differently from wasm32-unknown-unknown?
If my understanding is correct, in order to use the C ABI in wasm_bindgen, changes need to happen on wasm_bindgen. There is some promise of work by devsnek to do so, at which point the same ABI change will also happen to wasm32-unknown-unknown, making everything C compatible. Until then (though it may all end up in the same release), there is value in having some option for those of us who wish to use C and Rust code in WASM but do not need wasm_bindgen. Given wasi already is a little dubious due to C/Rust cross-usage, it makes sense to go ahead and apply the change to that target (instead of, say, creating a new target only to have it be removed when wasm_bindgen is updated).
If my understanding is correct, in order to use the C ABI in wasm_bindgen, changes need to happen on wasm_bindgen.
Are you saying that even if we were to try to use the fix for wasm32-wasi to fix wasm32-unknown-unknown, wasm_bindgen would still need to change?
even if we were to try to use the fix for wasm32-wasi to fix wasm32-unknown-unknown, wasm_bindgen would still need to change
Not even, it precisely needs to change to be compatible with the fixed ABI. Without those fixes, changing wasm32-unknown-unknown ABI to the correct one will break wasm-bindgen users.
Are you saying that even if we were to try to use the fix for wasm32-wasi to fix wasm32-unknown-unknown, wasm_bindgen would still need to change?
Yes, this whole thing is because wasm_bindgen has some more clever idea of what the WASM ABI should be than clang. Thus, wasm32-unknown-unkonwn is set to match wasm_bindgen, but there needed to be something which matched clang for C interop. With current git head, that is now wasm32-wasi, with wasm32-unknown-unkonwn left unchanged to match the wasm_bindgen ABI expectations. I guess now the wasm_bindgen changes are up for grabs, but it sounded like at least Alex was down with changing wasm_bindgen to just expect the clang-compatible ABI.
I wouldn't call either way a "fix" per se - its just two separate ABIs, neither is really "right" or "wrong" just "incompatible".
Thus, wasm32-unknown-unkonwn is set to match wasm_bindgen, but there needed to be something which matched clang for C interop.
I think quite a few projects are using wasm32-unknown-unknown with its current level of C-Rust interop already; they just avoid passing structures by value between Rust and C. The problem I am trying to solve is that this is considered "unsupported" at least until this ABI change is made. But I actually don't even need the ABI change since I never pass aggregate structures by value. It would be sufficient for me, and perhaps for other projects, if we started "supporting" wasm32-unknown-unknown without insisting that this ABI change is made.
Alternatively, although this might not work for other wasm32-unknown-unknown users, it would also work for my particular case if wasm32-wasi was supported in the context of web browser extensions with with some minimal, lightweight, wasm32-wasi environment available for us to use; the only library we need is __wasi_random_get. Is there an effort underway to provide this? If so, the demand for wasm32-unknown-unknown support might just go away.
some minimal, lightweight, wasm32-wasi environment available for us to use; the only library we need is __wasi_random_get. Is there an effort underway to provide this? If so, the demand for wasm32-unknown-unknown support might just go away.
https://github.com/rustwasm/wasm-pack/issues/654 is an issue tracking wasm32-wasi for wasm-pack, which isn't implemented yet, and which would be required for projects migrating from -unknown-unknown to -wasi.
if we started "supporting" wasm32-unknown-unknown without insisting that this ABI change is made.
I'm no rustc contributor, so I can't speak for anyone, but presumably that's not something anyone plans on breaking, but given the lack of time it seems like regular contributors have available to change wasm_bindgen, I don't think anyone has the time to add a new thing to the "officially supported" list. If you want it to be "supported", just watch the PR flow to make sure it doesn't break in the future :)
the only library we need is __wasi_random_get. Is there an effort underway to provide this? If so, the demand for wasm32-unknown-unknown support might just go away
FWIW from this it sounds like you indeed want a WASI target rather than wasm32-unknown-unknown
. __wasi_random_get
is not something that needs to be provided on the Rust side - it's up to the WASI execution environment to provide a corresponding syscall implementation.
it's up to the WASI execution environment to provide a corresponding syscall implementation.
That's what I'm asking for: is anybody working on a WASI execution environment for use within a web browser extension like uBlock Origin?
is anybody working on a WASI execution environment for use within a web browser extension like uBlock Origin
There's couple of WASI execution environments for the browser in different state of readiness (even I built one: https://github.com/GoogleChromeLabs/wasi-fs-access), but they're probably overkill for your usecase if you only need random implementation.
You can quite easily implement such "environment" / binding in a few lines yourself - see https://github.com/GoogleChromeLabs/wasi-fs-access/blob/d621cefc26a57209228b8f36f502616d3828bb5c/src/bindings.ts#L412-L416 for inspiration.
Has there been any progress on this since January? (explicityly: C interop with wasm32-unknown-unknown
)
I think I saw @alexcrichton doing some further work on aligning interop under a feature in rustc but not sure if it made it to stable Rust yet?
Hi @RReverser, a bit off topic but I was trying to run this code and kept getting a Uncaught Error: Cannot find module 'env'
... seems that the problem is this line in /pkg/rs.js: imports['env'] = require('env');
. Any clues please? Thank you!
Here's a slightly modified variation of my example above, that uses wasm-bindgen instead of Emscripten for JS interactions, but still combines Rust + C in the same way:
Here's a slightly modified variation of my example above, that uses wasm-bindgen instead of Emscripten for JS interactions, but still combines Rust + C in the same way:
error: linking with
emcc
failed: exit status: 1 | = note: "emcc" "-s" "EXPORTED_FUNCTIONS=[\"_main\",\"_test_invoke_cpp\",\"_rust_eh_personality\"]" "/gh/prehonor/CProject/bookmarks_test_cc/target/wasm32-unknown-emscripten/debug/deps/bookmarks_test.1zt35b637p30e23c.rcgu.o" "/gh/prehonor/CProject/bookmarks_test_cc/target/wasm32-unknown-emscripten/debug/deps/bookmarks_test.243yktfgnti058s.rcgu.o" "/gh/prehonor/CProject/bookmarks_test_cc/target/wasm32-unknown-emscripten/debug/deps/bookmarks_test.2a9kwce6t89mft6r.rcgu.o" "/gh/prehonor/CProject/bookmarks_test_cc/target/wasm32-unknown-emscripten/debug/deps/bookmarks_test.2z2pks3t6vsj4hkk.rcgu.o" "/gh/prehonor/CProject/bookmarks_test_cc/target/wasm32-unknown-emscripten/debug/deps/bookmarks_test.36860bziyiy5cvl.rcgu.o" "/gh/prehonor/CProject/bookmarks_test_cc/target/wasm32-unknown-emscripten/debug/deps/bookmarks_test.49kc1169thitggcs.rcgu.o" "/gh/prehonor/CProject/bookmarks_test_cc/target/wasm32-unknown-emscripten/debug/deps/bookmarks_test.4aunakts9t0q8z1l.rcgu.o" "/gh/prehonor/CProject/bookmarks_test_cc/target/wasm32-unknown-emscripten/debug/deps/bookmarks_test.4wfhoqsroghu99wi.rcgu.o" "/gh/prehonor/CProject/bookmarks_test_cc/target/wasm32-unknown-emscripten/debug/deps/bookmarks_test.7q4wrp4319020j0.rcgu.o" "/gh/prehonor/CProject/bookmarks_test_cc/target/wasm32-unknown-emscripten/debug/deps/bookmarks_test.mngym9vxcykk1p6.rcgu.o" "/gh/prehonor/CProject/bookmarks_test_cc/target/wasm32-unknown-emscripten/debug/deps/bookmarks_test.qj64dmrn8ov4e8u.rcgu.o" "/gh/prehonor/CProject/bookmarks_test_cc/target/wasm32-unknown-emscripten/debug/deps/bookmarks_test.12mv00qfwubtsih0.rcgu.o" "-L" "/gh/prehonor/CProject/bookmarks_test_cc/target/wasm32-unknown-emscripten/debug/deps" "-L" "/gh/prehonor/CProject/bookmarks_test_cc/target/debug/deps" "-L" "/gh/prehonor/CProject/bookmarks_test_cc/target/wasm32-unknown-emscripten/debug/build/bookmarks_test-68e0abdcab42ce34/out" "-L" "/home/prehonor/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/wasm32-unknown-emscripten/lib" "-l" "add" "/home/prehonor/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/wasm32-unknown-emscripten/lib/libstd-bdf7176c8a0dd833.rlib" "/home/prehonor/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/wasm32-unknown-emscripten/lib/libpanic_unwind-c70f927a8f048f20.rlib" "/home/prehonor/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/wasm32-unknown-emscripten/lib/libstd_detect-393f12da1976f45f.rlib" "/home/prehonor/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/wasm32-unknown-emscripten/lib/librustc_demangle-6dcb3726c5a42cf3.rlib" "/home/prehonor/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/wasm32-unknown-emscripten/lib/libhashbrown-9bc5b46025ae3bc3.rlib" "/home/prehonor/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/wasm32-unknown-emscripten/lib/librustc_std_workspace_alloc-6fe9f65b51decf4b.rlib" "/home/prehonor/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/wasm32-unknown-emscripten/lib/libunwind-1b099c6338bbcc10.rlib" "/home/prehonor/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/wasm32-unknown-emscripten/lib/libcfg_if-dbff1947880a2590.rlib" "/home/prehonor/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/wasm32-unknown-emscripten/lib/liblibc-3e2ff821d678d3bb.rlib" "/home/prehonor/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/wasm32-unknown-emscripten/lib/liballoc-92a42921c4e08bd8.rlib" "/home/prehonor/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/wasm32-unknown-emscripten/lib/librustc_std_workspace_core-576f79f783431afc.rlib" "/home/prehonor/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/wasm32-unknown-emscripten/lib/libcore-5bd5cf806585fd45.rlib" "/home/prehonor/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/wasm32-unknown-emscripten/lib/libcompiler_builtins-40a69e0c0e852207.rlib" "-l" "c" "-s" "DISABLE_EXCEPTION_CATCHING=0" "-L" "/home/prehonor/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/wasm32-unknown-emscripten/lib" "-L" "/home/prehonor/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/wasm32-unknown-emscripten/lib/self-contained" "-o" "/gh/prehonor/CProject/bookmarks_test_cc/target/wasm32-unknown-emscripten/debug/deps/bookmarks_test.js" "-O0" "--memory-init-file" "0" "-g4" "-s" "DEFAULT_LIBRARY_FUNCS_TO_INCLUDE=[]" "-s" "ERROR_ON_UNDEFINED_SYMBOLS=1" "-s" "ASSERTIONS=1" "-s" "ABORTING_MALLOC=0" "-Wl,--fatal-warnings" = note: emcc: warning: please replace -g4 with -gsource-map [-Wdeprecated] wasm-ld: error: unknown file type: add.o emcc: error: '/gh/prehonor/gitproject/emsdk/upstream/bin/wasm-ld -o /gh/prehonor/CProject/bookmarks_test_cc/target/wasm32-unknown-emscripten/debug/deps/bookmarks_test.wasm /gh/prehonor/CProject/bookmarks_test_cc/target/wasm32-unknown-emscripten/debug/deps/bookmarks_test.1zt35b637p30e23c.rcgu.o /gh/prehonor/CProject/bookmarks_test_cc/target/wasm32-unknown-emscripten/debug/deps/bookmarks_test.243yktfgnti058s.rcgu.o /gh/prehonor/CProject/bookmarks_test_cc/target/wasm32-unknown-emscripten/debug/deps/bookmarks_test.2a9kwce6t89mft6r.rcgu.o /gh/prehonor/CProject/bookmarks_test_cc/target/wasm32-unknown-emscripten/debug/deps/bookmarks_test.2z2pks3t6vsj4hkk.rcgu.o /gh/prehonor/CProject/bookmarks_test_cc/target/wasm32-unknown-emscripten/debug/deps/bookmarks_test.36860bziyiy5cvl.rcgu.o /gh/prehonor/CProject/bookmarks_test_cc/target/wasm32-unknown-emscripten/debug/deps/bookmarks_test.49kc1169thitggcs.rcgu.o /gh/prehonor/CProject/bookmarks_test_cc/target/wasm32-unknown-emscripten/debug/deps/bookmarks_test.4aunakts9t0q8z1l.rcgu.o /gh/prehonor/CProject/bookmarks_test_cc/target/wasm32-unknown-emscripten/debug/deps/bookmarks_test.4wfhoqsroghu99wi.rcgu.o /gh/prehonor/CProject/bookmarks_test_cc/target/wasm32-unknown-emscripten/debug/deps/bookmarks_test.7q4wrp4319020j0.rcgu.o /gh/prehonor/CProject/bookmarks_test_cc/target/wasm32-unknown-emscripten/debug/deps/bookmarks_test.mngym9vxcykk1p6.rcgu.o /gh/prehonor/CProject/bookmarks_test_cc/target/wasm32-unknown-emscripten/debug/deps/bookmarks_test.qj64dmrn8ov4e8u.rcgu.o /gh/prehonor/CProject/bookmarks_test_cc/target/wasm32-unknown-emscripten/debug/deps/bookmarks_test.12mv00qfwubtsih0.rcgu.o -L/gh/prehonor/CProject/bookmarks_test_cc/target/wasm32-unknown-emscripten/debug/deps -L/gh/prehonor/CProject/bookmarks_test_cc/target/debug/deps -L/gh/prehonor/CProject/bookmarks_test_cc/target/wasm32-unknown-emscripten/debug/build/bookmarks_test-68e0abdcab42ce34/out -L/home/prehonor/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/wasm32-unknown-emscripten/lib /gh/prehonor/CProject/bookmarks_test_cc/target/wasm32-unknown-emscripten/debug/build/bookmarks_test-68e0abdcab42ce34/out/libadd.a /home/prehonor/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/wasm32-unknown-emscripten/lib/libstd-bdf7176c8a0dd833.rlib /home/prehonor/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/wasm32-unknown-emscripten/lib/libpanic_unwind-c70f927a8f048f20.rlib /home/prehonor/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/wasm32-unknown-emscripten/lib/libstd_detect-393f12da1976f45f.rlib /home/prehonor/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/wasm32-unknown-emscripten/lib/librustc_demangle-6dcb3726c5a42cf3.rlib /home/prehonor/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/wasm32-unknown-emscripten/lib/libhashbrown-9bc5b46025ae3bc3.rlib /home/prehonor/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/wasm32-unknown-emscripten/lib/librustc_std_workspace_alloc-6fe9f65b51decf4b.rlib /home/prehonor/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/wasm32-unknown-emscripten/lib/libunwind-1b099c6338bbcc10.rlib /home/prehonor/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/wasm32-unknown-emscripten/lib/libcfg_if-dbff1947880a2590.rlib /home/prehonor/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/wasm32-unknown-emscripten/lib/liblibc-3e2ff821d678d3bb.rlib /home/prehonor/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/wasm32-unknown-emscripten/lib/liballoc-92a42921c4e08bd8.rlib /home/prehonor/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/wasm32-unknown-emscripten/lib/librustc_std_workspace_core-576f79f783431afc.rlib /home/prehonor/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/wasm32-unknown-emscripten/lib/libcore-5bd5cf806585fd45.rlib /home/prehonor/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/wasm32-unknown-emscripten/lib/libcompiler_builtins-40a69e0c0e852207.rlib -lc -L/home/prehonor/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/wasm32-unknown-emscripten/lib -L/home/prehonor/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/wasm32-unknown-emscripten/lib/self-contained --fatal-warnings -L/gh/prehonor/gitproject/emsdk/upstream/emscripten/cache/sysroot/lib/wasm32-emscripten -lGL -lal -lhtml5 -lc -lcompiler_rt -lc++ -lc++abi -ldlmalloc -lc_rt_wasm -lsockets -mllvm -combiner-global-alias-analysis=false -mllvm -enable-emscripten-cxx-exceptions -mllvm -enable-emscripten-sjlj -mllvm -disable-lsr --import-undefined --export-if-defined=main --export-if-defined=test_invoke_cpp --export-if-defined=rust_eh_personality --export-if-defined=emscripten_stack_get_end --export-if-defined=emscripten_stack_get_free --export-if-defined=emscripten_stack_init --export-if-defined=stackSave --export-if-defined=stackRestore --export-if-defined=stackAlloc --export-if-defined=wasm_call_ctors --export-if-defined=fflush --export-if-defined=errno_location --export-if-defined=malloc --export-if-defined=free --export-if-defined=cxa_is_pointer_type --export-if-defined=__cxa_can_catch --export-if-defined=setThrew --export-if-defined=ntohs --export-if-defined=htonl --export-if-defined=htons --export-if-defined=emscripten_main_thread_process_queued_calls --export-if-defined=sysconf --export-if-defined=start_em_asm --export-if-defined=__stop_em_asm --export-table -z stack-size=5242880 --initial-memory=16777216 --no-entry --max-memory=16777216 --global-base=1024' failed (returned 1)
Hi, I'm a WebAssembly DevRel at Google and thought I'd chime as I've actively worked with both Rust (including wasm-bindgen) and Emscripten at various points.
Admittedly, this is a simple demo, but, as far as I can tell,
wasm32-unknown-emscripten
target works fine for combined Rust + C code.Of course, you can't expect to use both
#[wasm_bindgen]
and Emscripten bindings at the same time - you need to choose a single tool that will be providing runtime bindings and generating the JavaScript wrapper - but as long as one side is a "driver" and another contains pure portable code, things should work.Is there a specific API or minimal code sample you could show that you're struggling with?
asm-pack build --target nodejs Error: crate-type must be cdylib to compile to wasm32-unknown-unknown. Add the following to your Cargo.toml file:
[lib] crate-type = ["cdylib", "rlib"]
my cargo.toml
[package] name = "bookmarks_test" version = "0.1.0" authors = ["prehonor ryx666@sina.cn"] edition = "2018" build = "build.rs"
[lib] crate-type = ["cdylib", "rlib"]
[dependencies]
wasm-bindgen = "*"
[build-dependencies] cc = "*"
This is still kind of difficult with WASM.
I get rust-lld
error, even when using clean Ubuntu (WSL). Currently I have very plain setup:
apt install llvm-dev libclang-dev clang
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh
Error I get when running wasm-pack build
error: linking with `rust-lld` failed: exit status: 1
... note: rust-lld: error: /mnt/c/DepSource/FreeType-Wasm-RS/freetypewasm/target/wasm32-unknown-unknown/release/build/freetypewasm-2bc08b83a54e5a95/out/libtest.a: archive has no index; run ranlib to add one
AFAIU, you cannot use wasm-pack with C stuff included. wasm-pack uses a different target, and currently linking C is only supported with the wasi target.
@TheBlueMatt thanks. This is all confusing.
I don't know where I even need wasm-pack if Rust can do it too? Of course wasm-pack generates the nice JS wrapper I usually need. Maybe I can generate the JS wrapper with wasm-pack and compile with plain rust?
It almost compiles with emscripten... But not quiet:
$ cargo build --target wasm32-unknown-emscripten --release
note: wasm-ld: error: function signature mismatch: emscripten_memcpy_big
>>> defined as (i32, i32, i32) -> void in /emsdk/upstream/emscripten/cache/sysroot/lib/wasm32-emscripten/libc-debug.a(emscripten_memcpy.o)
>>> defined as (i32, i32, i32) -> i32 in /emsdk/upstream/emscripten/cache/sysroot/lib/wasm32-emscripten/libstandalonewasm.a(standalone.o)
Btw, I get same error with wasi target too as with wasm-pack?
$ cargo build --target wasm32-wasi
error: linking with `rust-lld` failed: exit status: 1
note: rust-lld: error: /home/jarppa/projects/freetypewasm/target/wasm32-wasi/debug/build/freetypewasm-bb71202e81378ddf/out/libtest.a: archive has no index; run ranlib to add one
@Ciantic
note: wasm-ld: error: function signature mismatch: emscripten_memcpy_big
That specific error was recently fixed in emscripten, https://github.com/emscripten-core/emscripten/pull/17212 There hasn't been a release yet with that change, but you can try it with a tip of tree build (emsdk install tot
).
It almost compiles with emscripten... But not quiet:
That is precisely the issue tracked as https://github.com/rustwasm/wasm-pack/issues/654. You have to use the wasm32-wasi target to get clang/rust ABI compatibility in wasm.
Hi, There are a lot of important dependencies in the rust ecosystem that use ffi to C fia the
cc
crate or similiar. which tools and targets currently support that? in the pastasmjs-unknown-emscripten
worked and together withcargo-web
you could just runcargo web test
to know if your library compiles+run on wasm/emscripten. Sadly emscripten is broken on stable for a while now https://github.com/rust-lang/rust/issues/66916.wasm32-unknown-unknown works in combination with
clang-8
only(probably a bug), not before and not later(doesn't work on clang-9 and clang-10) https://github.com/alexcrichton/cc-rs/issues/378 sowasm-pack
can't be used here.wasi
seem to have the same problem, runningcargo wasi test
fails to find the sysroot(fatal error: 'string.h' file not found
) although it seems like you can download sysroots for wasi or compile them yourself https://bytecodealliance.github.io/wasmtime/wasm-c.htmlIs there any tool out there that can test rust+C code out of the box? (We had emscripten tests in the CI until it broke and we want to continue testing for wasm target in the CI)