Add gen-c-header option

This commit is contained in:
Felix Schütt
2023-01-04 09:44:58 +01:00
parent 3a7307bff9
commit afb9d401cd
6 changed files with 138 additions and 9 deletions

View File

@@ -11,7 +11,8 @@ use crate::commands::CreateObj;
#[cfg(feature = "wast")]
use crate::commands::Wast;
use crate::commands::{
Add, Cache, Config, Init, Inspect, List, Login, Publish, Run, SelfUpdate, Validate, Whoami,
Add, Cache, Config, GenCHeader, Init, Inspect, List, Login, Publish, Run, SelfUpdate, Validate,
Whoami,
};
use crate::error::PrettyError;
use clap::{CommandFactory, ErrorKind, Parser};
@@ -128,6 +129,9 @@ enum WasmerCLIOptions {
#[structopt(name = "create-obj", verbatim_doc_comment)]
CreateObj(CreateObj),
/// Generate the C static_defs.h header file for the input .wasm module
GenCHeader(GenCHeader),
/// Get various configuration information needed
/// to compile programs which use Wasmer
Config(Config),
@@ -177,6 +181,7 @@ impl WasmerCLIOptions {
Self::List(list) => list.execute(),
Self::Login(login) => login.execute(),
Self::Publish(publish) => publish.execute(),
Self::GenCHeader(gen_heder) => gen_heder.execute(),
#[cfg(feature = "wast")]
Self::Wast(wast) => wast.execute(),
#[cfg(target_os = "linux")]
@@ -235,8 +240,8 @@ fn wasmer_main_inner() -> Result<(), anyhow::Error> {
} else {
match command.unwrap_or(&"".to_string()).as_ref() {
"add" | "cache" | "compile" | "config" | "create-obj" | "create-exe" | "help"
| "inspect" | "init" | "run" | "self-update" | "validate" | "wast" | "binfmt"
| "list" | "login" | "publish" => WasmerCLIOptions::parse(),
| "gen-c-header" | "inspect" | "init" | "run" | "self-update" | "validate" | "wast"
| "binfmt" | "list" | "login" | "publish" => WasmerCLIOptions::parse(),
_ => {
WasmerCLIOptions::try_parse_from(args.iter()).unwrap_or_else(|e| {
match e.kind() {

View File

@@ -10,6 +10,7 @@ mod config;
mod create_exe;
#[cfg(feature = "static-artifact-create")]
mod create_obj;
mod gen_c_header;
mod init;
mod inspect;
mod list;
@@ -34,8 +35,8 @@ use serde::{Deserialize, Serialize};
#[cfg(feature = "wast")]
pub use wast::*;
pub use {
add::*, cache::*, config::*, init::*, inspect::*, list::*, login::*, publish::*, run::*,
self_update::*, validate::*, whoami::*,
add::*, cache::*, config::*, gen_c_header::*, init::*, inspect::*, list::*, login::*,
publish::*, run::*, self_update::*, validate::*, whoami::*,
};
/// The kind of object format to emit.

View File

@@ -504,7 +504,7 @@ pub(super) fn compile_pirita_into_directory(
/// Prefix map used during compilation of object files
#[derive(Debug, Default, PartialEq)]
struct PrefixMapCompilation {
pub(crate) struct PrefixMapCompilation {
/// Sha256 hashes for the input files
input_hashes: BTreeMap<String, String>,
/// Manual prefixes for input files (file:prefix)
@@ -638,7 +638,7 @@ impl PrefixMapCompilation {
}
}
fn hash_for_bytes(bytes: &[u8]) -> String {
pub(crate) fn hash_for_bytes(bytes: &[u8]) -> String {
use sha2::{Digest, Sha256};
let mut hasher = Sha256::new();
hasher.update(bytes);
@@ -992,7 +992,7 @@ fn get_module_infos(
}
/// Create the static_defs.h header files in the /include directory
fn create_header_files_in_dir(
pub(crate) fn create_header_files_in_dir(
directory: &Path,
entrypoint: &mut Entrypoint,
atoms: &[(String, Vec<u8>)],

View File

@@ -0,0 +1,69 @@
use crate::store::CompilerOptions;
use anyhow::Context;
use clap::Parser;
use std::path::PathBuf;
use wasmer::Target;
use wasmer_compiler::Artifact;
use wasmer_types::compilation::symbols::ModuleMetadataSymbolRegistry;
use super::normalize_path;
#[derive(Debug, Parser)]
/// The options for the `wasmer gen-c-header` subcommand
pub struct GenCHeader {
/// Input file
#[clap(name = "FILE", parse(from_os_str))]
path: PathBuf,
/// Prefix hash (default: SHA256 of input .wasm file)
#[clap(long)]
prefix: Option<String>,
/// Output file
#[clap(name = "OUTPUT PATH", short = 'o', parse(from_os_str))]
output: PathBuf,
}
impl GenCHeader {
/// Runs logic for the `gen-c-header` subcommand
pub fn execute(&self) -> Result<(), anyhow::Error> {
let path = crate::commands::normalize_path(&format!("{}", self.path.display()));
let file = std::fs::read(&path)
.map_err(|e| anyhow::anyhow!("{e}"))
.with_context(|| anyhow::anyhow!("{path}"))?;
let prefix = match self.prefix.as_deref() {
Some(s) => s.to_string(),
None => crate::commands::PrefixMapCompilation::hash_for_bytes(&file),
};
let (store, _) = CompilerOptions::default().get_store_for_target(Target::default())?;
let module_name = format!("WASMER_{}_METADATA", prefix.to_uppercase());
let engine = store.engine();
let engine_inner = engine.inner();
let compiler = engine_inner.compiler()?;
let features = engine_inner.features();
let tunables = store.tunables();
let (compile_info, _, _, _) =
Artifact::generate_metadata(&file, compiler, tunables, features)?;
let module_info = compile_info.module;
let metadata_length = 0;
let header_file_src = crate::c_gen::staticlib_header::generate_header_file(
&prefix,
&module_name,
&module_info,
&ModuleMetadataSymbolRegistry {
prefix: prefix.clone(),
},
metadata_length as usize,
);
let output = normalize_path(&self.output.display().to_string());
std::fs::write(&output, &header_file_src)
.map_err(|e| anyhow::anyhow!("{e}"))
.with_context(|| anyhow::anyhow!("{output}"))?;
Ok(())
}
}

View File

@@ -412,7 +412,7 @@ impl Artifact {
#[allow(clippy::type_complexity)]
#[cfg(feature = "static-artifact-create")]
/// Generate a compilation
fn generate_metadata<'data>(
pub fn generate_metadata<'data>(
data: &'data [u8],
compiler: &dyn Compiler,
tunables: &dyn Tunables,

View File

@@ -0,0 +1,54 @@
use std::path::PathBuf;
use std::process::Command;
use wasmer_integration_tests_cli::get_wasmer_path;
use wasmer_integration_tests_cli::C_ASSET_PATH;
fn create_exe_wabt_path() -> String {
format!("{}/{}", C_ASSET_PATH, "wabt-1.0.37.wasmer")
}
fn create_exe_python_wasmer() -> String {
format!("{}/{}", C_ASSET_PATH, "python-0.1.0.wasmer")
}
fn create_exe_test_wasm_path() -> String {
format!("{}/{}", C_ASSET_PATH, "qjs.wasm")
}
#[test]
fn gen_c_header_works() -> anyhow::Result<()> {
let temp_dir = tempfile::tempdir()?;
let operating_dir: PathBuf = temp_dir.path().to_owned();
let wasm_path = operating_dir.join(create_exe_test_wasm_path());
let out_path = temp_dir.path().join("header.h");
let _ = Command::new(get_wasmer_path())
.arg("gen-c-header")
.arg(&wasm_path)
.arg("-o")
.arg(&out_path)
.output()
.unwrap();
let file = std::fs::read_to_string(&out_path).expect("no header.h file");
assert!(file.contains("wasmer_function_6f62a6bc5c8f8e3e12a54e2ecbc5674ccfe1c75f91d8e4dd6ebb3fec422a4d6c_0"), "no wasmer_function_6f62a6bc5c8f8e3e12a54e2ecbc5674ccfe1c75f91d8e4dd6ebb3fec422a4d6c_0 in file");
let cmd = Command::new(get_wasmer_path())
.arg("gen-c-header")
.arg(&wasm_path)
.arg("-o")
.arg(&out_path)
.arg("--prefix")
.arg("abc123")
.output()
.unwrap();
let file = std::fs::read_to_string(&out_path).expect("no header.h file");
assert!(
file.contains("wasmer_function_abc123_0"),
"no wasmer_function_abc123_0 in file"
);
Ok(())
}