Skip to content

Instantly share code, notes, and snippets.

@helje5
Last active April 7, 2024 13:38
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save helje5/f1d5a2860293ed7646ea3b2ebed0f976 to your computer and use it in GitHub Desktop.
Save helje5/f1d5a2860293ed7646ea3b2ebed0f976 to your computer and use it in GitHub Desktop.
Compile a Sum Rust Function

Install rust using rustup

brew install rustup
rustup-init
# new shell for env (or source .cargo/env), then:
rustup target add wasm32-wasi

Compile Cowsay

git clone https://github.com/wapm-packages/cowsay
cd cowsay
cargo build --target wasm32-wasi --release

gives:

Updating crates.io index
Downloaded atty v0.2.14
...
Compiling cowsay v0.1.0 (/private/tmp/cowsay)
warning: use of deprecated function `rand::sample`: renamed to seq::sample_iter
...
warning: `cowsay` (bin "cowsay") generated 5 warnings (run `cargo fix --bin "cowsay"` to apply 2 suggestions)
  Finished release [optimized] target(s) in 9.62s

Cowsay is smaller? Hm.

du -sh target/wasm32-wasi/release/cowsay.wasm
712K	target/wasm32-wasi/release/cowsay.wasm

But still 712k vs 4k for the native binary, aka 178⨯ the size.

ls -lh /opt/homebrew/Cellar/cowsay/3.04_1/bin/cowsay
-rwxr-xr-x  1 helge  admin   4.1K Mar  8  2023 /opt/homebrew/Cellar/cowsay/3.04_1/bin/cowsay

Well, I initially thought, but then I wondered and:

otool -L /opt/homebrew/Cellar/cowsay/3.04_1/bin/cowsay
/opt/homebrew/Cellar/cowsay/3.04_1/bin/cowsay: is not an object file

head -n 4 /opt/homebrew/Cellar/cowsay/3.04_1/bin/cowsay
#!/usr/bin/perl

##
## Cowsay 3.03

🙈

So let's try this cowsay.c:

curl -o cowsay.c https://raw.githubusercontent.com/0xAether/ccowsay/master/cowsay.c
clang -O3 cowsay.c -o cowsay
ls -lh cowsay 
-rwxr-xr-x  1 helge  wheel    50K Apr  7 12:21 cowsay

But still 712k vs 50k for the native binary, aka 14⨯ the size.

Compile Own Rust Lib

helge@M2ni /tmp % cargo new --lib sum
     Created library `sum` package
helge@M2ni /tmp % cd sum

Add this to Cargo.toml:

[lib]
crate-type = ["cdylib"]

And replace lib.rs w/ the sum function:

#[no_mangle]
extern "C" fn sum(a: i32, b: i32) -> i32 {
  let s = a + b;
  println!("From WASM: Sum is: {:?}", s);
  s
}

Release Build yields a stunning 1.6MB:

cargo build --release --target wasm32-wasi
du -sh target/wasm32-wasi/release/sum.wasm
1.6M	target/wasm32-wasi/release/sum.wasm

OK, maybe it is just what "print" adds? Let's see:

#[no_mangle]
extern "C" fn sum(a: i32, b: i32) -> i32 {
  let s = a + b;
  // println removed
  s
}
cargo build --release --target wasm32-wasi
du -sh target/wasm32-wasi/release/sum.wasm
1.6M	target/wasm32-wasi/release/sum.wasm

OK, as shown by @codertrix the thing has to be explicitly stripped, adding this to the Cargo.toml yields to the expected result:

[profile.release]
opt-level = "z"
strip = "symbols"
lto = true
panic = "abort"
codegen-units = 1

Gives:

ls -lh target/wasm32-wasi/release/sum.wasm
-rwxr-xr-x  1 helge  wheel   108B Apr  7 15:31 target/wasm32-wasi/release/sum.wasm

108 bytes, no we are talking!

Still a little much for what is adding two numbers, but let's assume this is just a common .wasm framing overhead. Adding an identical second function sum2 adds 19 bytes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment