mirror of
https://github.com/mii443/wasmer.git
synced 2025-12-06 20:58:28 +00:00
Add first draft of wasmer create-exe
This commit is contained in:
1
Cargo.lock
generated
1
Cargo.lock
generated
@@ -2213,6 +2213,7 @@ dependencies = [
|
|||||||
"fern",
|
"fern",
|
||||||
"log",
|
"log",
|
||||||
"structopt",
|
"structopt",
|
||||||
|
"tempfile",
|
||||||
"wasmer",
|
"wasmer",
|
||||||
"wasmer-cache",
|
"wasmer-cache",
|
||||||
"wasmer-compiler",
|
"wasmer-compiler",
|
||||||
|
|||||||
@@ -28,6 +28,9 @@
|
|||||||
# define DEPRECATED(message) __declspec(deprecated(message))
|
# define DEPRECATED(message) __declspec(deprecated(message))
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// The `jit` feature has been enabled for this build.
|
||||||
|
#define WASMER_JIT_ENABLED
|
||||||
|
|
||||||
// The `compiler` feature has been enabled for this build.
|
// The `compiler` feature has been enabled for this build.
|
||||||
#define WASMER_COMPILER_ENABLED
|
#define WASMER_COMPILER_ENABLED
|
||||||
|
|
||||||
|
|||||||
@@ -45,6 +45,7 @@ cfg-if = "0.1"
|
|||||||
# For debug feature
|
# For debug feature
|
||||||
fern = { version = "0.6", features = ["colored"], optional = true }
|
fern = { version = "0.6", features = ["colored"], optional = true }
|
||||||
log = { version = "0.4", optional = true }
|
log = { version = "0.4", optional = true }
|
||||||
|
tempfile = "3"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
# Don't add the compiler features in default, please add them on the Makefile
|
# Don't add the compiler features in default, please add them on the Makefile
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
|
#[cfg(feature = "object-file")]
|
||||||
|
use wasmer_cli::commands::CreateExe;
|
||||||
#[cfg(feature = "wast")]
|
#[cfg(feature = "wast")]
|
||||||
use wasmer_cli::commands::Wast;
|
use wasmer_cli::commands::Wast;
|
||||||
use wasmer_cli::commands::{Cache, Compile, Config, Inspect, Run, SelfUpdate, Validate};
|
use wasmer_cli::commands::{Cache, Compile, Config, Inspect, Run, SelfUpdate, Validate};
|
||||||
@@ -26,6 +28,11 @@ enum WasmerCLIOptions {
|
|||||||
#[structopt(name = "compile")]
|
#[structopt(name = "compile")]
|
||||||
Compile(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
|
/// Get various configuration information needed
|
||||||
/// to compile programs which use Wasmer
|
/// to compile programs which use Wasmer
|
||||||
#[structopt(name = "config")]
|
#[structopt(name = "config")]
|
||||||
@@ -53,6 +60,8 @@ impl WasmerCLIOptions {
|
|||||||
Self::Cache(cache) => cache.execute(),
|
Self::Cache(cache) => cache.execute(),
|
||||||
Self::Validate(validate) => validate.execute(),
|
Self::Validate(validate) => validate.execute(),
|
||||||
Self::Compile(compile) => compile.execute(),
|
Self::Compile(compile) => compile.execute(),
|
||||||
|
#[cfg(feature = "object-file")]
|
||||||
|
Self::CreateExe(create_exe) => create_exe.execute(),
|
||||||
Self::Config(config) => config.execute(),
|
Self::Config(config) => config.execute(),
|
||||||
Self::Inspect(inspect) => inspect.execute(),
|
Self::Inspect(inspect) => inspect.execute(),
|
||||||
#[cfg(feature = "wast")]
|
#[cfg(feature = "wast")]
|
||||||
|
|||||||
@@ -2,6 +2,8 @@
|
|||||||
mod cache;
|
mod cache;
|
||||||
mod compile;
|
mod compile;
|
||||||
mod config;
|
mod config;
|
||||||
|
#[cfg(feature = "object-file")]
|
||||||
|
mod create_exe;
|
||||||
mod inspect;
|
mod inspect;
|
||||||
mod run;
|
mod run;
|
||||||
mod self_update;
|
mod self_update;
|
||||||
@@ -9,6 +11,8 @@ mod validate;
|
|||||||
#[cfg(feature = "wast")]
|
#[cfg(feature = "wast")]
|
||||||
mod wast;
|
mod wast;
|
||||||
|
|
||||||
|
#[cfg(feature = "object-file")]
|
||||||
|
pub use create_exe::*;
|
||||||
#[cfg(feature = "wast")]
|
#[cfg(feature = "wast")]
|
||||||
pub use wast::*;
|
pub use wast::*;
|
||||||
pub use {cache::*, compile::*, config::*, inspect::*, run::*, self_update::*, validate::*};
|
pub use {cache::*, compile::*, config::*, inspect::*, run::*, self_update::*, validate::*};
|
||||||
|
|||||||
@@ -38,8 +38,7 @@ impl Compile {
|
|||||||
.context(format!("failed to compile `{}`", self.path.display()))
|
.context(format!("failed to compile `{}`", self.path.display()))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_recommend_extension(
|
pub(crate) fn get_recommend_extension(
|
||||||
&self,
|
|
||||||
engine_type: &EngineType,
|
engine_type: &EngineType,
|
||||||
target_triple: &Triple,
|
target_triple: &Triple,
|
||||||
) -> &'static str {
|
) -> &'static str {
|
||||||
@@ -82,7 +81,7 @@ impl Compile {
|
|||||||
.file_stem()
|
.file_stem()
|
||||||
.map(|osstr| osstr.to_string_lossy().to_string())
|
.map(|osstr| osstr.to_string_lossy().to_string())
|
||||||
.unwrap_or_default();
|
.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() {
|
match self.output.extension() {
|
||||||
Some(ext) => {
|
Some(ext) => {
|
||||||
if ext != recommended_extension {
|
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;
|
use wasmer_compiler::CompilerConfig;
|
||||||
|
|
||||||
#[derive(Debug, Clone, StructOpt)]
|
#[derive(Debug, Clone, StructOpt)]
|
||||||
/// The compiler options
|
/// The compiler and engine options
|
||||||
pub struct StoreOptions {
|
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.
|
/// Use Singlepass compiler.
|
||||||
#[structopt(long, conflicts_with_all = &["cranelift", "llvm", "backend"])]
|
#[structopt(long, conflicts_with_all = &["cranelift", "llvm", "backend"])]
|
||||||
singlepass: bool,
|
singlepass: bool,
|
||||||
@@ -36,19 +55,7 @@ pub struct StoreOptions {
|
|||||||
#[structopt(long, parse(from_os_str))]
|
#[structopt(long, parse(from_os_str))]
|
||||||
llvm_debug_dir: Option<PathBuf>,
|
llvm_debug_dir: Option<PathBuf>,
|
||||||
|
|
||||||
/// Use JIT Engine.
|
/// The deprecated backend flag - Please do not use
|
||||||
#[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
|
|
||||||
#[structopt(long = "backend", hidden = true, conflicts_with_all = &["singlepass", "cranelift", "llvm"])]
|
#[structopt(long = "backend", hidden = true, conflicts_with_all = &["singlepass", "cranelift", "llvm"])]
|
||||||
backend: Option<String>,
|
backend: Option<String>,
|
||||||
|
|
||||||
@@ -56,80 +63,8 @@ pub struct StoreOptions {
|
|||||||
features: WasmFeatures,
|
features: WasmFeatures,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The compiler used for the store
|
#[cfg(feature = "compiler")]
|
||||||
#[derive(Debug, PartialEq, Eq)]
|
impl CompilerOptions {
|
||||||
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 {
|
|
||||||
fn get_compiler(&self) -> Result<CompilerType> {
|
fn get_compiler(&self) -> Result<CompilerType> {
|
||||||
if self.cranelift {
|
if self.cranelift {
|
||||||
Ok(CompilerType::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> {
|
pub fn get_features(&self, mut features: Features) -> Result<Features> {
|
||||||
if self.features.threads || self.features.all {
|
if self.features.threads || self.features.all {
|
||||||
features.threads(true);
|
features.threads(true);
|
||||||
@@ -181,6 +116,63 @@ impl StoreOptions {
|
|||||||
Ok(features)
|
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
|
/// Get the Compiler Config for the current options
|
||||||
#[allow(unused_variables)]
|
#[allow(unused_variables)]
|
||||||
pub(crate) fn get_compiler_config(&self) -> Result<(Box<dyn CompilerConfig>, CompilerType)> {
|
pub(crate) fn get_compiler_config(&self) -> Result<(Box<dyn CompilerConfig>, CompilerType)> {
|
||||||
@@ -315,7 +307,82 @@ impl StoreOptions {
|
|||||||
#[allow(unreachable_code)]
|
#[allow(unreachable_code)]
|
||||||
Ok((compiler_config, compiler))
|
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
|
/// Gets the store for the host target, with the engine name and compiler name selected
|
||||||
pub fn get_store(&self) -> Result<(Store, EngineType, CompilerType)> {
|
pub fn get_store(&self) -> Result<(Store, EngineType, CompilerType)> {
|
||||||
let target = Target::default();
|
let target = Target::default();
|
||||||
@@ -327,7 +394,7 @@ impl StoreOptions {
|
|||||||
&self,
|
&self,
|
||||||
target: Target,
|
target: Target,
|
||||||
) -> Result<(Store, EngineType, CompilerType)> {
|
) -> 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 (engine, engine_type) = self.get_engine_with_compiler(target, compiler_config)?;
|
||||||
let store = Store::new(&*engine);
|
let store = Store::new(&*engine);
|
||||||
Ok((store, engine_type, compiler_type))
|
Ok((store, engine_type, compiler_type))
|
||||||
@@ -339,41 +406,10 @@ impl StoreOptions {
|
|||||||
compiler_config: Box<dyn CompilerConfig>,
|
compiler_config: Box<dyn CompilerConfig>,
|
||||||
) -> Result<(Box<dyn Engine + Send + Sync>, EngineType)> {
|
) -> Result<(Box<dyn Engine + Send + Sync>, EngineType)> {
|
||||||
let engine_type = self.get_engine()?;
|
let engine_type = self.get_engine()?;
|
||||||
let features = self.get_features(compiler_config.default_features_for_target(&target))?;
|
let engine = self
|
||||||
let engine: Box<dyn Engine + Send + Sync> = match engine_type {
|
.compiler
|
||||||
#[cfg(feature = "jit")]
|
.get_engine_by_type(target, compiler_config, engine_type)?;
|
||||||
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, engine_type))
|
Ok((engine, engine_type))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user