wasmtime_cli/commands/
settings.rs1use anyhow::{Result, anyhow};
4use clap::Parser;
5use serde::{Serialize, ser::SerializeMap};
6use std::collections::BTreeMap;
7use std::str::FromStr;
8use wasmtime_environ::{CompilerBuilder, FlagValue, Setting, SettingKind, Tunables};
9
10#[derive(Parser, PartialEq)]
12pub struct SettingsCommand {
13 #[arg(long, value_name = "TARGET")]
15 target: Option<String>,
16
17 #[arg(long)]
19 json: bool,
20}
21
22struct SettingData(Setting);
23
24impl Serialize for SettingData {
25 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
26 where
27 S: serde::Serializer,
28 {
29 let mut map = serializer.serialize_map(None)?;
30 map.serialize_entry("name", self.0.name)?;
31 map.serialize_entry("description", self.0.description)?;
32 map.serialize_entry("values", &self.0.values)?;
33 map.end()
34 }
35}
36
37#[derive(serde_derive::Serialize)]
39struct Settings {
40 triple: String,
41
42 enums: Vec<SettingData>,
43 nums: Vec<SettingData>,
44 bools: Vec<SettingData>,
45 presets: Vec<SettingData>,
46
47 inferred: Option<Vec<&'static str>>,
48}
49
50impl Settings {
51 fn from_builder(builder: &Box<dyn CompilerBuilder>) -> Settings {
52 let mut settings = Settings {
53 triple: builder.triple().to_string(),
54 enums: Vec::new(),
55 nums: Vec::new(),
56 bools: Vec::new(),
57 presets: Vec::new(),
58 inferred: None,
59 };
60 settings.add_settings(builder.settings());
61 settings
62 }
63
64 fn infer(&mut self, builder: &Box<dyn CompilerBuilder>) -> Result<()> {
65 let compiler = builder.build()?;
66 let values = compiler.isa_flags().into_iter().collect::<BTreeMap<_, _>>();
67 let mut result = Vec::new();
68 for (name, value) in values {
69 if let FlagValue::Bool(true) = value {
70 result.push(name);
71 }
72 }
73
74 self.inferred = Some(result);
75
76 Ok(())
77 }
78
79 fn add_setting(&mut self, setting: Setting) {
80 let collection = match setting.kind {
81 SettingKind::Enum => &mut self.enums,
82 SettingKind::Num => &mut self.nums,
83 SettingKind::Bool => &mut self.bools,
84 SettingKind::Preset => &mut self.presets,
85 };
86 collection.push(SettingData(setting));
87 }
88
89 fn add_settings<I>(&mut self, iterable: I)
90 where
91 I: IntoIterator<Item = Setting>,
92 {
93 for item in iterable.into_iter() {
94 self.add_setting(item);
95 }
96 }
97
98 fn is_empty(&self) -> bool {
99 self.enums.is_empty()
100 && self.nums.is_empty()
101 && self.bools.is_empty()
102 && self.presets.is_empty()
103 }
104}
105
106impl SettingsCommand {
107 pub fn execute(self) -> Result<()> {
109 let mut builder = wasmtime_cranelift::builder(None)?;
111 let tunables = if let Some(target) = &self.target {
112 let target = target_lexicon::Triple::from_str(target).map_err(|e| anyhow!(e))?;
113 let tunables = Tunables::default_for_target(&target)?;
114 builder.target(target)?;
115 tunables
116 } else {
117 Tunables::default_host()
118 };
119
120 builder.set_tunables(tunables)?;
121 let mut settings = Settings::from_builder(&builder);
122
123 if self.target.is_none() {
125 settings.infer(&builder)?;
126 }
127
128 if self.json {
130 self.print_json(settings)
131 } else {
132 self.print_human_readable(settings)
133 }
134 }
135
136 fn print_json(self, settings: Settings) -> Result<()> {
137 println!("{}", serde_json::to_string_pretty(&settings)?);
138 Ok(())
139 }
140
141 fn print_human_readable(self, settings: Settings) -> Result<()> {
142 if settings.is_empty() {
143 println!("Target '{}' has no settings.", settings.triple);
144 return Ok(());
145 }
146
147 println!("Cranelift settings for target '{}':", settings.triple);
148
149 Self::print_settings_human_readable("Boolean settings:", &settings.bools);
150 Self::print_settings_human_readable("Enum settings:", &settings.enums);
151 Self::print_settings_human_readable("Numerical settings:", &settings.nums);
152 Self::print_settings_human_readable("Presets:", &settings.presets);
153
154 if let Some(inferred) = settings.inferred {
155 println!();
156 println!("Settings inferred for the current host:");
157
158 for name in inferred {
159 println!(" {name}");
160 }
161 }
162
163 Ok(())
164 }
165
166 fn print_settings_human_readable(header: &str, settings: &[SettingData]) {
167 if settings.is_empty() {
168 return;
169 }
170
171 println!();
172 println!("{header}");
173
174 let width = settings.iter().map(|s| s.0.name.len()).max().unwrap_or(0);
175
176 for setting in settings {
177 println!(
178 " {:width$} {}{}",
179 setting.0.name,
180 setting.0.description,
181 setting
182 .0
183 .values
184 .map(|v| format!(" Supported values: {}.", v.join(", ")))
185 .unwrap_or("".to_string()),
186 width = width + 2
187 );
188 }
189 }
190}