I'm trying to write some WASM that can read from the local filesystem using WASI. (using wasmtime) But every time I try, I get a runtime error that says:
Error: unknown import:
wasi_snapshot_preview1::fd_filestat_get
has not been defined
Both the WASM and the wasmtime code are in rust:
use std::fs;
#[unsafe(no_mangle)]
pub fn get_file() -> u32 {
let message = fs::read_to_string("test.txt");
return match message {
Ok(_content) => 0,
Err(_e) => 1,
};
}
This should try to read in the test.txt
file, and return an integer to the outer code with whether it succeeded or not.
This is compiled into WASM with:
cargo build --target wasm32-wasip1
And then converted to WAT:
wasm2wat wasmcode.wasm > watcode.wat
I'm using wasmtime as my WASM runtime. It looks like:
use std::fs;
use anyhow::Result;
use wasmtime::Linker;
use wasmtime::*;
use wasmtime_wasi::p2::WasiCtxBuilder;
use wasmtime_wasi::preview1::WasiP1Ctx;
use wasmtime_wasi::{DirPerms, FilePerms};
fn main() -> Result<()> {
let wat = fs::read_to_string("watcode.wat");
let wasi_ctx: WasiP1Ctx = WasiCtxBuilder::new()
.preopened_dir(".", "/", DirPerms::READ, FilePerms::READ)?
.build_p1();
let config = Config::new();
let engine: Engine = Engine::new(&config)?;
let mut store = Store::new(&engine, wasi_ctx);
let mut linker = Linker::new(&engine);
let module: Module = Module::new(&engine, wat)?;
let instance = linker.instantiate(&mut store, &module)?;
wasmtime_wasi::preview1::add_to_linker_sync(&mut linker, |s| s)?;
let get_file = instance.get_typed_func::<(), u32>(&mut store, "get_file")?;
let error_code = get_file.call(&mut store, ())?;
println!("get_file returned: {}", error_code);
Ok(())
}
The error clearly is telling me that the WASM code is trying to link to fd_filestat_get
, and it can't be found. But why not? I'm building the linker with build_p1
and then linking it with add_to_linker_sync
. I'm new to Rust, but not sure what I'm missing here. Thanks!
The add_to_linker_sync
call is in the wrong place. It has to come before the linker is instantiated and the module is created. So the working code looks like:
use std::fs;
use anyhow::Result;
use wasmtime::Linker;
use wasmtime::*;
use wasmtime_wasi::p2::WasiCtxBuilder;
use wasmtime_wasi::preview1::WasiP1Ctx;
use wasmtime_wasi::{DirPerms, FilePerms};
fn main() -> Result<()> {
let wat = fs::read_to_string("watcode.wat");
let wasi_ctx: WasiP1Ctx = WasiCtxBuilder::new()
.preopened_dir(".", "/", DirPerms::READ, FilePerms::READ)?
.build_p1();
let config = Config::new();
let engine: Engine = Engine::new(&config)?;
let mut store = Store::new(&engine, wasi_ctx);
let mut linker = Linker::new(&engine);
wasmtime_wasi::preview1::add_to_linker_sync(&mut linker, |s| s)?; // This line has moved
let module: Module = Module::new(&engine, wat)?;
let instance = linker.instantiate(&mut store, &module)?;
let get_file = instance.get_typed_func::<(), u32>(&mut store, "get_file")?;
let error_code = get_file.call(&mut store, ())?;
println!("get_file returned: {}", error_code);
Ok(())
}
Annoying that it just silently fails in this instance.