Skip to content

Commit da75db4

Browse files
committed
add async and WASIp3 support
This adds basic support for async exports, async imports, streams, and futures. See the new `http-p3` example for a practical demonstration. This does not include support for cancelling subtasks, reads, or writes. That shouldn't be difficult to add, but can wait until a later PR. I've also used this opportunity to update the Rust edition to 2024, update some deps, and reflow some comments. Signed-off-by: Joel Dice <joel.dice@fermyon.com>
1 parent c9ccc9a commit da75db4

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

62 files changed

+7054
-1345
lines changed

Cargo.lock

Lines changed: 1127 additions & 815 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "componentize-py"
3-
version = "0.18.0"
3+
version = "0.19.0"
44
edition = "2024"
55
exclude = ["cpython"]
66

@@ -14,23 +14,24 @@ clap = { version = "4.5.20", features = ["derive"] }
1414
tar = "0.4.42"
1515
tempfile = "3.13.0"
1616
zstd = "0.13.2"
17-
# TODO: switch to wasm-tools 1.241.0 when available
18-
wasm-encoder = { git = "https://github.com/bytecodealliance/wasm-tools", rev = "b1d8ff59" }
19-
wit-dylib = { git = "https://github.com/bytecodealliance/wasm-tools", rev = "b1d8ff59" }
20-
wit-parser = { git = "https://github.com/bytecodealliance/wasm-tools", rev = "b1d8ff59" }
21-
wit-component = { git = "https://github.com/bytecodealliance/wasm-tools", rev = "b1d8ff59" }
22-
wasmparser = { git = "https://github.com/bytecodealliance/wasm-tools", rev = "b1d8ff59" }
17+
# TODO: switch to wasm-tools release once https://github.com/bytecodealliance/wasm-tools/pull/2367 has been merged and released
18+
wasm-encoder = { git = "https://github.com/dicej/wasm-tools", rev = "416c5da7" }
19+
wit-dylib = { git = "https://github.com/dicej/wasm-tools", rev = "416c5da7" }
20+
wit-parser = { git = "https://github.com/dicej/wasm-tools", rev = "416c5da7" }
21+
wit-component = { git = "https://github.com/dicej/wasm-tools", rev = "416c5da7" }
22+
wasmparser = { git = "https://github.com/dicej/wasm-tools", rev = "416c5da7" }
2323
indexmap = "2.6.0"
2424
bincode = "1.3.3"
2525
heck = "0.5.0"
2626
pyo3 = { version = "0.26.0", features = [
2727
"abi3-py39",
2828
"extension-module",
2929
], optional = true }
30-
wasmtime = { version = "37.0.2", features = [ "component-model-async" ] }
31-
wasmtime-wasi = "37.0.2"
30+
# TODO: switch to wasmtime 39.0.x when available
31+
wasmtime = { git = "https://github.com/bytecodealliance/wasmtime", rev = "efd56f68", features = [ "component-model-async" ] }
32+
wasmtime-wasi = { git = "https://github.com/bytecodealliance/wasmtime", rev = "efd56f68", features = [ "p3" ] }
3233
once_cell = "1.20.2"
33-
component-init-transform = { git = "https://github.com/dicej/component-init", rev = "3b9680fe" }
34+
component-init-transform = { git = "https://github.com/dicej/component-init", rev = "2d965957" }
3435
async-trait = "0.1.83"
3536
futures = "0.3.31"
3637
tokio = { version = "1.41.0", features = [
@@ -82,3 +83,4 @@ flate2 = "1.1.1"
8283

8384
[workspace]
8485
members = ["runtime", "test-generator"]
86+

build.rs

Lines changed: 89 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,8 @@ fn stubs_for_clippy(out_dir: &Path) -> Result<()> {
5252
);
5353

5454
let files = [
55-
"libcomponentize_py_runtime.so.zst",
55+
"libcomponentize_py_runtime_sync.so.zst",
56+
"libcomponentize_py_runtime_async.so.zst",
5657
"libpython3.14.so.zst",
5758
"libc.so.zst",
5859
"libwasi-emulated-mman.so.zst",
@@ -103,62 +104,20 @@ fn package_all_the_things(out_dir: &Path) -> Result<()> {
103104

104105
make_pyo3_config(&repo_dir)?;
105106

106-
let mut cmd = Command::new("rustup");
107-
cmd.current_dir("runtime")
108-
.arg("run")
109-
.arg("nightly")
110-
.arg("cargo")
111-
.arg("build")
112-
.arg("-Z")
113-
.arg("build-std=panic_abort,std")
114-
.arg("--release")
115-
.arg("--target=wasm32-wasip1");
116-
117-
for (key, _) in env::vars_os() {
118-
if key
119-
.to_str()
120-
.map(|key| key.starts_with("RUST") || key.starts_with("CARGO"))
121-
.unwrap_or(false)
122-
{
123-
cmd.env_remove(&key);
124-
}
125-
}
126-
127-
cmd.env(
128-
"RUSTFLAGS",
129-
"-C relocation-model=pic --cfg pyo3_disable_reference_pool",
130-
)
131-
.env("CARGO_TARGET_DIR", out_dir)
132-
.env("PYO3_CONFIG_FILE", out_dir.join("pyo3-config.txt"));
133-
134-
let status = cmd.status()?;
135-
assert!(status.success());
136-
println!("cargo:rerun-if-changed=runtime");
137-
138-
let path = out_dir.join("wasm32-wasip1/release/libcomponentize_py_runtime.a");
139-
140-
if path.exists() {
141-
let clang = wasi_sdk.join(format!("bin/{CLANG_EXECUTABLE}"));
142-
if clang.exists() {
143-
let name = "libcomponentize_py_runtime.so";
144-
145-
run(Command::new(clang)
146-
.arg("-shared")
147-
.arg("-o")
148-
.arg(out_dir.join(name))
149-
.arg("-Wl,--whole-archive")
150-
.arg(&path)
151-
.arg("-Wl,--no-whole-archive")
152-
.arg(format!("-L{}", cpython_wasi_dir.to_str().unwrap()))
153-
.arg("-lpython3.14"))?;
154-
155-
compress(out_dir, name, out_dir, false)?;
156-
} else {
157-
bail!("no such file: {}", clang.display())
158-
}
159-
} else {
160-
bail!("no such file: {}", path.display())
161-
}
107+
make_runtime(
108+
out_dir,
109+
&wasi_sdk,
110+
&cpython_wasi_dir,
111+
false,
112+
"libcomponentize_py_runtime_sync.so",
113+
)?;
114+
make_runtime(
115+
out_dir,
116+
&wasi_sdk,
117+
&cpython_wasi_dir,
118+
true,
119+
"libcomponentize_py_runtime_async.so",
120+
)?;
162121

163122
let libraries = [
164123
"libc.so",
@@ -406,6 +365,79 @@ fn make_pyo3_config(repo_dir: &Path) -> Result<()> {
406365
Ok(())
407366
}
408367

368+
fn make_runtime(
369+
out_dir: &Path,
370+
wasi_sdk: &Path,
371+
cpython_wasi_dir: &Path,
372+
async_: bool,
373+
name: &str,
374+
) -> Result<()> {
375+
let mut cmd = Command::new("rustup");
376+
cmd.current_dir("runtime")
377+
.arg("run")
378+
.arg("nightly")
379+
.arg("cargo")
380+
.arg("build")
381+
.arg("-Z")
382+
.arg("build-std=panic_abort,std")
383+
.arg("--release")
384+
.arg("--target=wasm32-wasip1");
385+
386+
if async_ {
387+
cmd.arg("--features=async");
388+
}
389+
390+
for (key, _) in env::vars_os() {
391+
if key
392+
.to_str()
393+
.map(|key| key.starts_with("RUST") || key.starts_with("CARGO"))
394+
.unwrap_or(false)
395+
{
396+
cmd.env_remove(&key);
397+
}
398+
}
399+
400+
let target = if async_ { "async" } else { "sync" };
401+
402+
cmd.env(
403+
"RUSTFLAGS",
404+
"-C relocation-model=pic --cfg pyo3_disable_reference_pool",
405+
)
406+
.env("CARGO_TARGET_DIR", out_dir.join(target))
407+
.env("PYO3_CONFIG_FILE", out_dir.join("pyo3-config.txt"));
408+
409+
let status = cmd.status()?;
410+
assert!(status.success());
411+
println!("cargo:rerun-if-changed=runtime");
412+
413+
let path = out_dir
414+
.join(target)
415+
.join("wasm32-wasip1/release/libcomponentize_py_runtime.a");
416+
417+
if path.exists() {
418+
let clang = wasi_sdk.join(format!("bin/{CLANG_EXECUTABLE}"));
419+
if clang.exists() {
420+
run(Command::new(clang)
421+
.arg("-shared")
422+
.arg("-o")
423+
.arg(out_dir.join(name))
424+
.arg("-Wl,--whole-archive")
425+
.arg(&path)
426+
.arg("-Wl,--no-whole-archive")
427+
.arg(format!("-L{}", cpython_wasi_dir.to_str().unwrap()))
428+
.arg("-lpython3.14"))?;
429+
430+
compress(out_dir, name, out_dir, false)?;
431+
} else {
432+
bail!("no such file: {}", clang.display())
433+
}
434+
} else {
435+
bail!("no such file: {}", path.display())
436+
}
437+
438+
Ok(())
439+
}
440+
409441
fn fetch_extract(url: &str, out_dir: &Path) -> Result<()> {
410442
let response = reqwest::blocking::get(url)?;
411443
let decoder = flate2::read::GzDecoder::new(response);

0 commit comments

Comments
 (0)