wasmtime_cli/commands/
settings.rs

1//! The module that implements the `wasmtime settings` command.
2
3use 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/// Displays available Cranelift settings for a target.
11#[derive(Parser, PartialEq)]
12pub struct SettingsCommand {
13    /// The target triple to get the settings for; defaults to the host triple.
14    #[arg(long, value_name = "TARGET")]
15    target: Option<String>,
16
17    /// Switch output format to JSON
18    #[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// Gather together all of the setting data to displays
38#[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    /// Executes the command.
108    pub fn execute(self) -> Result<()> {
109        // Gather settings from the cranelift compiler builder
110        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        // Add inferred settings if no target specified
124        if self.target.is_none() {
125            settings.infer(&builder)?;
126        }
127
128        // Print settings
129        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}