-
Notifications
You must be signed in to change notification settings - Fork 59
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
Status of rust+C bindings for wasm targets #291
Comments
@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. |
* rust-bitcoin/master: Fix no-std raw test, after removal of lang items Fix broken benchmarks Disable emscripten tests until they work again rust-lang/rust#66916 rustwasm/team#291 Add constant of the prime of the curve field. Simplify callback logic to returning raw coordinates Removed no longer used dont_replace_c_symbols feature Fix wrong feature name external-symbols Fix missing return c_int in NonceFn
I am also struggling to compile simple c libraries like imgui to wasm. |
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, Of course, you can't expect to use both 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. |
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
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.
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 |
Yeah, i probably could successfully compile rust with emscripten, but wasm-bindgen absence seems like a showstopper.
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.
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. |
Yeah that's true, for that you need some minimal stdlib and it's quite unfortunate that 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: ebiggers/libdeflate@27d5a74 Alternatively, in other cases, you can build C / C++ against |
It's probably possible, but it seems like too much work to do for the whole imgui.
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?
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. |
I simply used cargo wasi build, and got the same stdlib errors. |
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. |
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. |
according to this rustwasm/wasm-pack#621 (comment)
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? |
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
|
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 |
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 |
@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: rustwasm/wasm-bindgen#2209. |
Yes, it has nothing to do with malloc/no_std/etc, it has to do with the ABI of passing structs by ownership to functions. |
For compiling to # Script assumes you have clang, cmake, and ninja available locally
# Also note I needed mmap support, so I added -D_WASI_EMULATED_MMAN and -lwasi-emulated-mman below
# Set up wasi-sdk
WASI_SDK_VERSION_TAG=wasi-sdk-17
WASI_SDK_ROOT=wasi-sdk
git clone --recursive --branch $WASI_SDK_VERSION_TAG https://github.com/WebAssembly/wasi-sdk $WASI_SDK_ROOT
(cd $WASI_SDK_ROOT && make package)
# Configure environment variables for cargo build
WASI_SDK_PATH=$WASI_SDK_ROOT/build/install/opt/wasi-sdk
WASI_SDK_PATH=`realpath $WASI_SDK_PATH`
export CC="$WASI_SDK_PATH/bin/clang -D_WASI_EMULATED_MMAN --sysroot=$WASI_SDK_PATH/share/wasi-sysroot"
export LLD="$WASI_SDK_PATH/bin/lld -lwasi-emulated-mman"
export LD="$LLD"
export AR="$WASI_SDK_PATH/bin/llvm-ar"
export NM="$WASI_SDK_PATH/bin/llvm-nm"
# Build for web
TARGET=wasm32-wasi
rustup target add $TARGET
cargo build -r --target=$TARGET |
I've been trying to get a Rust codebase that uses tree-sitter to compile to Wasm. I eventually got it to work using Zig's toolchain for C compilation:
However, it appears that the wasm file expects the tree-sitter code to be imported via the
Does anybody know if there's some way to link it all together so that the |
You may want to check whether that problem also arises when just using C code. My experience (at least with using the |
Thanks for the response! I'm not sure what you mean by just using C code. Do you mean when running natively? Because it does work then. I suppose I can try building this with a stub of C code and see if it works with webassembly. |
@NicholasLYang I’m actually trying to do something very similar with rust and tree-sitter - were you able to figure anything out? |
@amckinney did you ever figure it out? currently struggling with rust wasm and tree-sitter |
@vedkothavade try with https://github.com/shadaj/tree-sitter-c2rust! This is how rust-sitter supports wasm32-unknown-unknown. |
thanks @shadaj! i was able to get tree-sitter-c2rust itself to build, but languages themselves fail to compile (eg. tree-sitter-c). i locally cloned the language repo and replaced the tree-sitter dep in Cargo.toml and build.rs with tree-sitter-c2rust and still am getting errors such as ( edit: actually, i think that the clang errors i'm getting might be in part due to some nix weirdness going on, will have to investigate further--let me know if you've seen any CC errors when building languages though, maybe it will help |
@vedkothavade sorry for the late response! Yeah, we've seen this in Rust Sitter. We get around this by including minimal stub implementations of those headers, see https://github.com/hydro-project/rust-sitter/blob/main/tool/src/lib.rs#L67. |
@shadaj thanks! |
If you arrived here while searching how to compile Rust+C for the |
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 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 rust-lang/rust#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) rust-lang/cc-rs#378so
wasm-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)
The text was updated successfully, but these errors were encountered: