https://github.com/rafaelbeckel/test-c-rust-wasm
Rust+C WASM compilation under the same binary for the `wasm32-unknown-unknown` target
https://github.com/rafaelbeckel/test-c-rust-wasm
c cpp llvm rust wasm wasm-bindgen
Last synced: about 2 months ago
JSON representation
Rust+C WASM compilation under the same binary for the `wasm32-unknown-unknown` target
- Host: GitHub
- URL: https://github.com/rafaelbeckel/test-c-rust-wasm
- Owner: rafaelbeckel
- Created: 2024-05-28T10:55:40.000Z (almost 2 years ago)
- Default Branch: master
- Last Pushed: 2025-10-08T01:17:23.000Z (6 months ago)
- Last Synced: 2025-10-08T03:19:08.801Z (6 months ago)
- Topics: c, cpp, llvm, rust, wasm, wasm-bindgen
- Language: Rust
- Homepage: https://github.com/rafaelbeckel/test-c-rust-wasm
- Size: 146 KB
- Stars: 52
- Watchers: 3
- Forks: 2
- Open Issues: 3
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# Rust+C in the same WASM binary
This repository was originally created to test the state of Rust nightly for producing a compatible C ABI for the `wasm32-unknown-unknown` target with the flag `--Z wasm_c_abi=spec`.
Now [Rust v1.89](https://blog.rust-lang.org/2025/08/07/Rust-1.89.0/#standards-compliant-c-abi-on-the-wasm32-unknown-unknown-target) officially uses the "C" ABI by default.
For context, this is the [relevant tracking issue](https://github.com/rustwasm/wasm-bindgen/issues/3454) in Wasm Bingen, and the [official Rust blog post](https://blog.rust-lang.org/2025/04/04/c-abi-changes-for-wasm32-unknown-unknown/) talking about this.
## Description
The workspace contains a series of small examples of how to produce a single WASM binary with both C and Rust code that can call each other.
To see how to do it, check out the `build.sh` file in each of the crates in this workspace.
## Build Strategies
The crates experiment with different build strategies, with increasing levels of complexity:
1. [Linking Manually](crates/1_linking_manually)
- A simple calculator with primitive data types and manual build
2. [With CC Crate](crates/2_with_cc)
- The same calculator built with the [CC crate](https://docs.rs/cc/1.0.101/cc/)
3. [Libc and Heap](crates/3_libc_and_heap_allocation)
- We use [OpenBSD libc](https://github.com/trevyn/wasm32-unknown-unknown-openbsd-libc) to implement the Mem function in the calculator and store/free a value in the heap from C with `malloc` and `free`
4. [Wasm Bindgen](crates/4_wasm_bindgen/)
- We create a Calculator struct with member functions and export it with [Wasm Bindgen](https://github.com/rustwasm/wasm-bindgen)
5. [Rust Bindgen](crates/5_rust_bindgen/)
- This is the same as the previous project, but instead of writing the Calculator struct manually, we generate the Rust bindings from the C header with [Rust Bindgen](https://rust-lang.github.io/rust-bindgen/), which is the recommended way to interact with C code from Rust.
6. [Extern Types](crates/6_extern_types/)
- This project experiments with the nightly feature `extern types`.
## Running
To see the examples in action, use your favorite local server:
```bash
npx serve
```
Then, visit `http://localhost:3000` and click the example you want to see.
## Building
Either visit the specific crate and run its `build.sh` script or use the `build_all.sh` script in the root of the workspace to build all crates at once.
### Dependencies
- [LLVM](https://llvm.org/)
- [Clang](https://clang.llvm.org/)
- [Rust](https://www.rust-lang.org/) (1.89 or later)
- [Wasm Binary Toolkit](https://github.com/WebAssembly/wabt)
## Future plans
1. Uniffi
- I plan to add an example with Uniffi in the future.
2. Wgpu
- I have used these strategies in my work to build a `wgpu` project that depends on C libraries. I plan to bring a minimal example of it here.
3. Combine different crates in a build script
- C code coming from a crate and Rust code from another, link them by using linker flags in build.rs.
4. External C libs
- Finally, let's bring an external C lib and combine all of the above.
## Contributing
If you'd like to see any other scenario listed here, feel free to open an Issue or a PR.
If submitting a new example, create a numbered subfolder in the `crates` directory following the existing structure, and ensure your example builds correctly for both WASM and unit tests.
Finally, run `cargo clippy` and stick with the default rules.