Skip to content

Commit

Permalink
Merge #399
Browse files Browse the repository at this point in the history
399: Add extending WASI plugin example r=MarkMcCaskey a=MarkMcCaskey



Co-authored-by: Mark McCaskey <mark@wasmer.io>
Co-authored-by: Mark McCaskey <markmccaskey@users.noreply.github.com>
Co-authored-by: Mackenzie Clark <mackenzie.a.z.c@gmail.com>
  • Loading branch information
4 people committed Apr 29, 2019
2 parents d2d70b2 + 49aa104 commit 7ad4228
Show file tree
Hide file tree
Showing 9 changed files with 124 additions and 3 deletions.
5 changes: 3 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,12 @@ All PRs to the Wasmer repository must add to this file.
Blocks of changes will separated by version increments.

## **[Unreleased]**
- [#399](https://github.com/wasmerio/wasmer/pull/399) Add example of using a plugin extended from WASI
- [#397](https://github.com/wasmerio/wasmer/pull/397) Fix WASI fs abstraction to work on Windows
- [#390](https://github.com/wasmerio/wasmer/pull/390) Pin released wapm version and add it as a git submodule

## 0.4.0 - 2018-04-23

- [#397](https://github.com/wasmerio/wasmer/pull/397) Fix WASI fs abstraction to work on Windows
- [#390](https://github.com/wasmerio/wasmer/pull/390) Pin released wapm version and add it as a git submodule
- [#383](https://github.com/wasmerio/wasmer/pull/383) Hook up wasi exit code to wasmer cli.
- [#382](https://github.com/wasmerio/wasmer/pull/382) Improve error message on `--backend` flag to only suggest currently enabled backends
- [#381](https://github.com/wasmerio/wasmer/pull/381) Allow retrieving propagated user errors.
Expand Down
4 changes: 4 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 5 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ wasmer-llvm-backend = { path = "lib/llvm-backend", optional = true }
wasmer-wasi = { path = "lib/wasi", optional = true }

[workspace]
members = ["lib/clif-backend", "lib/singlepass-backend", "lib/runtime", "lib/runtime-abi", "lib/runtime-core", "lib/emscripten", "lib/spectests", "lib/win-exception-handler", "lib/runtime-c-api", "lib/llvm-backend", "lib/wasi"]
members = ["lib/clif-backend", "lib/singlepass-backend", "lib/runtime", "lib/runtime-abi", "lib/runtime-core", "lib/emscripten", "lib/spectests", "lib/win-exception-handler", "lib/runtime-c-api", "lib/llvm-backend", "lib/wasi", "examples/plugin-for-example"]

[build-dependencies]
wabt = "0.7.2"
Expand All @@ -49,3 +49,7 @@ fast-tests = []
"backend:singlepass" = ["wasmer-singlepass-backend"]
wasi = ["wasmer-wasi"]
vfs = ["wasmer-runtime-abi"]

[[example]]
name = "plugin"
crate-type = ["bin"]
Binary file added examples/plugin-for-example.wasm
Binary file not shown.
7 changes: 7 additions & 0 deletions examples/plugin-for-example/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
[package]
name = "plugin-for-example"
version = "0.1.0"
authors = ["The Wasmer Engineering Team <enigneering@wasmer.io>"]
edition = "2018"

[dependencies]
43 changes: 43 additions & 0 deletions examples/plugin-for-example/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# WASI plugin example

In this example we extend the imports of Wasmer's WASI ABI to demonstrate how custom plugins work.

See the `wasmer/examples/plugin.rs` file for the source code of the host system.

## Compiling
_Attention Windows users: WASI target only works with the `nightly-x86_64-pc-windows-gnu` toolchain._
```
# Install an up to date version of Rust nightly
# Add the target
rustup target add wasm32-unknown-wasi
# build it
cargo +nightly build --release --target=wasm32-unknown-wasi
# copy it to examples folder
cp ../../target/wasm32-unknown-wasi/release/plugin-for-example.wasm ../
```

## Running
```
# Go back to top level Wasmer dir
cd ..
# Run the example
cargo run --example plugin
```

## Inspecting the plugin
```
# Install wabt via wapm; installed globally with the `g` flag
wapm install -g wabt
# Turn the binary WASM file in to a readable WAT text file
wapm run wasm2wat examples/plugin-for-example.wasm
```

At the top of the file we can see which functions this plugin expects. Most are covered by WASI, but we handle the rest.

## Explanation

In this example, we instantiate a system with an extended (WASI)[wasi] ABI, allowing our program to rely on Wasmer's implementation of the syscalls defined by WASI as well as our own that we made. This allows us to use the full power of an existing ABI, like WASI, and give it super-powers for our specific use case.

Because the Rust WASI doesn't support the crate type of `cdylib`, we have to include a main function which we don't use. This is being discussed [here](https://github.com/WebAssembly/WASI/issues/24).

[wasi]: https://hacks.mozilla.org/2019/03/standardizing-wasi-a-webassembly-system-interface/
12 changes: 12 additions & 0 deletions examples/plugin-for-example/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
extern "C" {
fn it_works() -> i32;
}

#[no_mangle]
pub fn plugin_entrypoint(n: i32) -> i32 {
println!("Hello from inside WASI");
let result = unsafe { it_works() };
result + n
}

pub fn main() {}
12 changes: 12 additions & 0 deletions examples/plugin-for-example/wapm.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
[package]
name = "plugin-for-example"
version = "0.1.0"
description = "A plugin for our example system"
readme = "README.md"
repository = "https://github.com/wasmerio/wasmer/examples/plugin-for-example"
license = "MIT"

[[module]]
name = "plugin-for-example"
source = "../../target/wasm32-unknown-wasi/release/plugin-for-example.wasm"
abi = "none"
38 changes: 38 additions & 0 deletions examples/plugin.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
use wasmer_runtime::{func, imports, instantiate};
use wasmer_runtime_core::vm::Ctx;
use wasmer_wasi::generate_import_object;

static PLUGIN_LOCATION: &'static str = "examples/plugin-for-example.wasm";

fn it_works(_ctx: &mut Ctx) -> i32 {
println!("Hello from outside WASI");
5
}

fn main() {
// Load the plugin data
let wasm_bytes = std::fs::read(PLUGIN_LOCATION).expect(&format!(
"Could not read in WASM plugin at {}",
PLUGIN_LOCATION
));

// WASI imports
let mut base_imports = generate_import_object(vec![], vec![], vec![]);
// env is the default namespace for extern functions
let custom_imports = imports! {
"env" => {
"it_works" => func!(it_works),
},
};
// The WASI imports object contains all required import functions for a WASI module to run.
// Extend this imports with our custom imports containing "it_works" function so that our custom wasm code may run.
base_imports.extend(custom_imports);
let instance =
instantiate(&wasm_bytes[..], &base_imports).expect("failed to instantiate wasm module");

// get a reference to the function "plugin_entrypoint" which takes an i32 and returns an i32
let entry_point = instance.func::<(i32), i32>("plugin_entrypoint").unwrap();
// call the "entry_point" function in WebAssembly with the number "2" as the i32 argument
let result = entry_point.call(2).expect("failed to execute plugin");
println!("result: {}", result);
}

0 comments on commit 7ad4228

Please sign in to comment.