Custom Python Builds
Build a custom Python/WASM runtime when the stock boomslang_host.call(...) bridge is too blunt. A custom build changes the Rust/WASI guest inside boomslang.wasm; it is independent of whether the outside host is Java, Rust, or another language.
Use one for:
- typed WASM imports instead of string/JSON calls
- host functions exposed as custom Python modules
- extra Python modules prewarmed into the Wizer snapshot
- native libraries required by Python extensions (WASI has no dynamic linking — native code must be statically linked into the guest)
The runnable starting point is examples/custom-python-build/.
The build flow
- Declare an extension contract in your extension crate’s
build.rswith theboomslang-hostgenDSL. boomslang-hostgenemits the Rust guest code and an ABI JSON file at build time.- Generate host-language bridge code from the ABI JSON (Java or Rust adapters).
- Compose the extension with
boomslang-host-corein a custom guest crate. - Add any required native static libraries to the WASI build.
- Build the guest to
wasm32-wasip1. - Package the custom
boomslang.wasmand matching Python resources with your app. - For Java packaging, depend on
com.hubspot:boomslangwith theno-python-runtimeclassifier.
Declaring an extension
// my-ext/build.rs
fn main() {
let ext = boomslang_hostgen::ExtensionSpec::new("myext")
.wasm_module("myext")
.prewarm(["_myext"])
.function("do_thing", |f| {
f.param("input", boomslang_hostgen::Type::String)
.returns(boomslang_hostgen::Type::String)
});
boomslang_hostgen::Build::new(ext)
.emit()
.generate()
.expect("generate myext");
println!("cargo:rerun-if-changed=build.rs");
}
#![allow(unused)]
fn main() {
// my-ext/src/lib.rs
include!(concat!(env!("OUT_DIR"), "/ext_myext.rs"));
}
Register it alongside the stock host bridge in your guest crate:
#![allow(unused)]
fn main() {
boomslang_host_core::init(
|| {
boomslang_ext_host_bridge::register();
my_extension::register();
},
|py| {
boomslang_ext_host_bridge::prewarm(py);
my_extension::prewarm(py);
},
);
}
And build:
export CPYTHON_WASI_DIR=../../cpython/build/cpython-wasi # or omit to download from GitHub Releases
cargo build --target wasm32-wasip1 --release
Generating host adapters
Run the hostgen CLI against the ABI JSON your build emitted:
# Java hosts
boomslang-hostgen myext.abi.json --java-out src/main/java --java-package com.example.generated
# Rust/Wasmtime hosts
boomslang-hostgen myext.abi.json --rust-host-out src/generated
The generated Java class exposes typed functional interfaces and a builder — you only fill in implementations:
var extension = MyextHostFunctions.builder()
.withDoThing(input -> "result from Java")
.buildExtension();
PythonExecutorFactory factory = PythonExecutorFactory
.builder()
.withStdlibPath(pythonRoot)
.addExtension(extension)
.build();
Python code then imports the extension as a real module:
from myext import do_thing
print(do_thing("hello"))
Async functions (f.r#async() in the DSL) generate CompletionStage<String> handlers on the Java side; see Async host calls.
The full DSL surface and the ABI JSON contract are documented in the reference section.