diff --git a/CHANGELOG.md b/CHANGELOG.md index 645ba388c52..3739e29b0db 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ Looking for changes that affect our C API? See the [C API Changelog](lib/c-api/C - [#3008](https://github.com/wasmerio/wasmer/pull/3008) Add a new CI check that uses cargo public-api to track changes in the API between master and the last deployed version on crates.io - [#3003](https://github.com/wasmerio/wasmer/pull/3003) Remove RuntimeError::raise from public API - [#2999](https://github.com/wasmerio/wasmer/pull/2999) Allow `--invoke` CLI option for Emscripten files without a `main` function +- [#2997](https://github.com/wasmerio/wasmer/pull/2997) Fix "run --invoke [function]" to behave the same as "run" - [#2946](https://github.com/wasmerio/wasmer/pull/2946) Remove dylib,staticlib engines in favor of a single Universal engine - [#2949](https://github.com/wasmerio/wasmer/pull/2949) Switch back to using custom LLVM builds on CI - #2892 Renamed `get_native_function` to `get_typed_function`, marked former as deprecated. diff --git a/Cargo.lock b/Cargo.lock index 26b7f0fb2b8..60d861ac094 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3074,6 +3074,7 @@ name = "wasmer-integration-tests-cli" version = "2.3.0" dependencies = [ "anyhow", + "rand", "tempfile", ] diff --git a/lib/cli/src/commands/run.rs b/lib/cli/src/commands/run.rs index d6f4de250a0..1605009736f 100644 --- a/lib/cli/src/commands/run.rs +++ b/lib/cli/src/commands/run.rs @@ -226,8 +226,34 @@ impl Run { }; #[cfg(not(feature = "wasi"))] let ret = { - let instance = Instance::new(&mut store, &module, &imports! {})?; - self.inner_run(ctx, instance) + let instance = Instance::new(&module, &imports! {})?; + + // If this module exports an _initialize function, run that first. + if let Ok(initialize) = instance.exports.get_function("_initialize") { + initialize + .call(&[]) + .with_context(|| "failed to run _initialize function")?; + } + + // Do we want to invoke a function? + if let Some(ref invoke) = self.invoke { + let result = self.invoke_function(&instance, invoke, &self.args)?; + println!( + "{}", + result + .iter() + .map(|val| val.to_string()) + .collect::>() + .join(" ") + ); + } else { + let start: Function = self.try_find_function(&instance, "_start", &[])?; + let result = start.call(&[]); + #[cfg(feature = "wasi")] + self.wasi.handle_result(result)?; + #[cfg(not(feature = "wasi"))] + result?; + } }; ret diff --git a/tests/integration/cli/Cargo.toml b/tests/integration/cli/Cargo.toml index 068c50fec82..b3ea4e06b0f 100644 --- a/tests/integration/cli/Cargo.toml +++ b/tests/integration/cli/Cargo.toml @@ -7,6 +7,9 @@ repository = "https://github.com/wasmerio/wasmer" edition = "2018" publish = false +[dev-dependencies] +rand = "0.8.5" + [dependencies] anyhow = "1" tempfile = "3" diff --git a/tests/integration/cli/tests/run.rs b/tests/integration/cli/tests/run.rs index 07fddc86564..45e1901f06b 100644 --- a/tests/integration/cli/tests/run.rs +++ b/tests/integration/cli/tests/run.rs @@ -43,7 +43,6 @@ fn run_wasi_works() -> anyhow::Result<()> { } #[test] - fn run_no_imports_wasm_works() -> anyhow::Result<()> { let output = Command::new(WASMER_PATH) .arg("run") @@ -63,6 +62,56 @@ fn run_no_imports_wasm_works() -> anyhow::Result<()> { Ok(()) } +// This test verifies that "wasmer run --invoke _start module.wat" +// works the same as "wasmer run module.wat" (without --invoke). +#[test] +fn run_invoke_works_with_nomain_wasi() -> anyhow::Result<()> { + // In this example the function "wasi_unstable.arg_sizes_get" + // is a function that is imported from the WASI env. + let wasi_wat = " + (module + (import \"wasi_unstable\" \"args_sizes_get\" + (func $__wasi_args_sizes_get (param i32 i32) (result i32))) + (func $_start) + (memory 1) + (export \"memory\" (memory 0)) + (export \"_start\" (func $_start)) + ) + "; + + let random = rand::random::(); + let module_file = std::env::temp_dir().join(&format!("{random}.wat")); + std::fs::write(&module_file, wasi_wat.as_bytes()).unwrap(); + let output = Command::new(WASMER_PATH) + .arg("run") + .arg(&module_file) + .output()?; + + let stderr = std::str::from_utf8(&output.stderr).unwrap().to_string(); + let success = output.status.success(); + if !success { + println!("ERROR in 'wasmer run [module.wat]':\r\n{stderr}"); + panic!(); + } + + let output = Command::new(WASMER_PATH) + .arg("run") + .arg("--invoke") + .arg("_start") + .arg(&module_file) + .output()?; + + let stderr = std::str::from_utf8(&output.stderr).unwrap().to_string(); + let success = output.status.success(); + if !success { + println!("ERROR in 'wasmer run --invoke _start [module.wat]':\r\n{stderr}"); + panic!(); + } + + std::fs::remove_file(&module_file).unwrap(); + Ok(()) +} + #[test] fn run_no_start_wasm_report_error() -> anyhow::Result<()> { let output = Command::new(WASMER_PATH)