Files
wasmtime/src/commands/settings.rs
Alex Crichton ddfadaeb38 Add a cranelift compile-time feature to wasmtime (#3206)
* Remove unnecessary into_iter/map

Forgotten from a previous refactoring, this variable was already of the
right type!

* Move `wasmtime_jit::Compiler` into `wasmtime`

This `Compiler` struct is mostly a historical artifact at this point and
wasn't necessarily pulling much weight any more. This organization also
doesn't lend itself super well to compiling out `cranelift` when the
`Compiler` here is used for both parallel iteration configuration
settings as well as compilation.

The movement into `wasmtime` is relatively small, with
`Module::build_artifacts` being the main function added here which is a
merging of the previous functions removed from the `wasmtime-jit` crate.

* Add a `cranelift` compile-time feature to `wasmtime`

This commit concludes the saga of refactoring Wasmtime and making
Cranelift an optional dependency by adding a new Cargo feature to the
`wasmtime` crate called `cranelift`, which is enabled by default.

This feature is implemented by having a new cfg for `wasmtime` itself,
`cfg(compiler)`, which is used wherever compilation is necessary. This
bubbles up to disable APIs such as `Module::new`, `Func::new`,
`Engine::precompile_module`, and a number of `Config` methods affecting
compiler configuration. Checks are added to CI that when built in this
mode Wasmtime continues to successfully build. It's hoped that although
this is effectively "sprinkle `#[cfg]` until things compile" this won't
be too too bad to maintain over time since it's also an use case we're
interested in supporting.

With `cranelift` disabled the only way to create a `Module` is with the
`Module::deserialize` method, which requires some form of precompiled
artifact.

Two consequences of this change are:

* `Module::serialize` is also disabled in this mode. The reason for this
  is that serialized modules contain ISA/shared flags encoded in them
  which were used to produce the compiled code. There's no storage for
  this if compilation is disabled. This could probably be re-enabled in
  the future if necessary, but it may not end up being all that necessary.

* Deserialized modules are not checked to ensure that their ISA/shared
  flags are compatible with the host CPU. This is actually already the
  case, though, with normal modules. We'll likely want to fix this in
  the future using a shared implementation for both these locations.

Documentation should be updated to indicate that `cranelift` can be
disabled, although it's not really the most prominent documentation
because this is expected to be a somewhat niche use case (albeit
important, just not too common).

* Always enable cranelift for the C API

* Fix doc example builds

* Fix check tests on GitHub Actions
2021-08-18 16:47:47 -05:00

97 lines
3.1 KiB
Rust

//! The module that implements the `wasmtime settings` command.
use anyhow::{anyhow, Result};
use std::collections::BTreeMap;
use std::str::FromStr;
use structopt::StructOpt;
use wasmtime_environ::{FlagValue, Setting, SettingKind};
/// Displays available Cranelift settings for a target.
#[derive(StructOpt)]
#[structopt(name = "run")]
pub struct SettingsCommand {
/// The target triple to get the settings for; defaults to the host triple.
#[structopt(long, value_name = "TARGET")]
target: Option<String>,
}
impl SettingsCommand {
/// Executes the command.
pub fn execute(self) -> Result<()> {
let mut builder = wasmtime_cranelift::builder();
if let Some(target) = &self.target {
let target = target_lexicon::Triple::from_str(target).map_err(|e| anyhow!(e))?;
builder.target(target)?;
}
let mut enums = (Vec::new(), 0, "Enum settings:");
let mut nums = (Vec::new(), 0, "Numerical settings:");
let mut bools = (Vec::new(), 0, "Boolean settings:");
let mut presets = (Vec::new(), 0, "Presets:");
for setting in builder.settings() {
let (collection, max, _) = match setting.kind {
SettingKind::Enum => &mut enums,
SettingKind::Num => &mut nums,
SettingKind::Bool => &mut bools,
SettingKind::Preset => &mut presets,
};
if setting.name.len() > *max {
*max = setting.name.len();
}
collection.push(setting);
}
if enums.0.is_empty() && nums.0.is_empty() && bools.0.is_empty() && presets.0.is_empty() {
println!("Target '{}' has no settings.", builder.triple());
return Ok(());
}
println!("Cranelift settings for target '{}':", builder.triple());
for (collection, max, header) in &mut [enums, nums, bools, presets] {
if collection.is_empty() {
continue;
}
collection.sort_by_key(|k| k.name);
println!();
Self::print_settings(header, collection, *max);
}
if self.target.is_none() {
let compiler = builder.build();
println!();
println!("Settings inferred for the current host:");
let values = compiler.isa_flags().into_iter().collect::<BTreeMap<_, _>>();
for (name, value) in values {
if let FlagValue::Bool(true) = value {
println!(" {}", name);
}
}
}
Ok(())
}
fn print_settings(header: &str, settings: &[Setting], width: usize) {
println!("{}", header);
for setting in settings {
println!(
" {:width$} {}{}",
setting.name,
setting.description,
setting
.values
.map(|v| format!(" Supported values: {}.", v.join(", ")))
.unwrap_or("".to_string()),
width = width + 2
);
}
}
}