rustwasm / team

A point of coordination for all things Rust and WebAssembly
MIT License
1.45k stars 59 forks source link

Status of rust+C bindings for wasm targets #291

Open elichai opened 4 years ago

elichai commented 4 years ago

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 past asmjs-unknown-emscripten worked and together with cargo-web you could just run cargo 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 so wasm-pack can't be used here.

wasi seem to have the same problem, running cargo 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.html

Is 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)

kripken commented 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.

tlively commented 4 years ago

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.

DzmitryFil commented 4 years ago

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?

alexcrichton commented 4 years ago

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.

DzmitryFil commented 4 years ago

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.

RReverser commented 4 years ago

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?

DzmitryFil commented 4 years ago

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?

RReverser commented 4 years ago

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.

DzmitryFil commented 4 years ago

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.

RReverser commented 4 years ago

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.

DzmitryFil commented 4 years ago

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?

RReverser commented 4 years ago

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.

DzmitryFil commented 4 years ago

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?

tlively commented 4 years ago

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.

RReverser commented 4 years ago

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.

DzmitryFil commented 4 years ago

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?

DzmitryFil commented 4 years ago

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

tlively commented 4 years ago

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

RReverser commented 4 years ago

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.

RReverser commented 4 years ago

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:

image

tlively commented 4 years ago

@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.

RReverser commented 4 years ago

@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.

tlively commented 4 years ago

I have a PR to document this problem that points back to this issue here: https://github.com/rustwasm/wasm-bindgen/pull/2209.

briansmith commented 3 years ago

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.

tlively commented 3 years ago

@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?

TheBlueMatt commented 3 years ago

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.

RReverser commented 3 years ago

@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 🤞

briansmith commented 3 years ago

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.

briansmith commented 3 years ago

@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.

TheBlueMatt commented 3 years ago

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).

briansmith commented 3 years ago

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?

RReverser commented 3 years ago

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.

TheBlueMatt commented 3 years ago

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".

briansmith commented 3 years ago

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.

briansmith commented 3 years ago

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.

TheBlueMatt commented 3 years ago

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 :)

RReverser commented 3 years ago

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.

briansmith commented 3 years ago

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?

RReverser commented 3 years ago

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.

theduke commented 3 years ago

Has there been any progress on this since January? (explicityly: C interop with wasm32-unknown-unknown)

RReverser commented 3 years ago

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?

maninkari commented 3 years ago

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:

image

prehonor commented 3 years ago

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:

image 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)

prehonor commented 3 years ago

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]

libc = "*"

wasm-bindgen = "*"

[build-dependencies] cc = "*"

Ciantic commented 2 years ago

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

image

TheBlueMatt commented 2 years ago

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.

Ciantic commented 2 years ago

@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?

Ciantic commented 2 years ago

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
kripken commented 2 years ago

@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).

TheBlueMatt commented 2 years ago

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.