wasmer_compiler_cli/commands/
compile.rs

1use crate::store::StoreOptions;
2use crate::warning;
3use anyhow::{Context, Result};
4use clap::Parser;
5use std::fs;
6use std::path::{Path, PathBuf};
7use wasmer_compiler::{ArtifactBuild, ArtifactCreate, ModuleEnvironment};
8use wasmer_types::entity::PrimaryMap;
9use wasmer_types::target::{Architecture, CpuFeature, Target, Triple};
10use wasmer_types::{CompileError, MemoryIndex, MemoryStyle, TableIndex, TableStyle};
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    store: StoreOptions,
29
30    #[clap(short = 'm')]
31    cpu_features: Vec<CpuFeature>,
32}
33
34impl Compile {
35    /// Runs logic for the `compile` subcommand
36    pub fn execute(&self) -> Result<()> {
37        self.inner_execute()
38            .context(format!("failed to compile `{}`", self.path.display()))
39    }
40
41    fn inner_execute(&self) -> Result<()> {
42        let target = self
43            .target_triple
44            .as_ref()
45            .map(|target_triple| {
46                let mut features = self
47                    .cpu_features
48                    .clone()
49                    .into_iter()
50                    .fold(CpuFeature::set(), |a, b| a | b);
51                // Cranelift requires SSE2, so we have this "hack" for now to facilitate
52                // usage
53                if target_triple.architecture == Architecture::X86_64 {
54                    features |= CpuFeature::SSE2;
55                }
56                Target::new(target_triple.clone(), features)
57            })
58            .unwrap_or_default();
59        let (engine_builder, compiler_type) = self.store.get_engine_for_target(target.clone())?;
60        let engine = engine_builder
61            .set_hash_algorithm(Some(wasmer_types::HashAlgorithm::Sha256))
62            .engine();
63        let output_filename = self
64            .output
65            .file_stem()
66            .map(|osstr| osstr.to_string_lossy().to_string())
67            .unwrap_or_default();
68        // `.wasmu` is the default extension for all the triples. It
69        // 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        let tunables = self.store.get_tunables_for_target(&target)?;
90
91        println!("Compiler: {compiler_type}");
92        println!("Target: {}", target.triple());
93
94        // compile and save the artifact (without using module from api)
95        let path: &Path = self.path.as_ref();
96        let wasm_bytes = std::fs::read(path)?;
97        let environ = ModuleEnvironment::new();
98        let translation = environ.translate(&wasm_bytes).map_err(CompileError::Wasm)?;
99        let module = translation.module;
100        let memory_styles: PrimaryMap<MemoryIndex, MemoryStyle> = module
101            .memories
102            .values()
103            .map(|memory_type| tunables.memory_style(memory_type))
104            .collect();
105        let table_styles: PrimaryMap<TableIndex, TableStyle> = module
106            .tables
107            .values()
108            .map(|table_type| tunables.table_style(table_type))
109            .collect();
110        let artifact = ArtifactBuild::new(
111            &mut engine.inner_mut(),
112            &wasm_bytes,
113            &target,
114            memory_styles,
115            table_styles,
116            engine.hash_algorithm(),
117        )?;
118        let serialized = artifact.serialize()?;
119        fs::write(output_filename, serialized)?;
120        eprintln!(
121            "✔ File compiled successfully to `{}`.",
122            self.output.display(),
123        );
124
125        Ok(())
126    }
127}