summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Clayton <a.clayton@nginx.com>2023-10-25 19:41:47 +0100
committerAndrew Clayton <a.clayton@nginx.com>2023-10-25 19:57:13 +0100
commit3aed80812e105cd99c43f11023012608aecd9f4a (patch)
treeef078ea7efe8f5024294cb698d6fb47be2891c25
parent510d3becc7592405f02e90f5aa43740c53f7deeb (diff)
downloadproject_blackbird-3aed80812e105cd99c43f11023012608aecd9f4a.tar.gz
project_blackbird-3aed80812e105cd99c43f11023012608aecd9f4a.tar.bz2
Add a component model example
This adds the 'Hello World' example from here[0]. The runtime is in Rust and the component is in C. This requires some new tools - https://github.com/bytecodealliance/wit-bindgen - https://github.com/bytecodealliance/wasm-tools You can use the pre-built packages, once downloaded and untar'd, edit rust/hello_world/component/Makefile and adjust the paths for the above tools. To build the component with make you may need to specify where the WASI sysroot is $ make WASI_SYSROOT=/path/to/wasi-sysroot [0]: <https://docs.rs/wasmtime/latest/wasmtime/component/macro.bindgen.html> Signed-off-by: Andrew Clayton <a.clayton@nginx.com>
Diffstat (limited to '')
-rw-r--r--README32
-rw-r--r--rust/.gitignore3
-rw-r--r--rust/hello_world/Cargo.toml10
-rw-r--r--rust/hello_world/component/.gitignore1
-rw-r--r--rust/hello_world/component/Makefile27
-rw-r--r--rust/hello_world/component/my-component.c14
-rw-r--r--rust/hello_world/src/main.rs62
-rw-r--r--rust/hello_world/wit/my-component.wit8
8 files changed, 157 insertions, 0 deletions
diff --git a/README b/README
index 822d1df..7e13c9a 100644
--- a/README
+++ b/README
@@ -70,3 +70,35 @@ Getting function exports...
[cabi_realloc]
Shutting down...
Done.
+
+
+Component Model
+===============
+
+You can play with the component model under rust/hello_world
+
+This requires some new tools
+
+ - https://github.com/bytecodealliance/wit-bindgen
+ - https://github.com/bytecodealliance/wasm-tools
+
+ You can use the pre-built packages, once downloaded and untar'd, edit
+
+ rust/hello_world/component/Makefile
+
+ and adjust the paths for the above tools.
+
+ To build the component with make you may need to specify where the WASI
+ sysroot is
+
+ $ make WASI_SYSROOT=/path/to/wasi-sysroot
+
+You can then build the Rust runtime under rust/hello_world with
+
+ $ cargo build
+
+after a while (sheesh) it should finish... then you can run it with
+
+ $ target/debug/hello_world
+
+it won't actually print anything, but also shouldn't give an error.
diff --git a/rust/.gitignore b/rust/.gitignore
new file mode 100644
index 0000000..559d663
--- /dev/null
+++ b/rust/.gitignore
@@ -0,0 +1,3 @@
+Cargo.lock
+
+target/
diff --git a/rust/hello_world/Cargo.toml b/rust/hello_world/Cargo.toml
new file mode 100644
index 0000000..7051e1b
--- /dev/null
+++ b/rust/hello_world/Cargo.toml
@@ -0,0 +1,10 @@
+[package]
+name = "hello_world"
+version = "0.1.0"
+edition = "2021"
+
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+
+[dependencies]
+wasmtime = "14.0.1"
+wasmtime-wasi = "14.0.1"
diff --git a/rust/hello_world/component/.gitignore b/rust/hello_world/component/.gitignore
new file mode 100644
index 0000000..5e4f2b2
--- /dev/null
+++ b/rust/hello_world/component/.gitignore
@@ -0,0 +1 @@
+hello_world*
diff --git a/rust/hello_world/component/Makefile b/rust/hello_world/component/Makefile
new file mode 100644
index 0000000..a7f3f85
--- /dev/null
+++ b/rust/hello_world/component/Makefile
@@ -0,0 +1,27 @@
+# Look for wasi-sysroot in some common places, falling back
+# to provided WASI_SYSROOT
+ifneq ("$(wildcard /usr/wasm32-wasi)", "")
+ # Fedora
+ WASI_SYSROOT ?= /usr/wasm32-wasi
+else ifneq ("$(wildcard /usr/local/share/wasi-sysroot)", "")
+ # FreeBSD
+ WASI_SYSROOT ?= /usr/local/share/wasi-sysroot
+endif
+
+export WASI_SYSROOT
+
+CC = clang
+CFLAGS = -Wall -Wextra --target=wasm32-wasi --sysroot=$(WASI_SYSROOT)
+LDFLAGS = -Wl,--no-entry -mexec-model=reactor --rtlib=compiler-rt
+
+all: hello_world.wasm
+
+bindgen:
+ /home/andrew/src/c/wasm/wit-bindgen-v0.13.0-x86_64-linux/wit-bindgen c ../wit
+
+hello_world.wasm: bindgen my-component.c
+ $(CC) $(CFLAGS) $(LDFLAGS) -o $@ hello_world.c hello_world_component_type.o my-component.c
+ /home/andrew/src/c/wasm/wasm-tools-1.0.48-x86_64-linux/wasm-tools component new hello_world.wasm -o hello_world-component.wasm
+
+clean:
+ rm -f hello_world*
diff --git a/rust/hello_world/component/my-component.c b/rust/hello_world/component/my-component.c
new file mode 100644
index 0000000..fe09975
--- /dev/null
+++ b/rust/hello_world/component/my-component.c
@@ -0,0 +1,14 @@
+/*
+ * my-component.c
+ */
+
+#include "hello_world.h"
+
+void hello_world_greet(void)
+{
+ hello_world_string_t my_string;
+
+ hello_world_string_set(&my_string, "Hello, world!");
+
+ hello_world_name(&my_string);
+}
diff --git a/rust/hello_world/src/main.rs b/rust/hello_world/src/main.rs
new file mode 100644
index 0000000..98b16bb
--- /dev/null
+++ b/rust/hello_world/src/main.rs
@@ -0,0 +1,62 @@
+/*
+ * Example from
+ * https://docs.rs/wasmtime/latest/wasmtime/component/macro.bindgen.html
+ */
+
+use wasmtime::component::*;
+use wasmtime::{Config, Engine, Store};
+
+bindgen!();
+
+struct MyState {
+ name: String,
+}
+
+// Imports into the world, like the `name` import for this world, are satisfied
+// through traits.
+impl HelloWorldImports for MyState {
+ // Note the `Result` return value here where `Ok` is returned back to
+ // the component and `Err` will raise a trap.
+ fn name(&mut self) -> wasmtime::Result<String> {
+ Ok(self.name.clone())
+ }
+}
+
+fn main() -> wasmtime::Result<()> {
+ // Configure an `Engine` and compile the `Component` that is being run for
+ // the application.
+ let mut config = Config::new();
+ config.wasm_component_model(true);
+ let engine = Engine::new(&config)?;
+ let component = Component::from_file(&engine,
+ "component/hello_world-component.wasm")?;
+
+ // Instantiation of bindings always happens through a `Linker`.
+ // Configuration of the linker is done through a generated `add_to_linker`
+ // method on the bindings structure.
+ //
+ // Note that the closure provided here is a projection from `T` in
+ // `Store<T>` to `&mut U` where `U` implements the `HelloWorldImports`
+ // trait. In this case the `T`, `MyState`, is stored directly in the
+ // structure so no projection is necessary here.
+ let mut linker = Linker::new(&engine);
+ HelloWorld::add_to_linker(&mut linker, |state: &mut MyState| state)?;
+
+ // As with the core wasm API of Wasmtime instantiation occurs within a
+ // `Store`. The bindings structure contains an `instantiate` method which
+ // takes the store, component, and linker. This returns the `bindings`
+ // structure which is an instance of `HelloWorld` and supports typed access
+ // to the exports of the component.
+ let mut store = Store::new(
+ &engine,
+ MyState {
+ name: "me".to_string(),
+ },
+ );
+ let (bindings, _) = HelloWorld::instantiate(&mut store, &component, &linker)?;
+
+ // Here our `greet` function doesn't take any parameters for the component,
+ // but in the Wasmtime embedding API the first argument is always a `Store`.
+ bindings.call_greet(&mut store)?;
+ Ok(())
+}
diff --git a/rust/hello_world/wit/my-component.wit b/rust/hello_world/wit/my-component.wit
new file mode 100644
index 0000000..5ce6b6f
--- /dev/null
+++ b/rust/hello_world/wit/my-component.wit
@@ -0,0 +1,8 @@
+// wit/my-component.wit
+
+package my:project;
+
+world hello-world {
+ import name: func() -> string;
+ export greet: func();
+}