wasmer_cli/commands/
compile.rs

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