wasmtime_cli/commands/
wizer.rs1use crate::commands::run::{CliInstance, Preloads, RunCommand};
2use crate::common::{RunCommon, RunTarget};
3use anyhow::{Context, Result};
4use std::fs;
5use std::io::{self, Read, Write};
6use std::path::PathBuf;
7use wasmtime::Module;
8use wasmtime_wizer::Wizer;
9
10#[derive(clap::Parser)]
11#[expect(missing_docs, reason = "inheriting wizer's docs")]
12pub struct WizerCommand {
13 #[command(flatten)]
14 run: RunCommon,
15
16 #[command(flatten)]
17 wizer: Wizer,
18
19 input: PathBuf,
21
22 #[command(flatten)]
23 preloads: Preloads,
24
25 #[arg(short = 'o', long)]
29 output: Option<PathBuf>,
30}
31
32enum WizerInfo<'a> {
33 Core(wasmtime_wizer::ModuleContext<'a>),
34 #[cfg(feature = "component-model")]
35 Component(wasmtime_wizer::ComponentContext<'a>),
36}
37
38impl WizerCommand {
39 pub fn execute(mut self) -> Result<()> {
41 self.run.common.init_logging()?;
42 let runtime = tokio::runtime::Builder::new_multi_thread()
43 .enable_time()
44 .enable_io()
45 .build()?;
46 runtime.block_on(self.execute_async())
47 }
48
49 async fn execute_async(mut self) -> Result<()> {
50 if self.run.common.wasm.relaxed_simd_deterministic.is_none() {
54 self.run.common.wasm.relaxed_simd_deterministic = Some(true);
55 }
56
57 if self.run.common.wasi.cli.is_none() {
61 self.run.common.wasi.cli = Some(false);
62 }
63
64 let mut wasm = Vec::new();
66 if self.input.to_str() == Some("-") {
67 io::stdin()
68 .read_to_end(&mut wasm)
69 .context("failed to read input Wasm module from stdin")?;
70 } else {
71 wasm = fs::read(&self.input).context("failed to read input Wasm module")?;
72 }
73
74 #[cfg(feature = "wat")]
75 let wasm = wat::parse_bytes(&wasm)?;
76 let is_component = wasmparser::Parser::is_component(&wasm);
77
78 let mut run = RunCommand {
79 run: self.run,
80 argv0: None,
81 invoke: Some(if is_component {
82 format!("{}()", self.wizer.get_init_func())
83 } else {
84 self.wizer.get_init_func().to_string()
85 }),
86 module_and_args: vec![self.input.clone().into()],
87 preloads: self.preloads.clone(),
88 };
89 let engine = run.new_engine()?;
90
91 let (cx, main) = if is_component {
93 #[cfg(feature = "component-model")]
94 {
95 let (cx, wasm) = self.wizer.instrument_component(&wasm)?;
96 (
97 WizerInfo::Component(cx),
98 RunTarget::Component(wasmtime::component::Component::new(&engine, &wasm)?),
99 )
100 }
101 #[cfg(not(feature = "component-model"))]
102 unreachable!();
103 } else {
104 let (cx, wasm) = self.wizer.instrument(&wasm)?;
105 (
106 WizerInfo::Core(cx),
107 RunTarget::Core(Module::new(&engine, &wasm)?),
108 )
109 };
110
111 let (mut store, mut linker) = run.new_store_and_linker(&engine, &main)?;
114 let instance = run
115 .instantiate_and_run(&engine, &mut linker, &main, &mut store)
116 .await?;
117
118 let final_wasm = match (cx, instance) {
121 (WizerInfo::Core(cx), CliInstance::Core(instance)) => {
122 self.wizer
123 .snapshot(
124 cx,
125 &mut wasmtime_wizer::WasmtimeWizer {
126 store: &mut store,
127 instance,
128 },
129 )
130 .await?
131 }
132
133 #[cfg(feature = "component-model")]
134 (WizerInfo::Component(cx), CliInstance::Component(instance)) => {
135 self.wizer
136 .snapshot_component(
137 cx,
138 &mut wasmtime_wizer::WasmtimeWizerComponent {
139 store: &mut store,
140 instance,
141 },
142 )
143 .await?
144 }
145
146 #[cfg(feature = "component-model")]
147 (WizerInfo::Core(_) | WizerInfo::Component(_), _) => unreachable!(),
148 };
149
150 match &self.output {
151 Some(file) => fs::write(file, &final_wasm).context("failed to write output file")?,
152 None => std::io::stdout()
153 .write_all(&final_wasm)
154 .context("failed to write output to stdout")?,
155 }
156 Ok(())
157 }
158}