Skip to content

Commit 925338a

Browse files
authored
strip .so files by default (#210)
This brings the default size of e.g. the CLI example from ~40MB down to ~18MB.
1 parent ffa5a08 commit 925338a

File tree

2 files changed

+82
-8
lines changed

2 files changed

+82
-8
lines changed

Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,8 @@ tar = "0.4.41"
7979
zstd = "0.13.2"
8080
test-generator = { path = "test-generator" }
8181
flate2 = "1.1.1"
82+
wasmparser = "0.245.0"
83+
wasm-encoder = "0.245.0"
8284

8385
[workspace]
8486
members = ["runtime", "test-generator"]

build.rs

Lines changed: 80 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,20 @@ use {
66
env,
77
fmt::Write as _,
88
fs::{self, File},
9-
io::{self, Write},
10-
iter,
9+
io::{self, Cursor, Write},
10+
iter, mem,
1111
path::{Path, PathBuf},
1212
process::Command,
1313
},
1414
tar::Builder,
15+
wasm_encoder::{ComponentSectionId, Encode as _, RawSection, Section as _},
16+
wasmparser::{Parser, Payload},
1517
zstd::Encoder,
1618
};
1719

18-
const ZSTD_COMPRESSION_LEVEL: i32 = 19;
20+
const DEBUG_RUNTIME: bool = false;
21+
const STRIP_RUNTIME: bool = !DEBUG_RUNTIME;
22+
const ZSTD_COMPRESSION_LEVEL: i32 = if DEBUG_RUNTIME { 0 } else { 19 };
1923
const DEFAULT_SDK_VERSION: &str = "30";
2024

2125
// SQLite version to build - 3.51.2 (latest as of Jan 2026)
@@ -249,7 +253,11 @@ fn compress(src_dir: &Path, name: &str, dst_dir: &Path, rerun_if_changed: bool)
249253
File::create(dst_dir.join(format!("{name}.zst")))?,
250254
ZSTD_COMPRESSION_LEVEL,
251255
)?;
252-
io::copy(&mut File::open(path)?, &mut encoder)?;
256+
if STRIP_RUNTIME && name.ends_with(".so") {
257+
io::copy(&mut Cursor::new(strip(&fs::read(path)?)?), &mut encoder)?;
258+
} else {
259+
io::copy(&mut File::open(path)?, &mut encoder)?;
260+
}
253261
encoder.do_finish()?;
254262
Ok(())
255263
} else {
@@ -485,9 +493,12 @@ fn make_runtime(
485493
.arg("build")
486494
.arg("-Z")
487495
.arg("build-std=panic_abort,std")
488-
.arg("--release")
489496
.arg("--target=wasm32-wasip1");
490497

498+
if !DEBUG_RUNTIME {
499+
cmd.arg("--release");
500+
}
501+
491502
if async_ {
492503
cmd.arg("--features=async");
493504
}
@@ -515,9 +526,10 @@ fn make_runtime(
515526
assert!(status.success());
516527
println!("cargo:rerun-if-changed=runtime");
517528

518-
let path = out_dir
519-
.join(target)
520-
.join("wasm32-wasip1/release/libcomponentize_py_runtime.a");
529+
let build = if DEBUG_RUNTIME { "debug" } else { "release" };
530+
let path = out_dir.join(target).join(format!(
531+
"wasm32-wasip1/{build}/libcomponentize_py_runtime.a"
532+
));
521533

522534
if path.exists() {
523535
let clang = wasi_sdk.join(format!("bin/{CLANG_EXECUTABLE}"));
@@ -726,3 +738,63 @@ fn build_sqlite(wasi_sdk: &Path, install_dir: &Path) -> Result<()> {
726738

727739
Ok(())
728740
}
741+
742+
fn strip(input: &[u8]) -> anyhow::Result<Vec<u8>> {
743+
// Adapted from https://github.com/bytecodealliance/wasm-tools/blob/main/src/bin/wasm-tools/strip.rs
744+
//
745+
// TODO: Move that code into e.g. `wasm_encoder` so we can reuse it here
746+
// instead of duplicating it.
747+
748+
let mut output = Vec::new();
749+
let mut stack = Vec::new();
750+
751+
for payload in Parser::new(0).parse_all(input) {
752+
let payload = payload?;
753+
754+
// Track nesting depth, so that we don't mess with inner producer sections:
755+
match payload {
756+
Payload::Version { encoding, .. } => {
757+
output.extend_from_slice(match encoding {
758+
wasmparser::Encoding::Component => &wasm_encoder::Component::HEADER,
759+
wasmparser::Encoding::Module => &wasm_encoder::Module::HEADER,
760+
});
761+
}
762+
Payload::ModuleSection { .. } | Payload::ComponentSection { .. } => {
763+
stack.push(mem::take(&mut output));
764+
continue;
765+
}
766+
Payload::End { .. } => {
767+
let mut parent = match stack.pop() {
768+
Some(c) => c,
769+
None => break,
770+
};
771+
if output.starts_with(&wasm_encoder::Component::HEADER) {
772+
parent.push(ComponentSectionId::Component as u8);
773+
output.encode(&mut parent);
774+
} else {
775+
parent.push(ComponentSectionId::CoreModule as u8);
776+
output.encode(&mut parent);
777+
}
778+
output = parent;
779+
}
780+
_ => {}
781+
}
782+
783+
if let Payload::CustomSection(ref c) = payload {
784+
let name = c.name();
785+
if name != "name" && !name.starts_with("component-type:") && name != "dylink.0" {
786+
continue;
787+
}
788+
}
789+
790+
if let Some((id, range)) = payload.as_section() {
791+
RawSection {
792+
id,
793+
data: &input[range],
794+
}
795+
.append_to(&mut output);
796+
}
797+
}
798+
799+
Ok(output)
800+
}

0 commit comments

Comments
 (0)