#![allow(dead_code)]
use std::{env, path::PathBuf};
use anyhow::{Context, Result};
use clap::Parser;
use wasmer::*;
use wasmer_package::utils::from_disk;
use crate::store::CompilerOptions;
#[derive(Debug, Parser)]
pub struct CreateObj {
#[clap(name = "FILE")]
path: PathBuf,
#[clap(name = "OUTPUT_PATH", short = 'o')]
output: PathBuf,
#[clap(long, name = "DEBUG PATH")]
debug_dir: Option<PathBuf>,
#[clap(long, name = "PREFIX")]
prefix: Option<String>,
#[clap(long, name = "ATOM")]
atom: Option<String>,
#[clap(long = "target")]
target_triple: Option<Triple>,
#[clap(long, short = 'm', number_of_values = 1)]
cpu_features: Vec<CpuFeature>,
#[clap(flatten)]
compiler: CompilerOptions,
}
impl CreateObj {
pub fn execute(&self) -> Result<()> {
let path = crate::common::normalize_path(&format!("{}", self.path.display()));
let target_triple = self.target_triple.clone().unwrap_or_else(Triple::host);
let starting_cd = env::current_dir()?;
let input_path = starting_cd.join(path);
let temp_dir = tempfile::tempdir();
let output_directory_path = match self.debug_dir.as_ref() {
Some(s) => s.clone(),
None => temp_dir?.path().to_path_buf(),
};
std::fs::create_dir_all(&output_directory_path)?;
let prefix = match self.prefix.as_ref() {
Some(s) => vec![s.clone()],
None => Vec::new(),
};
let target = crate::commands::create_exe::utils::target_triple_to_target(
&target_triple,
&self.cpu_features,
);
let (_, compiler_type) = self.compiler.get_store_for_target(target.clone())?;
println!("Compiler: {compiler_type}");
println!("Target: {}", target.triple());
let atoms = if let Ok(webc) = from_disk(&input_path) {
crate::commands::create_exe::compile_pirita_into_directory(
&webc,
&output_directory_path,
&self.compiler,
&self.cpu_features,
&target_triple,
&prefix,
crate::commands::AllowMultiWasm::Reject(self.atom.clone()),
self.debug_dir.is_some(),
)
} else {
crate::commands::create_exe::prepare_directory_from_single_wasm_file(
&input_path,
&output_directory_path,
&self.compiler,
&target_triple,
&self.cpu_features,
&prefix,
self.debug_dir.is_some(),
)
}?;
let file_paths = std::fs::read_dir(output_directory_path.join("atoms"))
.map_err(|e| {
anyhow::anyhow!(
"could not read {}: {e}",
output_directory_path.join("atoms").display()
)
})?
.filter_map(|path| path.ok()?.path().canonicalize().ok())
.collect::<Vec<_>>();
if file_paths.is_empty() {
return Err(anyhow::anyhow!(
"could not compile object file: no output objects in {}",
output_directory_path.join("atoms").display()
));
}
if file_paths.len() == 1 {
if let Some(parent) = self.output.parent() {
std::fs::create_dir_all(parent)?;
}
std::fs::copy(
std::env::current_dir().unwrap().join(&file_paths[0]),
std::env::current_dir().unwrap().join(&self.output),
)
.map_err(|e| {
anyhow::anyhow!(
"{} -> {}: {e}",
&file_paths[0].display(),
self.output.display()
)
})?;
} else {
let keys = atoms
.iter()
.map(|(name, _)| name.clone())
.collect::<Vec<_>>();
return Err(anyhow::anyhow!(
"where <ATOM> is one of: {}",
keys.join(", ")
))
.context(anyhow::anyhow!(
"note: use --atom <ATOM> to specify which atom to compile"
))
.context(anyhow::anyhow!(
"cannot compile more than one atom at a time"
));
}
let output_file = self.output.canonicalize().unwrap().display().to_string();
let output_file = output_file
.strip_prefix(r"\\?\")
.unwrap_or(&output_file)
.to_string();
eprintln!("✔ Object compiled successfully to `{output_file}`");
Ok(())
}
}