diff --git a/lib/cli/src/commands/create_exe.rs b/lib/cli/src/commands/create_exe.rs index 7c063779c..c9512cb2e 100644 --- a/lib/cli/src/commands/create_exe.rs +++ b/lib/cli/src/commands/create_exe.rs @@ -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::>(); + + 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::>(); + 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::>(); - let mut object_paths = entrypoint - .atoms - .iter() - .filter_map(|a| directory.join(&a.path).canonicalize().ok()) - .collect::>(); - 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 { + 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::>(); + + 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::>() + .join("\n") + )); + + Ok(return_str.replace("// INSTANTIATE_MODULES", &c_code_to_instantiate)) + } + } +} + #[allow(dead_code)] pub(super) mod utils { diff --git a/lib/cli/src/commands/create_obj.rs b/lib/cli/src/commands/create_obj.rs index 681faeef4..2c9b45c67 100644 --- a/lib/cli/src/commands/create_obj.rs +++ b/lib/cli/src/commands/create_obj.rs @@ -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 { diff --git a/lib/cli/src/commands/wasmer_create_exe.h b/lib/cli/src/commands/wasmer_create_exe.h deleted file mode 100644 index a94afd114..000000000 --- a/lib/cli/src/commands/wasmer_create_exe.h +++ /dev/null @@ -1,25 +0,0 @@ -#include "wasmer.h" -#include -#include -#include - -#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 diff --git a/lib/cli/src/commands/wasmer_create_exe_main.c b/lib/cli/src/commands/wasmer_create_exe_main.c index 4fe6a7f94..645fc5ebd 100644 --- a/lib/cli/src/commands/wasmer_create_exe_main.c +++ b/lib/cli/src/commands/wasmer_create_exe_main.c @@ -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");