Add CLI handling to wasmer_main.c

This commit is contained in:
Felix Schütt
2022-12-21 15:51:22 +01:00
parent c92d8d34e3
commit b5119432ef
4 changed files with 170 additions and 76 deletions

View File

@@ -373,7 +373,7 @@ fn conpile_atoms(
/// Compile the C code.
#[allow(dead_code)]
fn run_c_compile(path_to_c_src: &Path, output_name: &Path, target: Triple) -> anyhow::Result<()> {
fn run_c_compile(path_to_c_src: &Path, output_name: &Path, target: &Triple) -> anyhow::Result<()> {
#[cfg(not(windows))]
let c_compiler = "cc";
// We must use a C++ compiler on Windows because wasm.h uses `static_assert`
@@ -551,48 +551,83 @@ fn link_exe_from_dir(
return Err(anyhow::anyhow!("file has no atoms to compile"));
}
let zig_binary_path = cross_compilation
.zig_binary_path
.as_ref()
.ok_or_else(|| anyhow::anyhow!("zig binary not found in $PATH"))?;
let wasmer_main_c = generate_wasmer_main_c(&entrypoint).map_err(|e| {
anyhow::anyhow!(
"could not generate wasmer_main.c in dir {}: {e}",
directory.display()
)
})?;
std::fs::write(directory.join("wasmer_main.c"), wasmer_main_c.as_bytes()).map_err(|e| {
anyhow::anyhow!(
"could not write wasmer_main.c in dir {}: {e}",
directory.display()
)
})?;
let library_path = cross_compilation
.library
.as_ref()
.ok_or_else(|| anyhow::anyhow!("libwasmer.a / wasmer.lib not found"))?;
let mut object_paths = entrypoint
.atoms
.iter()
.filter_map(|a| directory.join(&a.path).canonicalize().ok())
.collect::<Vec<_>>();
object_paths.extend(
entrypoint
.volumes
.iter()
.filter_map(|v| directory.join(&v.obj_file).canonicalize().ok()),
);
let zig_triple = utils::triple_to_zig_triple(&cross_compilation.target);
let include_dirs = entrypoint
.atoms
.iter()
.filter_map(|a| {
Some(
directory
.join(a.header.as_deref()?)
.canonicalize()
.ok()?
.parent()?
.to_path_buf(),
)
})
.collect::<Vec<_>>();
match entrypoint.object_format {
ObjectFormat::Serialized => {
return Err(anyhow::anyhow!(
"ObjectFormat::Serialized + cross compilation not implemented"
));
if cross_compilation.target == Triple::host() {
run_c_compile(
&directory.join("wasmer_main.c"),
&directory.join("wasmer_main.o"),
&cross_compilation.target,
)
.map_err(|e| {
anyhow::anyhow!(
"could not write wasmer_main.c in dir {}: {e}",
directory.display()
)
})?;
link_c_compilation()
} else {
Err(anyhow::anyhow!(
"ObjectFormat::Serialized + cross compilation not implemented"
))
}
}
ObjectFormat::Symbols => {
let zig_triple = utils::triple_to_zig_triple(&cross_compilation.target);
let include_dirs = entrypoint
.atoms
.iter()
.filter_map(|a| {
Some(
directory
.join(a.header.as_deref()?)
.canonicalize()
.ok()?
.parent()?
.to_path_buf(),
)
})
.collect::<Vec<_>>();
let mut object_paths = entrypoint
.atoms
.iter()
.filter_map(|a| directory.join(&a.path).canonicalize().ok())
.collect::<Vec<_>>();
object_paths.extend(
entrypoint
.volumes
.iter()
.filter_map(|v| directory.join(&v.obj_file).canonicalize().ok()),
);
let zig_binary_path = cross_compilation.zig_binary_path.as_ref().ok_or_else(|| {
anyhow::anyhow!(
"could not write wasmer_main.c in dir {}",
directory.display()
)
})?;
let mut cmd = Command::new(&zig_binary_path);
cmd.arg("build-exe");
@@ -654,12 +689,103 @@ fn link_exe_from_dir(
output_path.display()
)
})?;
Ok(())
}
}
}
/// Link compiled objects together using the system linker
fn link_c_compilation() -> Result<(), anyhow::Error> {
// TODO
Ok(())
}
/// Generate the wasmer_main.c that links all object files together
/// (depending on the object format / atoms number)
fn generate_wasmer_main_c(entrypoint: &Entrypoint) -> Result<String, anyhow::Error> {
const WASMER_MAIN_C_SOURCE: &str = include_str!("wasmer_create_exe_main.c");
match entrypoint.object_format {
ObjectFormat::Serialized => {
Ok(WASMER_MAIN_C_SOURCE.replace("// WASI_DEFINES", "#define WASI"))
}
ObjectFormat::Symbols => {
let atom_names = entrypoint
.atoms
.iter()
.map(|a| &a.command)
.collect::<Vec<_>>();
let mut c_code_to_add = String::new();
let mut c_code_to_instantiate = String::new();
let mut deallocate_module = String::new();
for a in atom_names.iter() {
let atom_name = utils::normalize_atom_name(&a);
let atom_name_uppercase = atom_name.to_uppercase();
c_code_to_add.push_str(&format!(
"
extern size_t {atom_name_uppercase}_LENGTH asm(\"{atom_name_uppercase}_LENGTH\");
extern char {atom_name_uppercase}_DATA asm(\"{atom_name_uppercase}_DATA\");
"
));
c_code_to_instantiate.push_str(&format!("
wasm_byte_vec_t atom_{atom_name}_byte_vec = {{
.size = {atom_name_uppercase}_LENGTH,
.data = &{atom_name_uppercase}_DATA,
}};
wasm_module_t *atom_{atom_name} = wasm_module_deserialize(store, &atom_{atom_name}_byte_vec);
if (!atom_{atom_name}) {{
fprintf(stderr, \"Failed to create module from atom \\\"{atom_name}\\\"\\n\");
print_wasmer_error();
return -1;
}}
"));
deallocate_module.push_str(&format!("wasm_module_delete(atom_{atom_name});"));
}
let return_str = WASMER_MAIN_C_SOURCE
.replace("#define WASI", "#define WASI\r\n#define WASI_PIRITA")
.replace("// DECLARE_MODULES", &c_code_to_add)
.replace("wasm_module_delete(module);", &deallocate_module);
if atom_names.len() == 1 {
let atom_to_run = &atom_names[0];
c_code_to_instantiate.push_str(&format!("module = atom_{atom_to_run};"));
} else {
for a in atom_names.iter() {
c_code_to_instantiate.push_str(&format!(
"if (strcmp(selected_atom, \"{a}\") == 0) {{ module = atom_{}; }}\n",
utils::normalize_atom_name(a)
));
}
}
c_code_to_instantiate.push_str(&format!(
"
if (!module) {{
fprintf(stderr, \"No --command given, available commands are:\\n\");
fprintf(stderr, \"\\n\");
{commands}
print_wasmer_error();
return -1;
}}
",
commands = atom_names
.iter()
.map(|a| format!("fprintf(stderr, \"{a}\\n\");"))
.collect::<Vec<_>>()
.join("\n")
));
Ok(return_str.replace("// INSTANTIATE_MODULES", &c_code_to_instantiate))
}
}
}
#[allow(dead_code)]
pub(super) mod utils {

View File

@@ -17,8 +17,6 @@ use wasmer_object::{emit_serialized, get_object_for_target};
#[cfg(feature = "webc_runner")]
use webc::{ParseOptions, WebCMmap};
const WASMER_SERIALIZED_HEADER: &[u8] = include_bytes!("wasmer_create_exe.h");
#[derive(Debug, Parser)]
/// The options for the `wasmer create-exe` subcommand
pub struct CreateObj {

View File

@@ -1,25 +0,0 @@
#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_object_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

View File

@@ -100,22 +100,17 @@ int main(int argc, char *argv[]) {
wasm_config_t *config = wasm_config_new();
wasm_engine_t *engine = wasm_engine_new_with_config(config);
wasm_store_t *store = wasm_store_new(engine);
wasm_module_t *module = NULL;
#ifdef WASI_PIRITA
// INSTANTIATE_MODULES
#else
wasm_byte_vec_t module_byte_vec = {
.size = WASMER_MODULE_LENGTH,
.data = &WASMER_MODULE_DATA,
};
wasm_module_t *module = wasm_module_deserialize(store, &module_byte_vec);
if (!module) {
fprintf(stderr, "Failed to create module\n");
print_wasmer_error();
return -1;
const char* selected_atom = "main";
for (int i = 1; i < argc; i++) {
if (strcmp(argv[i], "--command") == 0 && i + 1 < argc) {
selected_atom = argv[i + 1];
break;
}
}
#endif
// INSTANTIATE_MODULES
// We have now finished the memory buffer book keeping and we have a valid
// Module.
@@ -142,7 +137,7 @@ int main(int argc, char *argv[]) {
module,
filesystem,
&imports,
"##atom-name##"
selected_atom,
);
if (!wasi_env) {
printf("Error setting filesystem\n");