1 //! Example of instantiating a wasm module which uses WASI imports. 2 3 /* 4 You can execute this example with: 5 cmake examples/ 6 cargo run --example wasip2 7 */ 8 9 use wasmtime::component::{Component, Linker, ResourceTable}; 10 use wasmtime::*; 11 use wasmtime_wasi::p2::bindings::sync::Command; 12 use wasmtime_wasi::{WasiCtx, WasiCtxView, WasiView}; 13 14 pub struct ComponentRunStates { 15 // These two are required basically as a standard way to enable the impl of IoView and 16 // WasiView. 17 // impl of WasiView is required by [`wasmtime_wasi::p2::add_to_linker_sync`] 18 pub wasi_ctx: WasiCtx, 19 pub resource_table: ResourceTable, 20 // You can add other custom host states if needed 21 } 22 23 impl WasiView for ComponentRunStates { 24 fn ctx(&mut self) -> WasiCtxView<'_> { 25 WasiCtxView { 26 ctx: &mut self.wasi_ctx, 27 table: &mut self.resource_table, 28 } 29 } 30 } 31 32 fn main() -> Result<()> { 33 // Define the WASI functions globally on the `Config`. 34 let engine = Engine::default(); 35 let mut linker = Linker::new(&engine); 36 wasmtime_wasi::p2::add_to_linker_sync(&mut linker)?; 37 38 // Create a WASI context and put it in a Store; all instances in the store 39 // share this context. `WasiCtx` provides a number of ways to 40 // configure what the target program will have access to. 41 let wasi = WasiCtx::builder().inherit_stdio().inherit_args().build(); 42 let state = ComponentRunStates { 43 wasi_ctx: wasi, 44 resource_table: ResourceTable::new(), 45 }; 46 let mut store = Store::new(&engine, state); 47 48 // Instantiate our component with the imports we've created, and run it. 49 let component = Component::from_file(&engine, "target/wasm32-wasip2/debug/wasi.wasm")?; 50 let command = Command::instantiate(&mut store, &component, &linker)?; 51 let program_result = command.wasi_cli_run().call_run(&mut store)?; 52 if program_result.is_err() { 53 std::process::exit(1) 54 } 55 56 // Alternatively, instead of using `Command`, just instantiate it as a normal component 57 // New states 58 let wasi = WasiCtx::builder().inherit_stdio().inherit_args().build(); 59 let state = ComponentRunStates { 60 wasi_ctx: wasi, 61 resource_table: ResourceTable::new(), 62 }; 63 let mut store = Store::new(&engine, state); 64 // Instantiate it as a normal component 65 let instance = linker.instantiate(&mut store, &component)?; 66 // Get the index for the exported interface 67 let interface_idx = instance 68 .get_export_index(&mut store, None, "wasi:cli/run@0.2.0") 69 .expect("Cannot get `wasi:cli/run@0.2.0` interface"); 70 // Get the index for the exported function in the exported interface 71 let parent_export_idx = Some(&interface_idx); 72 let func_idx = instance 73 .get_export_index(&mut store, parent_export_idx, "run") 74 .expect("Cannot get `run` function in `wasi:cli/run@0.2.0` interface"); 75 let func = instance 76 .get_func(&mut store, func_idx) 77 .expect("Unreachable since we've got func_idx"); 78 // As the `run` function in `wasi:cli/run@0.2.0` takes no argument and return a WASI result that correspond to a `Result<(), ()>` 79 // Reference: 80 // * https://github.com/WebAssembly/wasi-cli/blob/main/wit/run.wit 81 // * Documentation for [Func::typed](https://docs.rs/wasmtime/latest/wasmtime/component/struct.Func.html#method.typed) and [ComponentNamedList](https://docs.rs/wasmtime/latest/wasmtime/component/trait.ComponentNamedList.html) 82 let typed = func.typed::<(), (Result<(), ()>,)>(&store)?; 83 let (result,) = typed.call(&mut store, ())?; 84 result.map_err(|_| wasmtime::format_err!("error")) 85 } 86