mirror of
https://github.com/mii443/wasmer.git
synced 2025-12-06 04:38:25 +00:00
Add first draft of wasmer create-exe
This commit is contained in:
@@ -1,4 +1,6 @@
|
||||
use anyhow::Result;
|
||||
#[cfg(feature = "object-file")]
|
||||
use wasmer_cli::commands::CreateExe;
|
||||
#[cfg(feature = "wast")]
|
||||
use wasmer_cli::commands::Wast;
|
||||
use wasmer_cli::commands::{Cache, Compile, Config, Inspect, Run, SelfUpdate, Validate};
|
||||
@@ -26,6 +28,11 @@ enum WasmerCLIOptions {
|
||||
#[structopt(name = "compile")]
|
||||
Compile(Compile),
|
||||
|
||||
/// Compile a WebAssembly binary into a native executable
|
||||
#[cfg(feature = "object-file")]
|
||||
#[structopt(name = "create-exe")]
|
||||
CreateExe(CreateExe),
|
||||
|
||||
/// Get various configuration information needed
|
||||
/// to compile programs which use Wasmer
|
||||
#[structopt(name = "config")]
|
||||
@@ -53,6 +60,8 @@ impl WasmerCLIOptions {
|
||||
Self::Cache(cache) => cache.execute(),
|
||||
Self::Validate(validate) => validate.execute(),
|
||||
Self::Compile(compile) => compile.execute(),
|
||||
#[cfg(feature = "object-file")]
|
||||
Self::CreateExe(create_exe) => create_exe.execute(),
|
||||
Self::Config(config) => config.execute(),
|
||||
Self::Inspect(inspect) => inspect.execute(),
|
||||
#[cfg(feature = "wast")]
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
mod cache;
|
||||
mod compile;
|
||||
mod config;
|
||||
#[cfg(feature = "object-file")]
|
||||
mod create_exe;
|
||||
mod inspect;
|
||||
mod run;
|
||||
mod self_update;
|
||||
@@ -9,6 +11,8 @@ mod validate;
|
||||
#[cfg(feature = "wast")]
|
||||
mod wast;
|
||||
|
||||
#[cfg(feature = "object-file")]
|
||||
pub use create_exe::*;
|
||||
#[cfg(feature = "wast")]
|
||||
pub use wast::*;
|
||||
pub use {cache::*, compile::*, config::*, inspect::*, run::*, self_update::*, validate::*};
|
||||
|
||||
@@ -38,8 +38,7 @@ impl Compile {
|
||||
.context(format!("failed to compile `{}`", self.path.display()))
|
||||
}
|
||||
|
||||
fn get_recommend_extension(
|
||||
&self,
|
||||
pub(crate) fn get_recommend_extension(
|
||||
engine_type: &EngineType,
|
||||
target_triple: &Triple,
|
||||
) -> &'static str {
|
||||
@@ -82,7 +81,7 @@ impl Compile {
|
||||
.file_stem()
|
||||
.map(|osstr| osstr.to_string_lossy().to_string())
|
||||
.unwrap_or_default();
|
||||
let recommended_extension = self.get_recommend_extension(&engine_type, target.triple());
|
||||
let recommended_extension = Self::get_recommend_extension(&engine_type, target.triple());
|
||||
match self.output.extension() {
|
||||
Some(ext) => {
|
||||
if ext != recommended_extension {
|
||||
|
||||
273
lib/cli/src/commands/create_exe.rs
Normal file
273
lib/cli/src/commands/create_exe.rs
Normal file
@@ -0,0 +1,273 @@
|
||||
//! Create a standalone native executable for a given Wasm file.
|
||||
|
||||
use crate::store::{CompilerOptions, EngineType};
|
||||
use anyhow::{Context, Result};
|
||||
use std::env;
|
||||
use std::fs;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::process::Command;
|
||||
use structopt::StructOpt;
|
||||
use wasmer::*;
|
||||
|
||||
const WASMER_MAIN_C_SOURCE: &[u8] = include_bytes!("wasmer_create_exe_main.c");
|
||||
|
||||
// TODO: to get this working locally I had to add wasmer_wasm.h and wasm.h to `.wasmer/include` manually.
|
||||
// this needs to be fixed before we can ship this.
|
||||
|
||||
#[derive(Debug, StructOpt)]
|
||||
/// The options for the `wasmer create-exe` subcommand
|
||||
pub struct CreateExe {
|
||||
/// Input file
|
||||
#[structopt(name = "FILE", parse(from_os_str))]
|
||||
path: PathBuf,
|
||||
|
||||
/// Output file
|
||||
#[structopt(name = "OUTPUT PATH", short = "o", parse(from_os_str))]
|
||||
output: PathBuf,
|
||||
|
||||
/// Compilation Target triple
|
||||
#[structopt(long = "target")]
|
||||
target_triple: Option<Triple>,
|
||||
|
||||
#[structopt(flatten)]
|
||||
compiler: CompilerOptions,
|
||||
|
||||
#[structopt(short = "m", multiple = true)]
|
||||
cpu_features: Vec<CpuFeature>,
|
||||
|
||||
/// Additional libraries to link against.
|
||||
/// This is useful for fixing linker errors that may occur on some systems.
|
||||
#[structopt(short = "l", multiple = true)]
|
||||
libraries: Vec<String>,
|
||||
}
|
||||
|
||||
impl CreateExe {
|
||||
/// Runs logic for the `compile` subcommand
|
||||
pub fn execute(&self) -> Result<()> {
|
||||
let target = self
|
||||
.target_triple
|
||||
.as_ref()
|
||||
.map(|target_triple| {
|
||||
let mut features = self
|
||||
.cpu_features
|
||||
.clone()
|
||||
.into_iter()
|
||||
.fold(CpuFeature::set(), |a, b| a | b);
|
||||
// Cranelift requires SSE2, so we have this "hack" for now to facilitate
|
||||
// usage
|
||||
features |= CpuFeature::SSE2;
|
||||
Target::new(target_triple.clone(), features)
|
||||
})
|
||||
.unwrap_or_default();
|
||||
let engine_type = EngineType::ObjectFile;
|
||||
let (store, compiler_type) = self
|
||||
.compiler
|
||||
.get_store_for_target_and_engine(target.clone(), engine_type)?;
|
||||
|
||||
println!("Engine: {}", engine_type.to_string());
|
||||
println!("Compiler: {}", compiler_type.to_string());
|
||||
println!("Target: {}", target.triple());
|
||||
|
||||
let working_dir = tempfile::tempdir()?;
|
||||
let starting_cd = env::current_dir()?;
|
||||
let output_path = starting_cd.join(&self.output);
|
||||
env::set_current_dir(&working_dir)?;
|
||||
|
||||
// TODO: encapsulate compile code
|
||||
|
||||
#[cfg(not(windows))]
|
||||
let wasm_object_path = PathBuf::from("wasm.o");
|
||||
#[cfg(windows)]
|
||||
let wasm_object_path = PathBuf::from("wasm.obj");
|
||||
|
||||
let wasm_module_path = starting_cd.join(&self.path);
|
||||
|
||||
let header_file_path = Path::new("my_wasm.h");
|
||||
let module =
|
||||
Module::from_file(&store, &wasm_module_path).context("failed to compile Wasm")?;
|
||||
let _ = module.serialize_to_file(&wasm_object_path)?;
|
||||
|
||||
let artifact: &wasmer_engine_object_file::ObjectFileArtifact =
|
||||
module.artifact().as_ref().downcast_ref().context(
|
||||
"Engine type is ObjectFile but could not downcast artifact into ObjectFileArtifact",
|
||||
)?;
|
||||
let symbol_registry = artifact.symbol_registry();
|
||||
let metadata_length = artifact.metadata_length();
|
||||
let module_info = module.info();
|
||||
let header_file_src = crate::c_gen::object_file_header::generate_header_file(
|
||||
module_info,
|
||||
symbol_registry,
|
||||
metadata_length,
|
||||
);
|
||||
|
||||
let header_path = header_file_path.clone();
|
||||
// for C code
|
||||
let mut header = std::fs::OpenOptions::new()
|
||||
.create(true)
|
||||
.truncate(true)
|
||||
.write(true)
|
||||
.open(&header_path)?;
|
||||
|
||||
use std::io::Write;
|
||||
header.write(header_file_src.as_bytes())?;
|
||||
|
||||
// auto compilation
|
||||
//
|
||||
|
||||
// write C src to disk
|
||||
let c_src_path = Path::new("wasmer_main.c");
|
||||
#[cfg(not(windows))]
|
||||
let c_src_obj = PathBuf::from("wasmer_main.o");
|
||||
#[cfg(windows)]
|
||||
let c_src_obj = PathBuf::from("wasmer_main.obj");
|
||||
|
||||
{
|
||||
let mut c_src_file = fs::OpenOptions::new()
|
||||
.create_new(true)
|
||||
.write(true)
|
||||
.open(&c_src_path)
|
||||
.context("Failed to open C source code file")?;
|
||||
// TODO:
|
||||
c_src_file.write_all(WASMER_MAIN_C_SOURCE)?;
|
||||
}
|
||||
run_c_compile(&c_src_path, &c_src_obj).context("Failed to compile C source code")?;
|
||||
LinkCode {
|
||||
object_paths: vec![c_src_obj, wasm_object_path],
|
||||
output_path,
|
||||
additional_libraries: self.libraries.clone(),
|
||||
..Default::default()
|
||||
}
|
||||
.run()
|
||||
.context("Failed to link objects together")?;
|
||||
|
||||
eprintln!(
|
||||
"✔ Native executable compiled successfully to `{}`.",
|
||||
self.output.display(),
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn get_wasmer_include_directory() -> anyhow::Result<PathBuf> {
|
||||
let mut path = PathBuf::from(env::var("WASMER_DIR")?);
|
||||
path.push("include");
|
||||
Ok(path)
|
||||
}
|
||||
|
||||
fn get_libwasmer_path() -> anyhow::Result<PathBuf> {
|
||||
let mut path = PathBuf::from(env::var("WASMER_DIR")?);
|
||||
path.push("lib");
|
||||
|
||||
#[cfg(not(windows))]
|
||||
path.push("libwasmer.a");
|
||||
#[cfg(windows)]
|
||||
path.push("libwasmer.lib");
|
||||
|
||||
Ok(path)
|
||||
}
|
||||
|
||||
/// Compile the C code.
|
||||
fn run_c_compile(path_to_c_src: &Path, output_name: &Path) -> anyhow::Result<()> {
|
||||
#[cfg(not(windows))]
|
||||
let c_compiler = "cc";
|
||||
#[cfg(windows)]
|
||||
let c_compiler = "clang++";
|
||||
|
||||
let output = Command::new(c_compiler)
|
||||
.arg("-O2")
|
||||
.arg("-c")
|
||||
.arg(path_to_c_src)
|
||||
.arg("-I")
|
||||
.arg(get_wasmer_include_directory()?)
|
||||
.arg("-o")
|
||||
.arg(output_name)
|
||||
.output()?;
|
||||
|
||||
if !output.status.success() {
|
||||
bail!(
|
||||
"C code compile failed with: stdout: {}\n\nstderr: {}",
|
||||
std::str::from_utf8(&output.stdout)
|
||||
.expect("stdout is not utf8! need to handle arbitrary bytes"),
|
||||
std::str::from_utf8(&output.stderr)
|
||||
.expect("stderr is not utf8! need to handle arbitrary bytes")
|
||||
);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Data used to run a linking command for generated artifacts.
|
||||
#[derive(Debug)]
|
||||
struct LinkCode {
|
||||
/// Path to the linker used to run the linking command.
|
||||
linker_path: PathBuf,
|
||||
/// String used as an optimization flag.
|
||||
optimization_flag: String,
|
||||
/// Paths of objects to link.
|
||||
object_paths: Vec<PathBuf>,
|
||||
/// Additional libraries to link against.
|
||||
additional_libraries: Vec<String>,
|
||||
/// Path to the output target.
|
||||
output_path: PathBuf,
|
||||
/// Path to the static libwasmer library.
|
||||
libwasmer_path: PathBuf,
|
||||
}
|
||||
|
||||
impl Default for LinkCode {
|
||||
fn default() -> Self {
|
||||
#[cfg(not(windows))]
|
||||
let linker = "cc";
|
||||
#[cfg(windows)]
|
||||
let linker = "clang";
|
||||
Self {
|
||||
linker_path: PathBuf::from(linker),
|
||||
optimization_flag: String::from("-O2"),
|
||||
object_paths: vec![],
|
||||
additional_libraries: vec![],
|
||||
output_path: PathBuf::from("a.out"),
|
||||
libwasmer_path: get_libwasmer_path().unwrap(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl LinkCode {
|
||||
// TODO: `wasmer create-exe` needs a command line flag for extra libraries to link aganist
|
||||
// or perhaps we just want to add a flag for passing things to the linker
|
||||
fn run(&self) -> anyhow::Result<()> {
|
||||
let mut command = Command::new(&self.linker_path);
|
||||
let command = command
|
||||
.arg(&self.optimization_flag)
|
||||
.args(
|
||||
self.object_paths
|
||||
.iter()
|
||||
.map(|path| path.canonicalize().unwrap()),
|
||||
)
|
||||
.arg(
|
||||
&self
|
||||
.libwasmer_path
|
||||
.canonicalize()
|
||||
.context("Failed to find libwasmer")?,
|
||||
);
|
||||
#[cfg(windows)]
|
||||
let command = command.arg("-luserenv").arg("-lWs2_32").arg("-ladvapi32");
|
||||
#[cfg(not(windows))]
|
||||
let command = command.arg("-ldl").arg("-lm").arg("-pthread");
|
||||
let link_aganist_extra_libs = self
|
||||
.additional_libraries
|
||||
.iter()
|
||||
.map(|lib| format!("-l{}", lib));
|
||||
let command = command.args(link_aganist_extra_libs);
|
||||
let output = command.arg("-o").arg(&self.output_path).output()?;
|
||||
|
||||
if !output.status.success() {
|
||||
bail!(
|
||||
"linking failed with: stdout: {}\n\nstderr: {}",
|
||||
std::str::from_utf8(&output.stdout)
|
||||
.expect("stdout is not utf8! need to handle arbitrary bytes"),
|
||||
std::str::from_utf8(&output.stderr)
|
||||
.expect("stderr is not utf8! need to handle arbitrary bytes")
|
||||
);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
89
lib/cli/src/commands/wasmer_create_exe_main.c
Normal file
89
lib/cli/src/commands/wasmer_create_exe_main.c
Normal file
@@ -0,0 +1,89 @@
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "wasmer_wasm.h"
|
||||
#include "wasm.h"
|
||||
#include "my_wasm.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
void print_wasmer_error()
|
||||
{
|
||||
int error_len = wasmer_last_error_length();
|
||||
printf("Error len: `%d`\n", error_len);
|
||||
char* error_str = (char*) malloc(error_len);
|
||||
wasmer_last_error_message(error_str, error_len);
|
||||
printf("Error str: `%s`\n", error_str);
|
||||
}
|
||||
|
||||
int main() {
|
||||
printf("Initializing...\n");
|
||||
wasm_config_t* config = wasm_config_new();
|
||||
wasm_config_set_engine(config, OBJECT_FILE);
|
||||
wasm_engine_t* engine = wasm_engine_new_with_config(config);
|
||||
wasm_store_t* store = wasm_store_new(engine);
|
||||
|
||||
wasm_module_t* module = wasmer_object_file_engine_new(store, "qjs.wasm");
|
||||
if (! module) {
|
||||
printf("Failed to create module\n");
|
||||
print_wasmer_error();
|
||||
return -1;
|
||||
}
|
||||
|
||||
// We have now finished the memory buffer book keeping and we have a valid Module.
|
||||
|
||||
// In this example we're passing some JavaScript source code as a command line argument
|
||||
// to a WASI module that can evaluate JavaScript.
|
||||
wasi_config_t* wasi_config = wasi_config_new("constant_value_here");
|
||||
const char* js_string = "function greet(name) { return JSON.stringify('Hello, ' + name); }; print(greet('World'));";
|
||||
wasi_config_arg(wasi_config, "--eval");
|
||||
wasi_config_arg(wasi_config, js_string);
|
||||
wasi_env_t* wasi_env = wasi_env_new(wasi_config);
|
||||
if (!wasi_env) {
|
||||
printf("> Error building WASI env!\n");
|
||||
print_wasmer_error();
|
||||
return 1;
|
||||
}
|
||||
|
||||
wasm_importtype_vec_t import_types;
|
||||
wasm_module_imports(module, &import_types);
|
||||
int num_imports = import_types.size;
|
||||
wasm_extern_t** imports = (wasm_extern_t**) malloc(num_imports * sizeof(wasm_extern_t*));
|
||||
wasm_importtype_vec_delete(&import_types);
|
||||
|
||||
bool get_imports_result = wasi_get_imports(store, module, wasi_env, imports);
|
||||
if (!get_imports_result) {
|
||||
printf("> Error getting WASI imports!\n");
|
||||
print_wasmer_error();
|
||||
return 1;
|
||||
}
|
||||
|
||||
wasm_instance_t* instance = wasm_instance_new(store, module, (const wasm_extern_t* const*) imports, NULL);
|
||||
if (! instance) {
|
||||
printf("Failed to create instance\n");
|
||||
print_wasmer_error();
|
||||
return -1;
|
||||
}
|
||||
wasi_env_set_instance(wasi_env, instance);
|
||||
|
||||
// WASI is now set up.
|
||||
|
||||
void* vmctx = wasm_instance_get_vmctx_ptr(instance);
|
||||
wasm_val_t* inout[2] = { NULL, NULL };
|
||||
|
||||
fflush(stdout);
|
||||
// We're able to call our compiled function directly through a trampoline.
|
||||
wasmer_trampoline_function_call__1(vmctx, wasmer_function__1, &inout);
|
||||
|
||||
wasm_instance_delete(instance);
|
||||
wasm_module_delete(module);
|
||||
wasm_store_delete(store);
|
||||
wasm_engine_delete(engine);
|
||||
return 0;
|
||||
}
|
||||
@@ -14,8 +14,27 @@ use wasmer::*;
|
||||
use wasmer_compiler::CompilerConfig;
|
||||
|
||||
#[derive(Debug, Clone, StructOpt)]
|
||||
/// The compiler options
|
||||
/// The compiler and engine options
|
||||
pub struct StoreOptions {
|
||||
#[structopt(flatten)]
|
||||
compiler: CompilerOptions,
|
||||
|
||||
/// Use JIT Engine.
|
||||
#[structopt(long, conflicts_with_all = &["native", "object_file"])]
|
||||
jit: bool,
|
||||
|
||||
/// Use Native Engine.
|
||||
#[structopt(long, conflicts_with_all = &["jit", "object_file"])]
|
||||
native: bool,
|
||||
|
||||
/// Use ObjectFile Engine.
|
||||
#[structopt(long, conflicts_with_all = &["jit", "native"])]
|
||||
object_file: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, StructOpt)]
|
||||
/// The compiler options
|
||||
pub struct CompilerOptions {
|
||||
/// Use Singlepass compiler.
|
||||
#[structopt(long, conflicts_with_all = &["cranelift", "llvm", "backend"])]
|
||||
singlepass: bool,
|
||||
@@ -36,19 +55,7 @@ pub struct StoreOptions {
|
||||
#[structopt(long, parse(from_os_str))]
|
||||
llvm_debug_dir: Option<PathBuf>,
|
||||
|
||||
/// Use JIT Engine.
|
||||
#[structopt(long, conflicts_with_all = &["native", "object_file"])]
|
||||
jit: bool,
|
||||
|
||||
/// Use Native Engine.
|
||||
#[structopt(long, conflicts_with_all = &["jit", "object_file"])]
|
||||
native: bool,
|
||||
|
||||
/// Use ObjectFile Engine.
|
||||
#[structopt(long, conflicts_with_all = &["jit", "native"])]
|
||||
object_file: bool,
|
||||
|
||||
/// The deprecated backend flag - Please not use
|
||||
/// The deprecated backend flag - Please do not use
|
||||
#[structopt(long = "backend", hidden = true, conflicts_with_all = &["singlepass", "cranelift", "llvm"])]
|
||||
backend: Option<String>,
|
||||
|
||||
@@ -56,80 +63,8 @@ pub struct StoreOptions {
|
||||
features: WasmFeatures,
|
||||
}
|
||||
|
||||
/// The compiler used for the store
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub enum CompilerType {
|
||||
/// Singlepass compiler
|
||||
Singlepass,
|
||||
/// Cranelift compiler
|
||||
Cranelift,
|
||||
/// LLVM compiler
|
||||
LLVM,
|
||||
/// Headless compiler
|
||||
Headless,
|
||||
}
|
||||
|
||||
impl CompilerType {
|
||||
/// Return all enabled compilers
|
||||
pub fn enabled() -> Vec<CompilerType> {
|
||||
vec![
|
||||
#[cfg(feature = "singlepass")]
|
||||
Self::Singlepass,
|
||||
#[cfg(feature = "cranelift")]
|
||||
Self::Cranelift,
|
||||
#[cfg(feature = "llvm")]
|
||||
Self::LLVM,
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
impl ToString for CompilerType {
|
||||
fn to_string(&self) -> String {
|
||||
match self {
|
||||
Self::Singlepass => "singlepass".to_string(),
|
||||
Self::Cranelift => "cranelift".to_string(),
|
||||
Self::LLVM => "llvm".to_string(),
|
||||
Self::Headless => "headless".to_string(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStr for CompilerType {
|
||||
type Err = Error;
|
||||
fn from_str(s: &str) -> Result<Self> {
|
||||
match s {
|
||||
"singlepass" => Ok(Self::Singlepass),
|
||||
"cranelift" => Ok(Self::Cranelift),
|
||||
"llvm" => Ok(Self::LLVM),
|
||||
"headless" => Ok(Self::Headless),
|
||||
backend => bail!("The `{}` compiler does not exist.", backend),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The engine used for the store
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub enum EngineType {
|
||||
/// JIT Engine
|
||||
JIT,
|
||||
/// Native Engine
|
||||
Native,
|
||||
/// Object File Engine
|
||||
ObjectFile,
|
||||
}
|
||||
|
||||
impl ToString for EngineType {
|
||||
fn to_string(&self) -> String {
|
||||
match self {
|
||||
Self::JIT => "jit".to_string(),
|
||||
Self::Native => "native".to_string(),
|
||||
Self::ObjectFile => "objectfile".to_string(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(all(feature = "compiler", feature = "engine"))]
|
||||
impl StoreOptions {
|
||||
#[cfg(feature = "compiler")]
|
||||
impl CompilerOptions {
|
||||
fn get_compiler(&self) -> Result<CompilerType> {
|
||||
if self.cranelift {
|
||||
Ok(CompilerType::Cranelift)
|
||||
@@ -161,7 +96,7 @@ impl StoreOptions {
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the Target architecture
|
||||
/// Get the enaled Wasm features.
|
||||
pub fn get_features(&self, mut features: Features) -> Result<Features> {
|
||||
if self.features.threads || self.features.all {
|
||||
features.threads(true);
|
||||
@@ -181,6 +116,63 @@ impl StoreOptions {
|
||||
Ok(features)
|
||||
}
|
||||
|
||||
/// Gets the Store for a given target and engine.
|
||||
pub fn get_store_for_target_and_engine(
|
||||
&self,
|
||||
target: Target,
|
||||
engine_type: EngineType,
|
||||
) -> Result<(Store, CompilerType)> {
|
||||
let (compiler_config, compiler_type) = self.get_compiler_config()?;
|
||||
let engine = self.get_engine_by_type(target, compiler_config, engine_type)?;
|
||||
let store = Store::new(&*engine);
|
||||
Ok((store, compiler_type))
|
||||
}
|
||||
|
||||
fn get_engine_by_type(
|
||||
&self,
|
||||
target: Target,
|
||||
compiler_config: Box<dyn CompilerConfig>,
|
||||
engine_type: EngineType,
|
||||
) -> Result<Box<dyn Engine + Send + Sync>> {
|
||||
let features = self.get_features(compiler_config.default_features_for_target(&target))?;
|
||||
let engine: Box<dyn Engine + Send + Sync> = match engine_type {
|
||||
#[cfg(feature = "jit")]
|
||||
EngineType::JIT => Box::new(
|
||||
wasmer_engine_jit::JIT::new(&*compiler_config)
|
||||
.features(features)
|
||||
.target(target)
|
||||
.engine(),
|
||||
),
|
||||
#[cfg(feature = "native")]
|
||||
EngineType::Native => {
|
||||
let mut compiler_config = compiler_config;
|
||||
Box::new(
|
||||
wasmer_engine_native::Native::new(&mut *compiler_config)
|
||||
.target(target)
|
||||
.features(features)
|
||||
.engine(),
|
||||
)
|
||||
}
|
||||
#[cfg(feature = "object-file")]
|
||||
EngineType::ObjectFile => {
|
||||
let mut compiler_config = compiler_config;
|
||||
Box::new(
|
||||
wasmer_engine_object_file::ObjectFile::new(&mut *compiler_config)
|
||||
.target(target)
|
||||
.features(features)
|
||||
.engine(),
|
||||
)
|
||||
}
|
||||
#[cfg(not(all(feature = "jit", feature = "native", feature = "object-file")))]
|
||||
engine => bail!(
|
||||
"The `{}` engine is not included in this binary.",
|
||||
engine.to_string()
|
||||
),
|
||||
};
|
||||
|
||||
Ok(engine)
|
||||
}
|
||||
|
||||
/// Get the Compiler Config for the current options
|
||||
#[allow(unused_variables)]
|
||||
pub(crate) fn get_compiler_config(&self) -> Result<(Box<dyn CompilerConfig>, CompilerType)> {
|
||||
@@ -315,7 +307,82 @@ impl StoreOptions {
|
||||
#[allow(unreachable_code)]
|
||||
Ok((compiler_config, compiler))
|
||||
}
|
||||
}
|
||||
|
||||
/// The compiler used for the store
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub enum CompilerType {
|
||||
/// Singlepass compiler
|
||||
Singlepass,
|
||||
/// Cranelift compiler
|
||||
Cranelift,
|
||||
/// LLVM compiler
|
||||
LLVM,
|
||||
/// Headless compiler
|
||||
Headless,
|
||||
}
|
||||
|
||||
impl CompilerType {
|
||||
/// Return all enabled compilers
|
||||
pub fn enabled() -> Vec<CompilerType> {
|
||||
vec![
|
||||
#[cfg(feature = "singlepass")]
|
||||
Self::Singlepass,
|
||||
#[cfg(feature = "cranelift")]
|
||||
Self::Cranelift,
|
||||
#[cfg(feature = "llvm")]
|
||||
Self::LLVM,
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
impl ToString for CompilerType {
|
||||
fn to_string(&self) -> String {
|
||||
match self {
|
||||
Self::Singlepass => "singlepass".to_string(),
|
||||
Self::Cranelift => "cranelift".to_string(),
|
||||
Self::LLVM => "llvm".to_string(),
|
||||
Self::Headless => "headless".to_string(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStr for CompilerType {
|
||||
type Err = Error;
|
||||
fn from_str(s: &str) -> Result<Self> {
|
||||
match s {
|
||||
"singlepass" => Ok(Self::Singlepass),
|
||||
"cranelift" => Ok(Self::Cranelift),
|
||||
"llvm" => Ok(Self::LLVM),
|
||||
"headless" => Ok(Self::Headless),
|
||||
backend => bail!("The `{}` compiler does not exist.", backend),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The engine used for the store
|
||||
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
|
||||
pub enum EngineType {
|
||||
/// JIT Engine
|
||||
JIT,
|
||||
/// Native Engine
|
||||
Native,
|
||||
/// Object File Engine
|
||||
ObjectFile,
|
||||
}
|
||||
|
||||
impl ToString for EngineType {
|
||||
fn to_string(&self) -> String {
|
||||
match self {
|
||||
Self::JIT => "jit".to_string(),
|
||||
Self::Native => "native".to_string(),
|
||||
Self::ObjectFile => "objectfile".to_string(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(all(feature = "compiler", feature = "engine"))]
|
||||
impl StoreOptions {
|
||||
/// Gets the store for the host target, with the engine name and compiler name selected
|
||||
pub fn get_store(&self) -> Result<(Store, EngineType, CompilerType)> {
|
||||
let target = Target::default();
|
||||
@@ -327,7 +394,7 @@ impl StoreOptions {
|
||||
&self,
|
||||
target: Target,
|
||||
) -> Result<(Store, EngineType, CompilerType)> {
|
||||
let (compiler_config, compiler_type) = self.get_compiler_config()?;
|
||||
let (compiler_config, compiler_type) = self.compiler.get_compiler_config()?;
|
||||
let (engine, engine_type) = self.get_engine_with_compiler(target, compiler_config)?;
|
||||
let store = Store::new(&*engine);
|
||||
Ok((store, engine_type, compiler_type))
|
||||
@@ -339,41 +406,10 @@ impl StoreOptions {
|
||||
compiler_config: Box<dyn CompilerConfig>,
|
||||
) -> Result<(Box<dyn Engine + Send + Sync>, EngineType)> {
|
||||
let engine_type = self.get_engine()?;
|
||||
let features = self.get_features(compiler_config.default_features_for_target(&target))?;
|
||||
let engine: Box<dyn Engine + Send + Sync> = match engine_type {
|
||||
#[cfg(feature = "jit")]
|
||||
EngineType::JIT => Box::new(
|
||||
wasmer_engine_jit::JIT::new(&*compiler_config)
|
||||
.features(features)
|
||||
.target(target)
|
||||
.engine(),
|
||||
),
|
||||
#[cfg(feature = "native")]
|
||||
EngineType::Native => {
|
||||
let mut compiler_config = compiler_config;
|
||||
Box::new(
|
||||
wasmer_engine_native::Native::new(&mut *compiler_config)
|
||||
.target(target)
|
||||
.features(features)
|
||||
.engine(),
|
||||
)
|
||||
}
|
||||
#[cfg(feature = "object-file")]
|
||||
EngineType::ObjectFile => {
|
||||
let mut compiler_config = compiler_config;
|
||||
Box::new(
|
||||
wasmer_engine_object_file::ObjectFile::new(&mut *compiler_config)
|
||||
.target(target)
|
||||
.features(features)
|
||||
.engine(),
|
||||
)
|
||||
}
|
||||
#[cfg(not(all(feature = "jit", feature = "native", feature = "object-file")))]
|
||||
engine => bail!(
|
||||
"The `{}` engine is not included in this binary.",
|
||||
engine.to_string()
|
||||
),
|
||||
};
|
||||
let engine = self
|
||||
.compiler
|
||||
.get_engine_by_type(target, compiler_config, engine_type)?;
|
||||
|
||||
Ok((engine, engine_type))
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user