diff --git a/lib/cli/src/c_gen/staticlib_header.rs b/lib/cli/src/c_gen/staticlib_header.rs index 96fe194fe..5336b52d3 100644 --- a/lib/cli/src/c_gen/staticlib_header.rs +++ b/lib/cli/src/c_gen/staticlib_header.rs @@ -92,7 +92,10 @@ pub fn generate_header_file( })), }, CStatement::Declaration { - name: "WASMER_METADATA".to_string(), + name: match module_info.name.as_deref() { + Some(s) => format!("WASMER_METADATA_{}", s.to_uppercase()), + None => "WASMER_METADATA".to_string() + }, is_extern: true, is_const: true, ctype: CType::Array { diff --git a/lib/cli/src/commands.rs b/lib/cli/src/commands.rs index d59d5c78c..b1ae506ae 100644 --- a/lib/cli/src/commands.rs +++ b/lib/cli/src/commands.rs @@ -34,9 +34,10 @@ pub use { add::*, cache::*, config::*, inspect::*, list::*, login::*, run::*, self_update::*, validate::*, whoami::*, }; +use serde::{Serialize, Deserialize}; /// The kind of object format to emit. -#[derive(Debug, Copy, Clone, clap::Parser)] +#[derive(Debug, Copy, Clone, clap::Parser, Serialize, Deserialize)] #[cfg(any(feature = "static-artifact-create", feature = "wasmer-artifact-create"))] pub enum ObjectFormat { /// Serialize the entire module into an object file. diff --git a/lib/cli/src/commands/create_exe.rs b/lib/cli/src/commands/create_exe.rs index c8f326ba6..0eeba7ddc 100644 --- a/lib/cli/src/commands/create_exe.rs +++ b/lib/cli/src/commands/create_exe.rs @@ -174,9 +174,9 @@ impl CreateExe { #[cfg(feature = "webc_runner")] { - let working_dir = tempdir::TempDir::new("testpirita")?; - let working_dir = working_dir.path().to_path_buf(); - + // let working_dir = tempdir::TempDir::new("testpirita")?; + // let working_dir = working_dir.path().to_path_buf(); + let working_dir = Path::new("./tmptestpirita").to_path_buf(); if let Ok(pirita) = WebCMmap::parse(wasm_module_path.clone(), &ParseOptions::default()) { return self.create_exe_pirita( @@ -712,6 +712,15 @@ impl CreateExe { .and_then(|s| file.get_atom_name_for_command("wasi", s).ok()); if let Some(atom_to_run) = atom_to_run.as_ref() { std::fs::write(output_path.join("entrypoint"), atom_to_run)?; + } else if file.manifest.commands.len() > 1 { + let entrypoint_json = file.manifest.commands.iter().filter_map(|(name, _)| { + Some(serde_json::json!({ + "command": name, + "atom": file.get_atom_name_for_command("wasi", name).ok()?, + "object_type": object_format, + })) + }).collect::>(); + std::fs::write(output_path.join("entrypoint.json"), serde_json::to_string_pretty(&entrypoint_json)?)?; } for (atom_name, atom_bytes) in file.get_all_atoms() { @@ -722,13 +731,6 @@ impl CreateExe { #[cfg(windows)] let object_path = output_path.join("atoms").join(&format!("{atom_name}.obj")); - std::fs::create_dir_all(output_path.join("atoms").join(&atom_name))?; - - let header_path = output_path - .join("atoms") - .join(&atom_name) - .join("static_defs.h"); - match object_format { ObjectFormat::Serialized => { let module = Module::new(&store, &atom_bytes) @@ -746,12 +748,20 @@ impl CreateExe { } #[cfg(feature = "static-artifact-create")] ObjectFormat::Symbols => { + std::fs::create_dir_all(output_path.join("atoms").join(&atom_name))?; + + let header_path = output_path + .join("atoms") + .join(&atom_name) + .join("static_defs.h"); + let engine = store.engine(); let engine_inner = engine.inner(); let compiler = engine_inner.compiler()?; let features = engine_inner.features(); let tunables = store.tunables(); - let prefixer: Option = None; + let atom_name = CreateExe::normalize_atom_name(&atom_name); + let prefixer: Option = Some(Box::new(move |_| atom_name.clone())); let (module_info, obj, metadata_length, symbol_registry) = Artifact::generate_object( compiler, atom_bytes, prefixer, target, tunables, features, diff --git a/tests/integration/cli/tests/create_exe.rs b/tests/integration/cli/tests/create_exe.rs index 45969f7c6..0c6a7d40f 100644 --- a/tests/integration/cli/tests/create_exe.rs +++ b/tests/integration/cli/tests/create_exe.rs @@ -7,6 +7,10 @@ use std::path::PathBuf; use std::process::Command; use wasmer_integration_tests_cli::*; +fn create_exe_wabt_path() -> String { + format!("{}/{}", C_ASSET_PATH, "wabt-1.0.37.wasmer") +} + fn create_exe_test_wasm_path() -> String { format!("{}/{}", C_ASSET_PATH, "qjs.wasm") } @@ -164,6 +168,47 @@ fn create_exe_works() -> anyhow::Result<()> { Ok(()) } +#[test] +fn create_exe_works_multi_command() -> anyhow::Result<()> { + let temp_dir = tempfile::tempdir()?; + let operating_dir: PathBuf = temp_dir.path().to_owned(); + + let wasm_path = operating_dir.join(create_exe_wabt_path()); + #[cfg(not(windows))] + let executable_path = operating_dir.join("multicommand.out"); + #[cfg(windows)] + let executable_path = operating_dir.join("multicommand.exe"); + + WasmerCreateExe { + current_dir: std::env::current_dir().unwrap(), // operating_dir.clone(), + wasm_path, + native_executable_path: executable_path.clone(), + compiler: Compiler::Cranelift, + ..Default::default() + } + .run() + .context("Failed to create-exe wasm with Wasmer")?; + + let result = run_code( + &operating_dir, + &executable_path, + &["--command".to_string(), "wabt".to_string()], + ) + .context("Failed to run generated executable")?; + + let result = run_code( + &operating_dir, + &executable_path, + &["-c".to_string(), "wabt".to_string()], + ) + .context("Failed to run generated executable")?; + + let result_lines = result.lines().collect::>(); + assert_eq!(result_lines, vec!["\"Hello, World\""],); + + Ok(()) +} + #[test] fn create_exe_works_with_file() -> anyhow::Result<()> { let temp_dir = tempfile::tempdir()?;