Reputation: 51
I have a cargo workspace organized like this:
Cargo.toml
|-foo
| |-Cargo.toml
| -src
| |-main.rs
|-foo-runtime
| |-Cargo.toml
| -src
| |-lib.rs
|-target
main.rs
has code somewhere that looks like
use std::sync::LazyLock;
use wasmer::{imports, Instance, Module, Store};
static RUNTIME_WASM: &[u8] = include_bytes!(???);
static INSTANCE: LazyLock<wasmer::Instance> = LazyLock::new(|| {
let mut store = Store::default();
let module = Module::from_binary(&store, RUNTIME_WASM)
.unwrap_or_else(|e| panic!("couldn't load WASM module: {e}"));
let import_object = imports! {};
Instance::new(&mut store, &module, &import_object)
.unwrap_or_else(|e| panic!("failed to create wasmer Instance: {e}"))
});
while lib.rs
has code that looks like
#[no_mangle]
pub extern fn add_i64(a: i64, b: i64) -> i64 {
a + b
}
foo-runtime/Cargo.toml
looks like
cargo-features = ["per-package-target"]
[package]
default-target = "wasm32-unknown-unknown"
[lib]
crate-type = ["cdylib"]
so that cargo build
on the foo-runtime
crate produces target/wasm32-unknown-unknown/debug/foo_runtime.wasm
. So far so good.
Now I want the rust binary crate foo
to depend on the foo-runtime
crate and in particular be able to include foo_runtime.wasm
at compile-time, possibly using include_bytes!()
as above. Loading at runtime would also be fine, but the questions in either case are (1) how do I correctly construct the path to foo_runtime.wasm
during compile- (or run-) time in main.rs
; and (2) how do I trigger all the necessary rebuilds when something in the dependencies changes?
I had thought the bindeps
cargo experimental feature was the answer, but adding this to foo
's Cargo.toml
[dependencies]
foo-runtime = { path = "../foo-runtime", artifact = "cdylib", target = "wasm32-unknown-unknown" }
doesn't work because this only causes cargo to compile a .so/.dylib
shared library, not a .wasm
binary, although it places it exactly where include_bytes!()
would find it. (And I think it also correctly manages dependency rebuilds.)
Upvotes: 5
Views: 577
Reputation: 107
I have the same issue and I've somewhat solved it with calling 'wasm-pack' from the build.rs in foo, e.g., :
$ cat build.rs
use std::path::Path;
use std::process::Command;
fn main() {
let dir = "<your-wasmdir-here>"; // update to your directory
println!("cargo:rerun-if-changed={}/", dir);
// don't write into the targets directory for now - figure that out later
// let out_dir = env::var_os("OUT_DIR").unwrap();
let dest_path = Path::new(&dir).join("pkg");
let output = Command::new("wasm-pack")
.args(&["build", "--target", "web"])
.arg(dir)
.output()
.expect("To build wasm files successfully");
if !output.status.success() {
panic!(
"Error while compiling:\n{}",
String::from_utf8_lossy(&output.stdout)
);
}
let js_file = dest_path.join("web_client.js");
let wasm_file = dest_path.join("web_client_bg.wasm");
for file in &[&js_file, &wasm_file] {
let file = std::fs::metadata(file).expect("file to exist");
assert!(file.is_file());
}
println!("cargo:rustc-env=PROJECT_NAME_JS={}", js_file.display());
println!("cargo:rustc-env=PROJECT_NAME_WASM={}", wasm_file.display());
}
The benefit of calling wasm-pack is in addition to building the .wasm binary, it also does the javascript wrapping magic which I can't seem to get cargo to do natively. Let me know if this works for you or if you found something better.
Upvotes: 1