xref: /wasmtime-44.0.1/src/lib.rs (revision a7f592a0)
1 //! The Wasmtime command line interface (CLI) crate.
2 //!
3 //! This crate implements the Wasmtime command line tools.
4 
5 #![deny(
6     missing_docs,
7     trivial_numeric_casts,
8     unused_extern_crates,
9     unstable_features
10 )]
11 #![warn(unused_import_braces)]
12 #![cfg_attr(feature = "clippy", plugin(clippy(conf_file = "../clippy.toml")))]
13 #![cfg_attr(feature = "cargo-clippy", allow(clippy::new_without_default))]
14 #![cfg_attr(
15     feature = "cargo-clippy",
16     warn(
17         clippy::float_arithmetic,
18         clippy::mut_mut,
19         clippy::nonminimal_bool,
20         clippy::map_unwrap_or,
21         clippy::unicode_not_nfc,
22         clippy::use_self
23     )
24 )]
25 
26 const SUPPORTED_WASM_FEATURES: &[(&str, &str)] = &[
27     ("all", "enables all supported WebAssembly features"),
28     (
29         "bulk-memory",
30         "enables support for bulk memory instructions",
31     ),
32     (
33         "module-linking",
34         "enables support for the module-linking proposal",
35     ),
36     (
37         "multi-memory",
38         "enables support for the multi-memory proposal",
39     ),
40     ("multi-value", "enables support for multi-value functions"),
41     ("reference-types", "enables support for reference types"),
42     ("simd", "enables support for proposed SIMD instructions"),
43     ("threads", "enables support for WebAssembly threads"),
44 ];
45 
46 const SUPPORTED_WASI_MODULES: &[(&str, &str)] = &[
47     (
48         "default",
49         "enables all stable WASI modules (no experimental modules)",
50     ),
51     (
52         "wasi-common",
53         "enables support for the WASI common APIs, see https://github.com/WebAssembly/WASI",
54     ),
55     (
56         "experimental-wasi-nn",
57         "enables support for the WASI neural network API (experimental), see https://github.com/WebAssembly/wasi-nn",
58     ),
59     (
60         "experimental-wasi-crypto",
61         "enables support for the WASI cryptography APIs (experimental), see https://github.com/WebAssembly/wasi-crypto",
62     ),
63 ];
64 
65 lazy_static::lazy_static! {
66     static ref FLAG_EXPLANATIONS: String = {
67         use std::fmt::Write;
68 
69         let mut s = String::new();
70 
71         // Explain --wasm-features.
72         writeln!(&mut s, "Supported values for `--wasm-features`:").unwrap();
73         writeln!(&mut s).unwrap();
74         let max = SUPPORTED_WASM_FEATURES.iter().max_by_key(|(name, _)| name.len()).unwrap();
75         for (name, desc) in SUPPORTED_WASM_FEATURES.iter() {
76             writeln!(&mut s, "{:width$} {}", name, desc, width = max.0.len() + 2).unwrap();
77         }
78         writeln!(&mut s).unwrap();
79 
80         // Explain --wasi-modules.
81         writeln!(&mut s, "Supported values for `--wasi-modules`:").unwrap();
82         writeln!(&mut s).unwrap();
83         let max = SUPPORTED_WASI_MODULES.iter().max_by_key(|(name, _)| name.len()).unwrap();
84         for (name, desc) in SUPPORTED_WASI_MODULES.iter() {
85             writeln!(&mut s, "{:width$} {}", name, desc, width = max.0.len() + 2).unwrap();
86         }
87 
88         writeln!(&mut s).unwrap();
89         writeln!(&mut s, "Features prefixed with '-' will be disabled.").unwrap();
90 
91         s
92     };
93 }
94 
95 pub mod commands;
96 mod obj;
97 
98 use anyhow::{bail, Result};
99 use std::collections::HashMap;
100 use std::path::PathBuf;
101 use structopt::StructOpt;
102 use target_lexicon::Triple;
103 use wasmtime::{Config, ProfilingStrategy, Strategy};
104 
105 pub use obj::compile_to_obj;
106 
107 fn pick_compilation_strategy(cranelift: bool, lightbeam: bool) -> Result<Strategy> {
108     Ok(match (lightbeam, cranelift) {
109         (true, false) => Strategy::Lightbeam,
110         (false, true) => Strategy::Cranelift,
111         (false, false) => Strategy::Auto,
112         (true, true) => bail!("Can't enable --cranelift and --lightbeam at the same time"),
113     })
114 }
115 
116 fn pick_profiling_strategy(jitdump: bool, vtune: bool) -> Result<ProfilingStrategy> {
117     Ok(match (jitdump, vtune) {
118         (true, false) => ProfilingStrategy::JitDump,
119         (false, true) => ProfilingStrategy::VTune,
120         (true, true) => {
121             println!("Can't enable --jitdump and --vtune at the same time. Profiling not enabled.");
122             ProfilingStrategy::None
123         }
124         _ => ProfilingStrategy::None,
125     })
126 }
127 
128 fn init_file_per_thread_logger(prefix: &'static str) {
129     file_per_thread_logger::initialize(prefix);
130 
131     // Extending behavior of default spawner:
132     // https://docs.rs/rayon/1.1.0/rayon/struct.ThreadPoolBuilder.html#method.spawn_handler
133     // Source code says DefaultSpawner is implementation detail and
134     // shouldn't be used directly.
135     rayon::ThreadPoolBuilder::new()
136         .spawn_handler(move |thread| {
137             let mut b = std::thread::Builder::new();
138             if let Some(name) = thread.name() {
139                 b = b.name(name.to_owned());
140             }
141             if let Some(stack_size) = thread.stack_size() {
142                 b = b.stack_size(stack_size);
143             }
144             b.spawn(move || {
145                 file_per_thread_logger::initialize(prefix);
146                 thread.run()
147             })?;
148             Ok(())
149         })
150         .build_global()
151         .unwrap();
152 }
153 
154 /// Common options for commands that translate WebAssembly modules
155 #[derive(StructOpt)]
156 struct CommonOptions {
157     /// Use specified configuration file
158     #[structopt(long, parse(from_os_str), value_name = "CONFIG_PATH")]
159     config: Option<PathBuf>,
160 
161     /// Use Cranelift for all compilation
162     #[structopt(long, conflicts_with = "lightbeam")]
163     cranelift: bool,
164 
165     /// Disable logging.
166     #[structopt(long, conflicts_with = "log_to_files")]
167     disable_logging: bool,
168 
169     /// Log to per-thread log files instead of stderr.
170     #[structopt(long)]
171     log_to_files: bool,
172 
173     /// Generate debug information
174     #[structopt(short = "g")]
175     debug_info: bool,
176 
177     /// Disable cache system
178     #[structopt(long)]
179     disable_cache: bool,
180 
181     /// Enable support for proposed SIMD instructions (deprecated; use `--wasm-features=simd`)
182     #[structopt(long, hidden = true)]
183     enable_simd: bool,
184 
185     /// Enable support for reference types (deprecated; use `--wasm-features=reference-types`)
186     #[structopt(long, hidden = true)]
187     enable_reference_types: bool,
188 
189     /// Enable support for multi-value functions (deprecated; use `--wasm-features=multi-value`)
190     #[structopt(long, hidden = true)]
191     enable_multi_value: bool,
192 
193     /// Enable support for Wasm threads (deprecated; use `--wasm-features=threads`)
194     #[structopt(long, hidden = true)]
195     enable_threads: bool,
196 
197     /// Enable support for bulk memory instructions (deprecated; use `--wasm-features=bulk-memory`)
198     #[structopt(long, hidden = true)]
199     enable_bulk_memory: bool,
200 
201     /// Enable support for the multi-memory proposal (deprecated; use `--wasm-features=multi-memory`)
202     #[structopt(long, hidden = true)]
203     enable_multi_memory: bool,
204 
205     /// Enable support for the module-linking proposal (deprecated; use `--wasm-features=module-linking`)
206     #[structopt(long, hidden = true)]
207     enable_module_linking: bool,
208 
209     /// Enable all experimental Wasm features (deprecated; use `--wasm-features=all`)
210     #[structopt(long, hidden = true)]
211     enable_all: bool,
212 
213     /// Enables or disables WebAssembly features
214     #[structopt(long, value_name = "FEATURE,FEATURE,...", parse(try_from_str = parse_wasm_features))]
215     wasm_features: Option<wasmparser::WasmFeatures>,
216 
217     /// Enables or disables WASI modules
218     #[structopt(long, value_name = "MODULE,MODULE,...", parse(try_from_str = parse_wasi_modules))]
219     wasi_modules: Option<WasiModules>,
220 
221     /// Use Lightbeam for all compilation
222     #[structopt(long, conflicts_with = "cranelift")]
223     lightbeam: bool,
224 
225     /// Generate jitdump file (supported on --features=profiling build)
226     #[structopt(long, conflicts_with = "vtune")]
227     jitdump: bool,
228 
229     /// Generate vtune (supported on --features=vtune build)
230     #[structopt(long, conflicts_with = "jitdump")]
231     vtune: bool,
232 
233     /// Run optimization passes on translated functions, on by default
234     #[structopt(short = "O", long)]
235     optimize: bool,
236 
237     /// Optimization level for generated functions
238     /// Supported levels: 0 (none), 1, 2 (most), or s (size); default is "most"
239     #[structopt(
240         long,
241         value_name = "LEVEL",
242         parse(try_from_str = parse_opt_level),
243         verbatim_doc_comment,
244     )]
245     opt_level: Option<wasmtime::OptLevel>,
246 
247     /// Set a Cranelift setting to a given value.
248     /// Use `wasmtime settings` to list Cranelift settings for a target.
249     #[structopt(long = "cranelift-set", value_name = "NAME=VALUE", number_of_values = 1, verbatim_doc_comment, parse(try_from_str = parse_cranelift_flag))]
250     cranelift_set: Vec<(String, String)>,
251 
252     /// Enable a Cranelift boolean setting or preset.
253     /// Use `wasmtime settings` to list Cranelift settings for a target.
254     #[structopt(
255         long,
256         value_name = "SETTING",
257         number_of_values = 1,
258         verbatim_doc_comment
259     )]
260     cranelift_enable: Vec<String>,
261 
262     /// Maximum size in bytes of wasm memory before it becomes dynamically
263     /// relocatable instead of up-front-reserved.
264     #[structopt(long, value_name = "MAXIMUM")]
265     static_memory_maximum_size: Option<u64>,
266 
267     /// Byte size of the guard region after static memories are allocated.
268     #[structopt(long, value_name = "SIZE")]
269     static_memory_guard_size: Option<u64>,
270 
271     /// Byte size of the guard region after dynamic memories are allocated.
272     #[structopt(long, value_name = "SIZE")]
273     dynamic_memory_guard_size: Option<u64>,
274 
275     /// Enable Cranelift's internal debug verifier (expensive)
276     #[structopt(long)]
277     enable_cranelift_debug_verifier: bool,
278 
279     /// Enable Cranelift's internal NaN canonicalization
280     #[structopt(long)]
281     enable_cranelift_nan_canonicalization: bool,
282 }
283 
284 impl CommonOptions {
285     fn init_logging(&self) {
286         if self.disable_logging {
287             return;
288         }
289         if self.log_to_files {
290             let prefix = "wasmtime.dbg.";
291             init_file_per_thread_logger(prefix);
292         } else {
293             pretty_env_logger::init();
294         }
295     }
296 
297     fn config(&self, target: Option<&str>) -> Result<Config> {
298         let mut config = Config::new();
299 
300         // Set the target before setting any cranelift options
301         if let Some(target) = target {
302             config.target(target)?;
303         }
304 
305         config
306             .cranelift_debug_verifier(self.enable_cranelift_debug_verifier)
307             .debug_info(self.debug_info)
308             .cranelift_opt_level(self.opt_level())
309             .strategy(pick_compilation_strategy(self.cranelift, self.lightbeam)?)?
310             .profiler(pick_profiling_strategy(self.jitdump, self.vtune)?)?
311             .cranelift_nan_canonicalization(self.enable_cranelift_nan_canonicalization);
312 
313         self.enable_wasm_features(&mut config);
314 
315         for name in &self.cranelift_enable {
316             unsafe {
317                 config.cranelift_flag_enable(name)?;
318             }
319         }
320 
321         for (name, value) in &self.cranelift_set {
322             unsafe {
323                 config.cranelift_flag_set(name, value)?;
324             }
325         }
326 
327         if !self.disable_cache {
328             match &self.config {
329                 Some(path) => {
330                     config.cache_config_load(path)?;
331                 }
332                 None => {
333                     config.cache_config_load_default()?;
334                 }
335             }
336         }
337 
338         if let Some(max) = self.static_memory_maximum_size {
339             config.static_memory_maximum_size(max);
340         }
341 
342         if let Some(size) = self.static_memory_guard_size {
343             config.static_memory_guard_size(size);
344         }
345 
346         if let Some(size) = self.dynamic_memory_guard_size {
347             config.dynamic_memory_guard_size(size);
348         }
349 
350         Ok(config)
351     }
352 
353     fn enable_wasm_features(&self, config: &mut Config) {
354         let features = self.wasm_features.unwrap_or_default();
355 
356         config
357             .wasm_simd(features.simd || self.enable_simd || self.enable_all)
358             .wasm_bulk_memory(features.bulk_memory || self.enable_bulk_memory || self.enable_all)
359             .wasm_reference_types(
360                 features.reference_types || self.enable_reference_types || self.enable_all,
361             )
362             .wasm_multi_value(features.multi_value || self.enable_multi_value || self.enable_all)
363             .wasm_threads(features.threads || self.enable_threads || self.enable_all)
364             .wasm_multi_memory(features.multi_memory || self.enable_multi_memory || self.enable_all)
365             .wasm_module_linking(
366                 features.module_linking || self.enable_module_linking || self.enable_all,
367             );
368     }
369 
370     fn opt_level(&self) -> wasmtime::OptLevel {
371         match (self.optimize, self.opt_level.clone()) {
372             (true, _) => wasmtime::OptLevel::Speed,
373             (false, other) => other.unwrap_or(wasmtime::OptLevel::Speed),
374         }
375     }
376 }
377 
378 fn parse_opt_level(opt_level: &str) -> Result<wasmtime::OptLevel> {
379     match opt_level {
380         "s" => Ok(wasmtime::OptLevel::SpeedAndSize),
381         "0" => Ok(wasmtime::OptLevel::None),
382         "1" => Ok(wasmtime::OptLevel::Speed),
383         "2" => Ok(wasmtime::OptLevel::Speed),
384         other => bail!(
385             "unknown optimization level `{}`, only 0,1,2,s accepted",
386             other
387         ),
388     }
389 }
390 
391 fn parse_wasm_features(features: &str) -> Result<wasmparser::WasmFeatures> {
392     let features = features.trim();
393 
394     let mut all = None;
395     let mut values: HashMap<_, _> = SUPPORTED_WASM_FEATURES
396         .iter()
397         .map(|(name, _)| (name.to_string(), None))
398         .collect();
399 
400     if features == "all" {
401         all = Some(true);
402     } else if features == "-all" {
403         all = Some(false);
404     } else {
405         for feature in features.split(',') {
406             let feature = feature.trim();
407 
408             if feature.is_empty() {
409                 continue;
410             }
411 
412             let (feature, value) = if feature.starts_with('-') {
413                 (&feature[1..], false)
414             } else {
415                 (feature, true)
416             };
417 
418             if feature == "all" {
419                 bail!("'all' cannot be specified with other WebAssembly features");
420             }
421 
422             match values.get_mut(feature) {
423                 Some(v) => *v = Some(value),
424                 None => bail!("unsupported WebAssembly feature '{}'", feature),
425             }
426         }
427     }
428 
429     Ok(wasmparser::WasmFeatures {
430         reference_types: all.unwrap_or(values["reference-types"].unwrap_or(true)),
431         multi_value: all.unwrap_or(values["multi-value"].unwrap_or(true)),
432         bulk_memory: all.unwrap_or(values["bulk-memory"].unwrap_or(true)),
433         module_linking: all.unwrap_or(values["module-linking"].unwrap_or(false)),
434         simd: all.unwrap_or(values["simd"].unwrap_or(false)),
435         threads: all.unwrap_or(values["threads"].unwrap_or(false)),
436         tail_call: false,
437         deterministic_only: false,
438         multi_memory: all.unwrap_or(values["multi-memory"].unwrap_or(false)),
439         exceptions: false,
440         memory64: false,
441     })
442 }
443 
444 fn parse_wasi_modules(modules: &str) -> Result<WasiModules> {
445     let modules = modules.trim();
446     match modules {
447         "default" => Ok(WasiModules::default()),
448         "-default" => Ok(WasiModules::none()),
449         _ => {
450             // Starting from the default set of WASI modules, enable or disable a list of
451             // comma-separated modules.
452             let mut wasi_modules = WasiModules::default();
453             let mut set = |module: &str, enable: bool| match module {
454                 "" => Ok(()),
455                 "wasi-common" => Ok(wasi_modules.wasi_common = enable),
456                 "experimental-wasi-nn" => Ok(wasi_modules.wasi_nn = enable),
457                 "experimental-wasi-crypto" => Ok(wasi_modules.wasi_crypto = enable),
458                 "default" => bail!("'default' cannot be specified with other WASI modules"),
459                 _ => bail!("unsupported WASI module '{}'", module),
460             };
461 
462             for module in modules.split(',') {
463                 let module = module.trim();
464                 let (module, value) = if module.starts_with('-') {
465                     (&module[1..], false)
466                 } else {
467                     (module, true)
468                 };
469                 set(module, value)?;
470             }
471 
472             Ok(wasi_modules)
473         }
474     }
475 }
476 
477 /// Select which WASI modules are available at runtime for use by Wasm programs.
478 #[derive(Debug, Clone, Copy, PartialEq)]
479 pub struct WasiModules {
480     /// Enable the wasi-common implementation; eventually this should be split into its separate
481     /// parts once the implementation allows for it (e.g. wasi-fs, wasi-clocks, etc.).
482     pub wasi_common: bool,
483 
484     /// Enable the experimental wasi-nn implementation.
485     pub wasi_nn: bool,
486 
487     /// Enable the experimental wasi-crypto implementation.
488     pub wasi_crypto: bool,
489 }
490 
491 impl Default for WasiModules {
492     fn default() -> Self {
493         Self {
494             wasi_common: true,
495             wasi_nn: false,
496             wasi_crypto: false,
497         }
498     }
499 }
500 
501 impl WasiModules {
502     /// Enable no modules.
503     pub fn none() -> Self {
504         Self {
505             wasi_common: false,
506             wasi_nn: false,
507             wasi_crypto: false,
508         }
509     }
510 }
511 
512 fn parse_cranelift_flag(name_and_value: &str) -> Result<(String, String)> {
513     let mut split = name_and_value.splitn(2, '=');
514     let name = if let Some(name) = split.next() {
515         name.to_string()
516     } else {
517         bail!("missing name in cranelift flag");
518     };
519     let value = if let Some(value) = split.next() {
520         value.to_string()
521     } else {
522         bail!("missing value in cranelift flag");
523     };
524     Ok((name, value))
525 }
526 
527 fn parse_target(s: &str) -> Result<Triple> {
528     use std::str::FromStr;
529     Triple::from_str(&s).map_err(|e| anyhow::anyhow!(e))
530 }
531 
532 #[cfg(test)]
533 mod test {
534     use super::*;
535 
536     #[test]
537     fn test_all_features() -> Result<()> {
538         let options = CommonOptions::from_iter_safe(vec!["foo", "--wasm-features=all"])?;
539 
540         let wasmparser::WasmFeatures {
541             reference_types,
542             multi_value,
543             bulk_memory,
544             module_linking,
545             simd,
546             threads,
547             tail_call,
548             deterministic_only,
549             multi_memory,
550             exceptions,
551             memory64,
552         } = options.wasm_features.unwrap();
553 
554         assert!(reference_types);
555         assert!(multi_value);
556         assert!(bulk_memory);
557         assert!(module_linking);
558         assert!(simd);
559         assert!(threads);
560         assert!(!tail_call); // Not supported
561         assert!(!deterministic_only); // Not supported
562         assert!(multi_memory);
563         assert!(!exceptions); // Not supported
564         assert!(!memory64); // Not supported
565 
566         Ok(())
567     }
568 
569     #[test]
570     fn test_no_features() -> Result<()> {
571         let options = CommonOptions::from_iter_safe(vec!["foo", "--wasm-features=-all"])?;
572 
573         let wasmparser::WasmFeatures {
574             reference_types,
575             multi_value,
576             bulk_memory,
577             module_linking,
578             simd,
579             threads,
580             tail_call,
581             deterministic_only,
582             multi_memory,
583             exceptions,
584             memory64,
585         } = options.wasm_features.unwrap();
586 
587         assert!(!reference_types);
588         assert!(!multi_value);
589         assert!(!bulk_memory);
590         assert!(!module_linking);
591         assert!(!simd);
592         assert!(!threads);
593         assert!(!tail_call);
594         assert!(!deterministic_only);
595         assert!(!multi_memory);
596         assert!(!exceptions);
597         assert!(!memory64);
598 
599         Ok(())
600     }
601 
602     #[test]
603     fn test_multiple_features() -> Result<()> {
604         let options = CommonOptions::from_iter_safe(vec![
605             "foo",
606             "--wasm-features=-reference-types,simd,multi-memory",
607         ])?;
608 
609         let wasmparser::WasmFeatures {
610             reference_types,
611             multi_value,
612             bulk_memory,
613             module_linking,
614             simd,
615             threads,
616             tail_call,
617             deterministic_only,
618             multi_memory,
619             exceptions,
620             memory64,
621         } = options.wasm_features.unwrap();
622 
623         assert!(!reference_types);
624         assert!(multi_value);
625         assert!(bulk_memory);
626         assert!(!module_linking);
627         assert!(simd);
628         assert!(!threads);
629         assert!(!tail_call); // Not supported
630         assert!(!deterministic_only); // Not supported
631         assert!(multi_memory);
632         assert!(!exceptions); // Not supported
633         assert!(!memory64); // Not supported
634 
635         Ok(())
636     }
637 
638     macro_rules! feature_test {
639         ($test_name:ident, $name:ident, $flag:literal) => {
640             #[test]
641             fn $test_name() -> Result<()> {
642                 let options =
643                     CommonOptions::from_iter_safe(vec!["foo", concat!("--wasm-features=", $flag)])?;
644 
645                 let wasmparser::WasmFeatures { $name, .. } = options.wasm_features.unwrap();
646 
647                 assert!($name);
648 
649                 let options = CommonOptions::from_iter_safe(vec![
650                     "foo",
651                     concat!("--wasm-features=-", $flag),
652                 ])?;
653 
654                 let wasmparser::WasmFeatures { $name, .. } = options.wasm_features.unwrap();
655 
656                 assert!(!$name);
657 
658                 Ok(())
659             }
660         };
661     }
662 
663     feature_test!(
664         test_reference_types_feature,
665         reference_types,
666         "reference-types"
667     );
668     feature_test!(test_multi_value_feature, multi_value, "multi-value");
669     feature_test!(test_bulk_memory_feature, bulk_memory, "bulk-memory");
670     feature_test!(
671         test_module_linking_feature,
672         module_linking,
673         "module-linking"
674     );
675     feature_test!(test_simd_feature, simd, "simd");
676     feature_test!(test_threads_feature, threads, "threads");
677     feature_test!(test_multi_memory_feature, multi_memory, "multi-memory");
678 
679     #[test]
680     fn test_default_modules() {
681         let options = CommonOptions::from_iter_safe(vec!["foo", "--wasi-modules=default"]).unwrap();
682         assert_eq!(
683             options.wasi_modules.unwrap(),
684             WasiModules {
685                 wasi_common: true,
686                 wasi_nn: false,
687                 wasi_crypto: false
688             }
689         );
690     }
691 
692     #[test]
693     fn test_empty_modules() {
694         let options = CommonOptions::from_iter_safe(vec!["foo", "--wasi-modules="]).unwrap();
695         assert_eq!(
696             options.wasi_modules.unwrap(),
697             WasiModules {
698                 wasi_common: true,
699                 wasi_nn: false,
700                 wasi_crypto: false
701             }
702         );
703     }
704 
705     #[test]
706     fn test_some_modules() {
707         let options = CommonOptions::from_iter_safe(vec![
708             "foo",
709             "--wasi-modules=experimental-wasi-nn,-wasi-common",
710         ])
711         .unwrap();
712         assert_eq!(
713             options.wasi_modules.unwrap(),
714             WasiModules {
715                 wasi_common: false,
716                 wasi_nn: true,
717                 wasi_crypto: false
718             }
719         );
720     }
721 
722     #[test]
723     fn test_no_modules() {
724         let options =
725             CommonOptions::from_iter_safe(vec!["foo", "--wasi-modules=-default"]).unwrap();
726         assert_eq!(
727             options.wasi_modules.unwrap(),
728             WasiModules {
729                 wasi_common: false,
730                 wasi_nn: false,
731                 wasi_crypto: false
732             }
733         );
734     }
735 }
736