Skip to content

Commit

Permalink
Merge #3068
Browse files Browse the repository at this point in the history
3068: create-{exe,obj}: add documentations and header file generation for create-obj r=epilys a=epilys



Co-authored-by: Manos Pitsidianakis <[email protected]>
  • Loading branch information
bors[bot] and epilys authored Aug 3, 2022
2 parents e2de53c + fa51522 commit 1ac2de5
Show file tree
Hide file tree
Showing 5 changed files with 144 additions and 49 deletions.
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

0 comments on commit 1ac2de5

Please sign in to comment.