Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

create-{exe,obj}: add documentations and header file generation for create-obj #3068

Merged
merged 3 commits into from
Aug 3, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 35 additions & 2 deletions lib/cli/src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,13 +49,46 @@ enum WasmerCLIOptions {
Compile(Compile),

/// Compile a WebAssembly binary into a native executable
///
/// To use, you need to set the `WASMER_DIR` environment variable
/// to the location of your Wasmer installation. This will probably be `~/.wasmer`. It
/// should include a `lib`, `include` and `bin` subdirectories. To create an executable
/// you will need `libwasmer`, so by setting `WASMER_DIR` the CLI knows where to look for
/// header files and libraries.
///
/// Example usage:
///
/// ```text
/// $ # in two lines:
/// $ export WASMER_DIR=/home/user/.wasmer/
/// $ wasmer create-exe qjs.wasm -o qjs.exe # or in one line:
/// $ WASMER_DIR=/home/user/.wasmer/ wasmer create-exe qjs.wasm -o qjs.exe
/// $ file qjs.exe
/// qjs.exe: ELF 64-bit LSB pie executable, x86-64 ...
/// ```
#[cfg(any(feature = "static-artifact-create", feature = "wasmer-artifact-create"))]
#[structopt(name = "create-exe")]
#[structopt(name = "create-exe", verbatim_doc_comment)]
CreateExe(CreateExe),

/// Compile a WebAssembly binary into an object file
///
/// To use, you need to set the `WASMER_DIR` environment variable to the location of your
/// Wasmer installation. This will probably be `~/.wasmer`. It should include a `lib`,
/// `include` and `bin` subdirectories. To create an object you will need `libwasmer`, so by
/// setting `WASMER_DIR` the CLI knows where to look for header files and libraries.
///
/// Example usage:
///
/// ```text
/// $ # in two lines:
/// $ export WASMER_DIR=/home/user/.wasmer/
/// $ wasmer create-obj qjs.wasm --object-format symbols -o qjs.obj # or in one line:
/// $ WASMER_DIR=/home/user/.wasmer/ wasmer create-exe qjs.wasm --object-format symbols -o qjs.obj
/// $ file qjs.obj
/// qjs.obj: ELF 64-bit LSB relocatable, x86-64 ...
/// ```
#[cfg(feature = "static-artifact-create")]
#[structopt(name = "create-obj")]
#[structopt(name = "create-obj", verbatim_doc_comment)]
CreateObj(CreateObj),

/// Get various configuration information needed
Expand Down
83 changes: 54 additions & 29 deletions lib/cli/src/commands/create_exe.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,12 @@ pub struct CreateExe {
target_triple: Option<Triple>,

/// Object format options
#[structopt(name = "OBJECT_FORMAT", long = "object-format")]
///
/// This flag accepts two options: `symbols` or `serialized`.
/// - (default) `symbols` creates an
/// executable where all functions and metadata of the module are regular object symbols
/// - `serialized` creates an executable where the module is zero-copy serialized as raw data
#[structopt(name = "OBJECT_FORMAT", long = "object-format", verbatim_doc_comment)]
object_format: Option<ObjectFormat>,
#[structopt(short = "m", multiple = true, number_of_values = 1)]
cpu_features: Vec<CpuFeature>,
Expand Down Expand Up @@ -186,14 +191,19 @@ impl CreateExe {
fn link(
output_path: PathBuf,
object_path: PathBuf,
header_code_path: PathBuf,
mut header_code_path: PathBuf,
) -> anyhow::Result<()> {
let linkcode = LinkCode {
object_paths: vec![object_path, "main_obj.obj".into()],
output_path,
..Default::default()
};
let c_src_path = Path::new("wasmer_main.c");
let mut libwasmer_path = get_libwasmer_path()?
.canonicalize()
.context("Failed to find libwasmer")?;
println!("Using libwasmer: {}", libwasmer_path.display());
let lib_filename = libwasmer_path
let _lib_filename = libwasmer_path
.file_name()
.unwrap()
.to_str()
Expand All @@ -209,32 +219,47 @@ fn link(
c_src_file.write_all(WASMER_STATIC_MAIN_C_SOURCE)?;
}

println!(
"link output {:?}",
Command::new("cc")
.arg(&object_path)
.arg(&header_code_path)
.arg(&c_src_path)
.arg(&format!("-L{}", libwasmer_path.display()))
.arg(&format!("-I{}", get_wasmer_include_directory()?.display()))
.arg(&format!("-l:{}", lib_filename))
// Add libraries required per platform.
// We need userenv, sockets (Ws2_32), advapi32 for some system calls and bcrypt for random numbers.
//#[cfg(windows)]
// .arg("-luserenv")
// .arg("-lWs2_32")
// .arg("-ladvapi32")
// .arg("-lbcrypt")
// On unix we need dlopen-related symbols, libmath for a few things, and pthreads.
//#[cfg(not(windows))]
.arg("-ldl")
.arg("-lm")
.arg("-pthread")
//.arg(&format!("-I{}", header_code_path.display()))
.arg("-o")
.arg(&output_path)
.output()?
);
if !header_code_path.is_dir() {
header_code_path.pop();
}

/* Compile main function */
let compilation = Command::new("cc")
.arg("-c")
.arg(&c_src_path)
.arg(if linkcode.optimization_flag.is_empty() {
"-O2"
} else {
linkcode.optimization_flag.as_str()
})
.arg(&format!("-L{}", libwasmer_path.display()))
.arg(&format!("-I{}", get_wasmer_include_directory()?.display()))
//.arg(&format!("-l:{}", lib_filename))
.arg("-lwasmer")
// Add libraries required per platform.
// We need userenv, sockets (Ws2_32), advapi32 for some system calls and bcrypt for random numbers.
//#[cfg(windows)]
// .arg("-luserenv")
// .arg("-lWs2_32")
// .arg("-ladvapi32")
// .arg("-lbcrypt")
// On unix we need dlopen-related symbols, libmath for a few things, and pthreads.
//#[cfg(not(windows))]
.arg("-ldl")
.arg("-lm")
.arg("-pthread")
.arg(&format!("-I{}", header_code_path.display()))
.arg("-v")
.arg("-o")
.arg("main_obj.obj")
.output()?;
if !compilation.status.success() {
return Err(anyhow::anyhow!(String::from_utf8_lossy(
&compilation.stderr
)
.to_string()));
}
linkcode.run().context("Failed to link objects together")?;
Ok(())
}

Expand Down
46 changes: 29 additions & 17 deletions lib/cli/src/commands/create_obj.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ use structopt::StructOpt;
use wasmer::*;
use wasmer_object::{emit_serialized, get_object_for_target};

const WASMER_SERIALIZED_HEADER: &[u8] = include_bytes!("wasmer_create_exe.h");

#[derive(Debug, StructOpt)]
/// The options for the `wasmer create-exe` subcommand
pub struct CreateObj {
Expand All @@ -23,15 +25,27 @@ pub struct CreateObj {
path: PathBuf,

/// Output file
#[structopt(name = "OUTPUT PATH", short = "o", parse(from_os_str))]
#[structopt(name = "OUTPUT_PATH", short = "o", parse(from_os_str))]
output: PathBuf,

/// Header output file
#[structopt(
name = "OUTPUT_HEADER_PATH",
long = "output-header-path",
parse(from_os_str)
)]
header_output: Option<PathBuf>,

/// Compilation Target triple
#[structopt(long = "target")]
target_triple: Option<Triple>,

/// Object format options
#[structopt(name = "OBJECT_FORMAT", long = "object-format")]
///
/// This flag accepts two options: `symbols` or `serialized`.
/// - (default) `symbols` creates an object where all functions and metadata of the module are regular object symbols
/// - `serialized` creates an object where the module is zero-copy serialized as raw data
#[structopt(name = "OBJECT_FORMAT", long = "object-format", verbatim_doc_comment)]
object_format: Option<ObjectFormat>,

#[structopt(short = "m", multiple = true, number_of_values = 1)]
Expand All @@ -44,7 +58,6 @@ pub struct CreateObj {
impl CreateObj {
/// Runs logic for the `create-obj` subcommand
pub fn execute(&self) -> Result<()> {
println!("objectformat: {:?}", &self.object_format);
let target = self
.target_triple
.as_ref()
Expand All @@ -68,8 +81,15 @@ impl CreateObj {
println!("Format: {:?}", object_format);

let starting_cd = env::current_dir()?;

let output_path = starting_cd.join(&self.output);
let header_output = self.header_output.clone().unwrap_or_else(|| {
let mut retval = self.output.clone();
retval.set_extension("h");
retval
});

let header_output_path = starting_cd.join(&header_output);
let wasm_module_path = starting_cd.join(&self.path);

match object_format {
Expand All @@ -83,6 +103,9 @@ impl CreateObj {
obj.write_stream(&mut writer)
.map_err(|err| anyhow::anyhow!(err.to_string()))?;
writer.flush()?;
let mut writer = BufWriter::new(File::create(&header_output_path)?);
writer.write_all(WASMER_SERIALIZED_HEADER)?;
writer.flush()?;
}
ObjectFormat::Symbols => {
let engine = store.engine();
Expand All @@ -106,27 +129,16 @@ impl CreateObj {
obj.write_stream(&mut writer)
.map_err(|err| anyhow::anyhow!(err.to_string()))?;
writer.flush()?;
{
let mut writer = BufWriter::new(File::create("/tmp/main_obj.o")?);
obj.write_stream(&mut writer)
.map_err(|err| anyhow::anyhow!(err.to_string()))?;
writer.flush()?;
}
let mut writer = BufWriter::new(File::create("func.c")?);
let mut writer = BufWriter::new(File::create(&header_output_path)?);
writer.write_all(header_file_src.as_bytes())?;
writer.flush()?;
{
let mut writer = BufWriter::new(File::create("/tmp/func.c")?);
writer.write_all(header_file_src.as_bytes())?;
writer.flush()?;
}
//link(output_path.clone(), std::path::Path::new("func.c").into())?;
}
}

eprintln!(
"✔ Object compiled successfully to `{}`.",
"✔ Object compiled successfully to `{}` and the header file was generated at `{}`.",
self.output.display(),
header_output.display(),
);

Ok(())
Expand Down
25 changes: 25 additions & 0 deletions lib/cli/src/commands/wasmer_create_exe.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#include "wasmer.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#ifdef __cplusplus
extern "C" {
#endif

extern size_t WASMER_MODULE_LENGTH asm("WASMER_MODULE_LENGTH");
extern char WASMER_MODULE_DATA asm("WASMER_MODULE_DATA");

wasm_module_t* wasmer_module_new(wasm_store_t* store, const char* wasm_name) {
wasm_byte_vec_t module_byte_vec = {
.size = WASMER_MODULE_LENGTH,
.data = (const char*)&WASMER_MODULE_DATA,
};
wasm_module_t* module = wasm_module_deserialize(store, &module_byte_vec);

return module;
}

#ifdef __cplusplus
}
#endif
2 changes: 1 addition & 1 deletion lib/types/src/serialize.rs
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,7 @@ impl MetadataHeader {

/// Parses the header and returns the length of the metadata following it.
pub fn parse(bytes: &[u8]) -> Result<usize, DeserializeError> {
if bytes.as_ptr() as usize % 16 != 0 {
if bytes.as_ptr() as usize % 8 != 0 {
return Err(DeserializeError::CorruptedBinary(
"misaligned metadata".to_string(),
));
Expand Down