wasmer_cli/commands/
compile.rs

1use std::path::PathBuf;
2
3use anyhow::{Context, Result, bail};
4use clap::Parser;
5use wasmer::{
6    sys::{engine::NativeEngineExt, *},
7    *,
8};
9
10use crate::{backend::RuntimeOptions, common::HashAlgorithm, warning};
11
12#[derive(Debug, Parser)]
13/// The options for the `wasmer compile` subcommand
14pub struct Compile {
15    /// Input file
16    #[clap(name = "FILE")]
17    path: PathBuf,
18
19    /// Output file
20    #[clap(name = "OUTPUT PATH", short = 'o')]
21    output: PathBuf,
22
23    /// Compilation Target triple
24    #[clap(long = "target")]
25    target_triple: Option<Triple>,
26
27    #[clap(flatten)]
28    rt: RuntimeOptions,
29
30    #[clap(short = 'm')]
31    cpu_features: Vec<CpuFeature>,
32
33    /// Hashing algorithm to be used for module hash
34    #[clap(long, value_enum)]
35    hash_algorithm: Option<HashAlgorithm>,
36}
37
38impl Compile {
39    /// Runs logic for the `compile` subcommand
40    pub fn execute(&self) -> Result<()> {
41        self.inner_execute()
42            .context(format!("failed to compile `{}`", self.path.display()))
43    }
44
45    fn inner_execute(&self) -> Result<()> {
46        let target = self
47            .target_triple
48            .as_ref()
49            .map(|target_triple| {
50                let mut features = self
51                    .cpu_features
52                    .clone()
53                    .into_iter()
54                    .fold(CpuFeature::set(), |a, b| a | b);
55                // Cranelift requires SSE2, so we have this "hack" for now to facilitate
56                // usage
57                if target_triple.architecture == Architecture::X86_64 {
58                    features |= CpuFeature::SSE2;
59                }
60                Target::new(target_triple.clone(), features)
61            })
62            .unwrap_or_default();
63
64        let module_contents = std::fs::read(&self.path)?;
65        if !is_wasm(&module_contents) {
66            bail!("`wasmer compile` only compiles WebAssembly files");
67        }
68
69        let mut engine = self.rt.get_engine_for_module(&module_contents, &target)?;
70
71        let hash_algorithm = self.hash_algorithm.unwrap_or_default().into();
72        engine.set_hash_algorithm(Some(hash_algorithm));
73
74        let output_filename = self
75            .output
76            .file_stem()
77            .map(|osstr| osstr.to_string_lossy().to_string())
78            .unwrap_or_default();
79        // wasmu stands for "WASM Universal"
80        let recommended_extension = "wasmu";
81        match self.output.extension() {
82            Some(ext) => {
83                if ext != recommended_extension {
84                    warning!(
85                        "the output file has a wrong extension. We recommend using `{}.{}` for the chosen target",
86                        &output_filename,
87                        &recommended_extension
88                    )
89                }
90            }
91            None => {
92                warning!(
93                    "the output file has no extension. We recommend using `{}.{}` for the chosen target",
94                    &output_filename,
95                    &recommended_extension
96                )
97            }
98        }
99        println!("Compiler: {}", engine.deterministic_id());
100        println!("Target: {}", target.triple());
101
102        let module = Module::new(&engine, &module_contents)?;
103        module.serialize_to_file(&self.output)?;
104        eprintln!(
105            "✔ File compiled successfully to `{}`.",
106            self.output.display(),
107        );
108
109        Ok(())
110    }
111}