Wasmtime is made by bytecodealliance Small and efficient runtime for open source WebAssembly and WASI. It runs WebAssembly code outside the Web, both as a command-line utility and as a library embedded in larger applications.
Has the following characteristics:
- Lightweight. Wasmtime is a standalone runtime for WebAssembly that can be extended according to your needs. It is suitable for tiny chips and can also use large servers. Wasmtime can also be embedded in almost any application.
- quick. Wasmtime is built on an optimized Cranelift code generator to quickly generate high-quality machine code at runtime.
- Configurable. Whether you need to precompile wasm ahead of time, generate code quickly with Lightbeam, or interpret it at runtime, Wasmtime has everything you need to execute wasm.
- WASI. Wasmtime supports a rich set of API s for WASI standard Interact with the host environment.
- standard. Wasmtime passed the official WebAssembly test suite, implemented wasm's official C API, and also implemented WebAssembly's proposals. Wasmtime developers have also been closely associated with the WebAssembly standard process.
Currently supported languages:
- Rust - the ["https://crates.io/crates/wasmtime">wasmtime crate](https://zhuanlan.zhihu.com/p/224862650/%3C/code)
- C - the f="https://bytecodealliance.github.io/wasmtime/c-api/">wasm.h, wasi.h, and wasmtime.h headers
- Python - the ["https://pypi.org/project/wasmtime/">wasmtime PyPI package](https://zhuanlan.zhihu.com/p/224862650/%3C/code)
- .NET - the ["https://www.nuget.org/packages/Wasmtime">Wasmtime NuGet package](https://zhuanlan.zhihu.com/p/224862650/%3C/code)
- Go - the [wasmtime-go repository](https://zhuanlan.zhihu.com/p/224862650/ht%3C/code%3Etps://pkg.go.dev/github.com/bytecodealliance/wasmtime-go)
Install
Installing Wasmtime CLI on macos and linux is as easy as executing the following command:
$ curl https://wasmtime.dev/install.sh -sSf | bash
Windows or other operating system users, need to go to GitHub Releases download.
Since my operating system is centos, it may appear different from yours. After I execute the install script, I have the following output:
curl https://wasmtime.dev/install.sh -sSf | bash Installing latest version of Wasmtime (dev) Checking for existing Wasmtime installation Fetching archive for Linux, version dev https://github.com/cranestation/wasmtime/releases/download/dev/wasmtime-dev-x86_64-linux.tar.xz ######################################################################## 100.0% Creating directory layout Extracting Wasmtime binaries wasmtime-dev-x86_64-linux/ wasmtime-dev-x86_64-linux/wasmtime wasmtime-dev-x86_64-linux/LICENSE wasmtime-dev-x86_64-linux/README.md Editing user profile (/root/.bashrc) Warning: Your profile (/root/.bashrc) already mentions Wasmtime and has not been changed. Finished installation. Open a new terminal to start using Wasmtime!
Then we check if wasmtime was successfully installed with the following:
# wasmtime wasmtime 0.19.0 Wasmtime WebAssembly Runtime USAGE: wasmtime <SUBCOMMAND> FLAGS: -h, --help Prints help information -V, --version Prints version information SUBCOMMANDS: config Controls Wasmtime configuration settings help Prints this message or the help of the given subcommand(s) run Runs a WebAssembly module wasm2obj Translates a WebAssembly module to native object file wast Runs a WebAssembly test script file If a subcommand is not provided, the `run` subcommand will be used. Usage examples: Running a WebAssembly module with a start function: wasmtime example.wasm Passing command line arguments to a WebAssembly module: wasmtime example.wasm arg1 arg2 arg3 Invoking a specific function (e.g. `add`) in a WebAssembly module: wasmtime example.wasm --invoke add 1 2
After the installation is complete, let's start with Hello world.
Demo
Wasmtime is available as a Go module. The following sections describe how to add Wasmtime to your project, with some examples of what can be done with WebAssembly modules.
Make sure you are using Go 1.12 or higher with module support.
First create a go module project:
$ mkdir hello-wasm $ cd hello-wasm $ go mod init hello-wasm
Then write main.go, the specific code is as follows:
package main import ( "fmt" "github.com/bytecodealliance/wasmtime-go" ) func main() { engine := wasmtime.NewEngine() // Almost all operations in wasmtime require a contextual `store` // argument to share, so create that first store := wasmtime.NewStore(engine) // Compiling modules requires WebAssembly binary input, but the wasmtime // package also supports converting the WebAssembly text format to the // binary format. wasm, err := wasmtime.Wat2Wasm(` (module (import "" "hello" (func $hello)) (func (export "run") (call $hello)) ) `) check(err) // Once we have our binary `wasm` we can compile that into a `*Module` // which represents compiled JIT code. module, err := wasmtime.NewModule(engine, wasm) check(err) // Our `hello.wat` file imports one item, so we create that function // here. item := wasmtime.WrapFunc(store, func() { fmt.Println("Hello from Go!") }) // Next up we instantiate a module which is where we link in all our // imports. We've got one import so we pass that in here. instance, err := wasmtime.NewInstance(store, module, []*wasmtime.Extern{item.AsExtern()}) check(err) // After we've instantiated we can lookup our `run` function and call // it. run := instance.GetExport("run").Func() _, err = run.Call() check(err) } func check(e error) { if e != nil { panic(e) } }
Finally run:
$ go run main.go Hello from Go!
Of course, when our wasm module code is relatively large, we can put the code in a file ending in .wat. Then use the NewModuleFromFile function to load the module code from the specified wat file.
E.g:
We create the following wasm text module that mainly exports a function for calculating the greatest common denominator of two numbers. Name it gcd.wat.
(module (func $gcd (param i32 i32) (result i32) (local i32) block ;; label = @1 block ;; label = @2 local.get 0 br_if 0 (;@2;) local.get 1 local.set 2 br 1 (;@1;) end loop ;; label = @2 local.get 1 local.get 0 local.tee 2 i32.rem_u local.set 0 local.get 2 local.set 1 local.get 0 br_if 0 (;@2;) end end local.get 2 ) (export "gcd" (func $gcd)) )
Then modify our main.go file as follows:
package main import ( "fmt" "github.com/bytecodealliance/wasmtime-go" ) func main() { engine := wasmtime.NewEngine() store := wasmtime.NewStore(engine) module, err := wasmtime.NewModuleFromFile(engine, "gcd.wat") check(err) instance, err := wasmtime.NewInstance(store, module, []*wasmtime.Extern{}) check(err) gcd := instance.GetExport("gcd").Func() val, err := gcd.Call(6, 27) fmt.Printf("gcd(6, 27) = %dn", val.(int32)) check(err) } func check(e error) { if e != nil { panic(e) } }
Running main.go yields the following output:
$ go run main.go gcd(6, 27) = 3
Epilogue
In fact, wasm's support for go is not particularly good. In future articles, we will create a wasm program in rust and execute it directly using something like wasmtime example.wasm .