-
Notifications
You must be signed in to change notification settings - Fork 800
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'master' into new-footer
- Loading branch information
Showing
18 changed files
with
1,586 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
--- | ||
id: runtime-cli-getting-started | ||
title: Runtime Command Line Interface Getting Started | ||
sidebar_label: Getting Started | ||
--- | ||
|
||
If you haven't already, Install the Wasmer CLI. | ||
|
||
``` | ||
curl https://get.wasmer.io -sSfL | sh | ||
``` | ||
|
||
Once you have the Wasmer CLI installed, you can run wasm modules from the command line! | ||
|
||
To do this, you want to find a Wasm Module compiled down to an ABI that the Wasmer runtime supports, such as WASI or Emscripten. For instance, we can search for a module on WAPM, and go to the module page, and then click on the "Browse modules" tab. | ||
|
||
In this example, we will be using the [WASI Compiled QuickJS](https://wapm.io/package/quickjs). To do this we would download the module, and then run: | ||
|
||
`wasmer quickjs.wasm` | ||
|
||
Which should bring up the QuickJS prompt which you can then interact with. | ||
|
||
Next, we can take a look at the command line flags and arguments for the CLI, for more advanced usage. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,97 @@ | ||
--- | ||
id: runtime-cli-usage | ||
title: Runtime Command Line Interface Usage | ||
sidebar_label: Usage | ||
--- | ||
|
||
This is the help output from the Wasmer CLI: | ||
|
||
``` | ||
USAGE: | ||
wasmer <SUBCOMMAND> | ||
FLAGS: | ||
-h, --help Prints help information | ||
-V, --version Prints version information | ||
SUBCOMMANDS: | ||
cache Wasmer cache | ||
help Prints this message or the help of the given subcommand(s) | ||
run Run a WebAssembly file. Formats accepted: wasm, wast | ||
self-update Update wasmer to the latest version | ||
validate Validate a Web Assembly binary | ||
``` | ||
|
||
## `wasmer cache` | ||
|
||
``` | ||
USAGE: | ||
wasmer cache <SUBCOMMAND> | ||
FLAGS: | ||
-h, --help Prints help information | ||
-V, --version Prints version information | ||
SUBCOMMANDS: | ||
clean Clear the cache | ||
dir Display the location of the cache | ||
help Prints this message or the help of the given subcommand(s) | ||
``` | ||
|
||
## `wasmer run` | ||
|
||
It runs a WebAssembly file. Formats accepted: wasm, wat | ||
|
||
``` | ||
USAGE: | ||
wasmer run [FLAGS] [OPTIONS] <path> [--] []... | ||
FLAGS: | ||
--enable-all Enable support for all pre-standard proposals. | ||
--disable-cache Disable the cache | ||
-h, --help Prints help information | ||
--enable-simd Enable support for the SIMD proposal. | ||
--enable-threads Enable support for the threads proposal. | ||
--track-state Whether or not state tracking should be disabled during compilation. State tracking is | ||
necessary for tier switching and backtracing. | ||
-V, --version Prints version information | ||
OPTIONS: | ||
--backend <backend> [default: cranelift] [possible values: cranelift, singlepass, llvm] | ||
--em-entrypoint <em-entrypoint> Begin execution at the specified symbol | ||
--em-symbol-map <em-symbol-map> Emscripten symbol map | ||
--env <env-vars>... Pass custom environment variables | ||
--loader <loader> Custom code loader [possible values: local, kernel] | ||
--mapdir <mapped-dirs>... Map a host directory to a different location for the wasm module | ||
--llvm-object-file <obj-file> Emit LLVM generated native code object file. | ||
--llvm-post-opt-ir <post-opt-ir> Emit LLVM IR after optimization pipeline. | ||
--dir <pre-opened-directories>... WASI pre-opened directory | ||
--llvm-pre-opt-ir <pre-opt-ir> Emit LLVM IR before optimization pipeline. | ||
ARGS: | ||
<path> Input file | ||
<>... Application arguments | ||
``` | ||
|
||
## `wasmer self-update` | ||
|
||
It auto-updates the current used wasmer | ||
|
||
## `wasmer validate <path>` | ||
|
||
It validates that the provided Wasm file is valid. | ||
|
||
``` | ||
USAGE: | ||
wasmer validate [FLAGS] <path> | ||
FLAGS: | ||
--enable-all Enable support for all pre-standard proposals. | ||
-h, --help Prints help information | ||
--enable-simd Enable support for the SIMD proposal. | ||
--enable-threads Enable support for the threads proposal. | ||
-V, --version Prints version information | ||
ARGS: | ||
<path> Input file | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,96 @@ | ||
--- | ||
id: runtime-rust-integration-examples-exit-early | ||
title: Runtime Rust Integration: Interrupting Execution | ||
sidebar_label: Interrupting Execution | ||
--- | ||
|
||
WebAssembly in its current state is currently run synchronously. Thus, once WebAssembly starts executing, you have to wait for the execution to complete to continue running code on the host (your rust application). However, there are cases where you may want to interrupt this synchronous execution while the guest WebAssembly module is calling a host function. This can be useful for saving resources, and not returning back to the guest WebAssembly for execution, when you already know the Wasm execution will fail, or no longer be needed. | ||
|
||
In this example, we will run a Wasm module that calls the imported host function, "interrupt_execution". This host function will immediately stop executing the WebAssembly module: | ||
|
||
```rust | ||
// Import the Filesystem so we can read our .wasm file | ||
use std::fs::File; | ||
use std::io::prelude::*; | ||
|
||
// Import the wasmer runtime so we can use it | ||
use wasmer_runtime::{ | ||
error, | ||
// Include the function macro | ||
func, | ||
imports, | ||
instantiate, | ||
// Include the Context for our Wasm Instance for passing imported host functions | ||
Ctx, | ||
Func, | ||
}; | ||
|
||
const WASM_FILE_PATH: &str = concat!( | ||
env!("CARGO_MANIFEST_DIR"), | ||
"/example-rust-wasm-crate/early-exit-import/pkg/early_exit_import_bg.wasm" | ||
); | ||
|
||
// Our entry point to our application | ||
fn main() -> error::Result<()> { | ||
// Let's read in our .wasm file as bytes | ||
|
||
// Let's open the file. | ||
let mut file = File::open(WASM_FILE_PATH).expect(&format!("wasm file at {}", WASM_FILE_PATH)); | ||
|
||
// Let's read the file into a Vec | ||
let mut wasm_vec = Vec::new(); | ||
file.read_to_end(&mut wasm_vec) | ||
.expect("Error reading the wasm file"); | ||
|
||
// Now that we have the wasm file as bytes, let's run it with the wasmer runtime | ||
|
||
// Let's define the import object used to import our function | ||
// into our webassembly sample application. | ||
// | ||
// Make sure to check your function signature (parameter and return types) carefully! | ||
let import_object = imports! { | ||
// Define the "env" namespace that was implicitly used | ||
// by our example rust wasm crate. | ||
"env" => { | ||
// Key should be the name of the imported function | ||
// Value should be the func! macro, with the function passed in. | ||
"interrupt_execution" => func!(interrupt_execution), | ||
}, | ||
}; | ||
|
||
// Let's create an instance of wasm module running in the wasmer-runtime | ||
let instance = instantiate(&wasm_vec, &import_object)?; | ||
|
||
// Let's call the exported "exit_early" function on the wasm module. | ||
let exit_early_func: Func<(), i32> = instance | ||
.func("exit_early") | ||
.expect("exit_early function not found"); | ||
let response = exit_early_func.call(); | ||
|
||
match response { | ||
Ok(value) => { | ||
// This should have thrown an error, return an error | ||
panic!("exit_early did not error. Returned the value: {}", value); | ||
} | ||
Err(e) => { | ||
// Log the error | ||
println!("Error from exit_early: {}", e); | ||
} | ||
} | ||
|
||
// Log a success message. | ||
println!("Success!"); | ||
|
||
// Return OK since everything executed successfully! | ||
Ok(()) | ||
} | ||
|
||
// Function that is imported into the guest wasm module, that will immediately stop execution | ||
fn interrupt_execution(_ctx: &mut Ctx) -> Result<(), ()> { | ||
// Log that we were called | ||
println!("interrupt_execution called!"); | ||
|
||
// Return an error, which will immediately stop execution of the wasm module | ||
Err(()) | ||
} | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,164 @@ | ||
--- | ||
id: runtime-rust-integration-examples-handling-errors | ||
title: Runtime Rust Integration: Handling Errors | ||
sidebar_label: Handling Errors | ||
--- | ||
|
||
There will come a time where running a WebAssembly module will not work, and trying to figure out why it does not work can be a difficult task! In the current MVP of WebAssembly, debugging is quite vauge, in runtimes for both the browser and the server. But errors can still be handled and debugged gracefully. | ||
|
||
In this example, we will load a WebAssembly module that purposely `panic!()`'s on its exported function call. The host (our rust application) will pattern match for the error and output the error message returned from Wasmer: | ||
|
||
```rust | ||
// Import the Filesystem so we can read our .wasm file | ||
use std::io::prelude::*; | ||
use std::fs::File; | ||
|
||
// Import the wasmer runtime so we can use it | ||
use wasmer_runtime::{ | ||
instantiate, | ||
Func, | ||
imports, | ||
error, | ||
}; | ||
|
||
// Our entry point to our application | ||
fn main() -> error::Result<()> { | ||
|
||
// Let's read in our .wasm file as bytes | ||
|
||
// Let's open the file. | ||
// The file path may be different depending where you run `cargo run`, and where you place the file. | ||
let mut file = File::open("./example-rust-wasm-crate/throw-wasm-error/pkg/throw_wasm_error_bg.wasm").expect("Incorrect file path to wasm module."); | ||
|
||
// Let's read the file into a Vec | ||
let mut wasm_vec = Vec::new(); | ||
file.read_to_end(&mut wasm_vec).expect("Error reading the wasm file"); | ||
|
||
// Let's get our byte slice ( [u8] ) from ouw wasm_vec. | ||
let wasm_bytes = wasm_vec.as_slice(); | ||
|
||
// Now that we have the wasm file as bytes, let's run it with the wasmer runtime | ||
|
||
// Our import object, that allows exposing functions to our wasm module. | ||
// We're not importing anything, so make an empty import object. | ||
let import_object = imports!{}; | ||
|
||
// Let's create an instance of wasm module running in the wasmer-runtime | ||
let instance = instantiate(wasm_bytes, &import_object)?; | ||
|
||
// Let's call the exported "throw_error" function ont the wasm module. | ||
let throw_error_func: Func<(), ()> = instance | ||
.func("throw_wasm_error") | ||
.expect("throw_wasm_error function was not found"); | ||
|
||
let response = throw_error_func.call(); | ||
|
||
match response { | ||
Ok(_) => { | ||
// The wasm modules should have thrown an error. | ||
panic!("throw_wasm_error did not error"); | ||
}, | ||
Err(e) => { | ||
// Log the error | ||
println!("Error from throw_wasm_error: {}", e); | ||
}, | ||
} | ||
|
||
// Log a success message. | ||
println!("Success!"); | ||
|
||
// Return OK since everything executed successfully! | ||
Ok(()) | ||
} | ||
``` | ||
|
||
If we run the following code with `cargo run`, we would see a result like: | ||
|
||
[](https://www.notion.so/5d431ea429a24e6bacead8c003c33920#08e329b5e9864744b8f7d1d362589114) | ||
|
||
However, let's make this a little more interesting. Let's unwrap the error, as you would during the development process and not in production. This will cause the program to error at the WebAssembly module function call, and will give a different output to our console: | ||
|
||
```rust | ||
// Import the Filesystem so we can read our .wasm file | ||
use std::io::prelude::*; | ||
use std::fs::File; | ||
|
||
// Import the wasmer runtime so we can use it | ||
use wasmer_runtime::{ | ||
instantiate, | ||
Func, | ||
imports, | ||
error, | ||
}; | ||
|
||
// Our entry point to our application | ||
fn main() -> error::Result<()> { | ||
|
||
// Let's read in our .wasm file as bytes | ||
|
||
// Let's open the file. | ||
// The file path may be different depending where you run `cargo run`, and where you place the file. | ||
let mut file = File::open("./example-rust-wasm-crate/throw-wasm-error/pkg/throw_wasm_error_bg.wasm").expect("Incorrect file path to wasm module."); | ||
|
||
// Let's read the file into a Vec | ||
let mut wasm_vec = Vec::new(); | ||
file.read_to_end(&mut wasm_vec).expect("Error reading the wasm file"); | ||
|
||
// Let's get our byte slice ( [u8] ) from ouw wasm_vec. | ||
let wasm_bytes = wasm_vec.as_slice(); | ||
|
||
// Now that we have the wasm file as bytes, let's run it with the wasmer runtime | ||
|
||
// Our import object, that allows exposing functions to our wasm module. | ||
// We're not importing anything, so make an empty import object. | ||
let import_object = imports!{}; | ||
|
||
// Let's create an instance of wasm module running in the wasmer-runtime | ||
let instance = instantiate(wasm_bytes, &import_object)?; | ||
|
||
// Let's call the exported "throw_error" function ont the wasm module. | ||
let throw_error_func: Func<(), ()> = instance | ||
.func("throw_wasm_error") | ||
.expect("throw_wasm_error function was not found"); | ||
|
||
// Unwrapping here, so that the error is thrown here | ||
let _response = throw_error_func.call().unwrap(); | ||
|
||
/* | ||
Commenting the pattern matching, to show the unwrapped error above. | ||
match response { | ||
Ok(_) => { | ||
// This should have thrown an error, return an error | ||
panic!("throw_wasm_error did not error"); | ||
}, | ||
Err(e) => { | ||
// Log the error | ||
println!("Error from throw_wasm_error: {}", e); | ||
}, | ||
} | ||
*/ | ||
|
||
// Log a success message. | ||
println!("Success!"); | ||
|
||
// Return OK since everything executed successfully! | ||
Ok(()) | ||
} | ||
``` | ||
|
||
If we run the code with `cargo run`, we would see a result like: | ||
|
||
[](https://www.notion.so/5d431ea429a24e6bacead8c003c33920#27c029496f2b492e813885e6cc88ebf1) | ||
|
||
As you can tell, this error doesn't give us much insight into why this had an error. Such as the line number in the host application. This can be extremely fustrating, especially if you are making multiple calls to a wasm module in a complex rust application. What we can do to get some more insight is use what the error itself suggests, which is the `RUST_BACKTRACE=1` environment variable. **It is HIGHLY RECCOMENDED that you use the `RUST_BACKTRACE=1` environment variable for debugging you rust application that embeds the Wasmer runtime.** | ||
|
||
So let's run the code with **`RUST_BACKTRACE=1 cargo run`** instead, we would see a result like: | ||
|
||
[](https://www.notion.so/5d431ea429a24e6bacead8c003c33920#2b64e7adb22e42b4a49b9086afe70a8b) | ||
|
||
If we look our for our file name (`src/main.rs`), we will see at step 10, there was an error on line 44. Which is the line number for where we call and unwrap the `throw_wasm_error` function. This is great, as now we can start to investigate the particular function call, and why it may be returning and error. | ||
|
||
Next, let's take a look at how we can interrupt an executing Wasm module. |
Oops, something went wrong.