WebAssembly运行时--Wasmtime

Posted 跨链技术践行者

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了WebAssembly运行时--Wasmtime相关的知识,希望对你有一定的参考价值。

Wasmtime是由 bytecodealliance 开源的WebAssembly和WASI的小型高效运行时。它在Web外部运行WebAssembly代码,既可以用作命令行实用程序,也可以用作更大应用程序中嵌入的库。

具备以下特点:

  • 轻量级。Wasmtime是WebAssembly的独立运行时,可根据您的需求进行扩展。它适合于微型芯片,也可以使用大型服务器。 Wasmtime也可以嵌入几乎所有应用程序中。
  • 。Wasmtime建立在优化的Cranelift代码生成器上,可在运行时快速生成高质量的机器代码。
  • 可配置。无论您是需要提前预编译wasm,使用Lightbeam快速生成代码还是在运行时进行解释,Wasmtime都能满足您执行wasm的所有需求。
  • WASI 。Wasmtime支持一组丰富的API,用于通过WASI标准与主机环境进行交互。
  • 标准。Wasmtime通过了官方的WebAssembly测试套件,实现了wasm的官方C API,并且还实现了WebAssembly的proposals。 Wasmtime开发人员也一直与WebAssembly标准流程密切相关。

目前支持语言:

安装

在macos和linux上安装Wasmtime CLI非常简单,只需执行以下命令即可:

$ curl https://wasmtime.dev/install.sh -sSf | bash

Windows或是其他操作系统用户,需要到 GitHub Releases 下载。

由于我的操作系统是centos,所以可能展现的与您有所不同。我执行安装脚本之后,有如下输出:

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!

然后我们检查以下是否成功安装了wasmtime:

# 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

安装完毕,我们接下来Hello world搞起。

Demo

Wasmtime可作为Go模块使用。接下来介绍如何将Wasmtime添加到您的项目中,并提供一些示例说明可以使用WebAssembly模块完成的操作。

确保您正在使用带有模块支持的Go 1.12或更高版本。

首先创建一个go 模块项目:

$ mkdir hello-wasm
$ cd hello-wasm
$ go mod init hello-wasm

然后编写main.go,具体代码如下:

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)
	}
}

最后运行:

$ go run main.go

Hello from Go!
当然当我们wasm模块代码比较庞大的时候,我们可以将该代码放到一个以.wat结尾的文件中。然后使用 NewModuleFromFile 函数,从指定wat文件中加载模块代码。

例如:

我们创建以下wasm 文本模块,主要导出用于计算两个数字的最大公分母的函数。命名为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))
)

然后修改我们的main.go文件,如下:

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) = %d\\n", val.(int32))
	check(err)
}

func check(e error) {
	if e != nil {
		panic(e)
	}
}

运行main.go 有如下输出:

$ go run main.go
gcd(6, 27) = 3

结语

其实wasm对于go的支持并不是特别好。在以后的文章中,我们使用rust语言创建一个wasm程序,然后直接使用诸如wasmtime example.wasm 执行。

以上是关于WebAssembly运行时--Wasmtime的主要内容,如果未能解决你的问题,请参考以下文章

WebAssembly Runtimes - WASI and Wasmtime

WASI探索 -- WASI简介与Wasmtime配置

.NET 应用支持直接调用 WebAssembly 模块

.NET应用支持直接调用WebAssembly模块

.NET 应用程序支持直接调用 WebAssembly 模块

WASM 中的环境检测:Web、Node.js 还是独立运行时?