提交 a72a04ea 编写于 作者: chai2010's avatar chai2010

启用新包装的 wabt 函数

上级 de465562
......@@ -13,11 +13,11 @@ import (
"github.com/tetratelabs/wazero"
"github.com/tetratelabs/wazero/sys"
"wa-lang.org/wa/internal/app/apputil"
"wa-lang.org/wa/internal/app/waruntime"
"wa-lang.org/wa/internal/backends/compiler_wat"
"wa-lang.org/wa/internal/config"
"wa-lang.org/wa/internal/loader"
"wa-lang.org/wa/internal/wabt"
)
func (p *App) RunTest(pkgpath string, appArgs ...string) error {
......@@ -42,18 +42,14 @@ func (p *App) RunTest(pkgpath string, appArgs ...string) error {
return err
}
// wat 落盘(仅用于调试)
os.WriteFile("a.out.wat", []byte(watOutput), 0666)
// 编译为 wasm
if err = os.WriteFile("a.out.wat", []byte(watOutput), 0666); err != nil {
return err
}
wasmBytes, stderr, err := apputil.RunWat2Wasm("a.out.wat")
wasmBytes, err := wabt.Wat2Wasm([]byte(watOutput))
if err != nil {
if s := sWithPrefix(string(stderr), " "); s != "" {
fmt.Println(s)
}
return err
}
// os.WriteFile("a.out.wasm", wasmBytes, 0666)
// 构建 wasm 可执行实例
// https://pkg.go.dev/github.com/tetratelabs/wazero@v1.0.0-pre.4#section-readme
......@@ -166,21 +162,22 @@ func (p *App) RunTest(pkgpath string, appArgs ...string) error {
}
}
for _, t := range mainPkg.TestInfo.Examples {
output, err := compiler_wat.New().Compile(prog, t.Name)
if err != nil {
return err
}
stdoutBuffer.Reset()
stderrBuffer.Reset()
if err = os.WriteFile("a.out.wat", []byte(output), 0666); err != nil {
_, err := wasmIns.ExportedFunction(mainPkg.Pkg.Path() + "." + t.Name).Call(ctx)
if err != nil {
if s := sWithPrefix(stderrBuffer.String(), " "); s != "" {
fmt.Println(s)
}
return err
}
stdout, stderr, err := apputil.RunWasmEx(cfg, "a.out.wat", appArgs...)
stdout := stdoutBuffer.Bytes()
stderr := stderrBuffer.Bytes()
stdout = bytes.TrimSpace(stdout)
bOutputOK := t.Output == string(stdout)
if err == nil && bOutputOK {
if t.Output != "" && t.Output == string(stdout) {
continue
}
......
// 版权 @2019 凹语言 作者。保留所有权利。
package apputil
import (
"bytes"
"context"
"crypto/rand"
"errors"
"os"
"os/exec"
"path/filepath"
"runtime"
"strings"
"sync"
"github.com/tetratelabs/wazero"
"github.com/tetratelabs/wazero/sys"
"wa-lang.org/wa/internal/app/waruntime"
"wa-lang.org/wa/internal/config"
"wa-lang.org/wa/internal/logger"
"wa-lang.org/wabt-go"
wabt_wasm "wa-lang.org/wabt-go/wabt-wasm"
)
func getWatAbsDir(filename string) string {
dir := filepath.Dir(filename)
abs, err := filepath.Abs(dir)
if err != nil {
return filepath.ToSlash(dir)
}
return filepath.ToSlash(abs)
}
func RunWasm(cfg *config.Config, filename string, wasmArgs ...string) (stdoutStderr []byte, err error) {
stdout, stderr, err := runWasm(cfg, filename, wasmArgs...)
stdoutStderr = append(stdout, stderr...)
return
}
func RunWasmEx(cfg *config.Config, filename string, wasmArgs ...string) (stdout, stderr []byte, err error) {
stdout, stderr, err = runWasm(cfg, filename, wasmArgs...)
return
}
func RunWat2Wasm(filename string) (stdout, stderr []byte, err error) {
watDir := getWatAbsDir(filename)
stdout, stderr, err = xRunWat2Wasm_exe(watDir, filename, "--output=-")
return
}
func runWasm(cfg *config.Config, filename string, wasmArgs ...string) (stdout, stderr []byte, err error) {
dst := filename
if strings.HasSuffix(filename, ".wat") {
dst = filename + ".wasm"
defer func() {
if err == nil {
os.Remove(dst)
}
}()
if stdout, stderr, err = xRunWat2Wasm_exe("", filename, "--output=-"); err != nil {
return stdout, stderr, err
}
os.WriteFile(dst, stdout, 0666)
}
wasmBytes, err := os.ReadFile(dst)
if err != nil {
return nil, nil, err
}
wasmExe := filepath.Base(filename)
stdoutBuffer := new(bytes.Buffer)
stderrBuffer := new(bytes.Buffer)
conf := wazero.NewModuleConfig().
WithStdout(stdoutBuffer).
WithStderr(stderrBuffer).
WithStdin(os.Stdin).
WithRandSource(rand.Reader).
WithSysNanosleep().
WithSysNanotime().
WithSysWalltime().
WithArgs(append([]string{wasmExe}, wasmArgs...)...)
// TODO: Windows 可能导致异常, 临时屏蔽
if runtime.GOOS != "windows" {
for _, s := range os.Environ() {
var key, value string
if kv := strings.Split(s, "="); len(kv) >= 2 {
key = kv[0]
value = kv[1]
} else if len(kv) >= 1 {
key = kv[0]
}
conf = conf.WithEnv(key, value)
}
}
ctx := context.Background()
r := wazero.NewRuntime(ctx)
defer r.Close(ctx)
code, err := r.CompileModule(ctx, wasmBytes)
if err != nil {
return stdoutBuffer.Bytes(), stderrBuffer.Bytes(), err
}
switch cfg.WaOS {
case config.WaOS_arduino:
if _, err = waruntime.ArduinoInstantiate(ctx, r); err != nil {
return stdoutBuffer.Bytes(), stderrBuffer.Bytes(), err
}
case config.WaOS_chrome:
if _, err = waruntime.ChromeInstantiate(ctx, r); err != nil {
return stdoutBuffer.Bytes(), stderrBuffer.Bytes(), err
}
case config.WaOS_wasi:
if _, err = waruntime.WasiInstantiate(ctx, r); err != nil {
return stdoutBuffer.Bytes(), stderrBuffer.Bytes(), err
}
}
_, err = r.InstantiateModule(ctx, code, conf)
if err != nil {
if exitErr, ok := err.(*sys.ExitError); ok {
if exitErr.ExitCode() == 0 {
return stdoutBuffer.Bytes(), stderrBuffer.Bytes(), nil
}
}
return stdoutBuffer.Bytes(), stderrBuffer.Bytes(), err
}
return stdoutBuffer.Bytes(), stderrBuffer.Bytes(), nil
}
func xRunWat2Wasm_wasm(dir string, args ...string) (stdout, stderr []byte, err error) {
if true {
panic("disabled")
}
stdoutBuffer := new(bytes.Buffer)
stderrBuffer := new(bytes.Buffer)
conf := wazero.NewModuleConfig().
WithFS(os.DirFS(dir)).
WithStdout(stdoutBuffer).
WithStderr(stderrBuffer).
WithStdin(os.Stdin).
WithRandSource(rand.Reader).
WithSysNanosleep().
WithSysNanotime().
WithSysWalltime().
WithArgs(append([]string{"wat2wasm.wasm"}, args...)...)
ctx := context.Background()
r := wazero.NewRuntime(ctx)
defer r.Close(ctx)
code, err := r.CompileModule(ctx, []byte(wabt_wasm.LoadWat2Wasm()))
if err != nil {
return stdoutBuffer.Bytes(), stderrBuffer.Bytes(), err
}
if _, err = waruntime.WasiInstantiate(ctx, r); err != nil {
return stdoutBuffer.Bytes(), stderrBuffer.Bytes(), err
}
_, err = r.InstantiateModule(ctx, code, conf)
if err != nil {
if exitErr, ok := err.(*sys.ExitError); ok {
if exitErr.ExitCode() == 0 {
return stdoutBuffer.Bytes(), stderrBuffer.Bytes(), nil
}
}
return stdoutBuffer.Bytes(), stderrBuffer.Bytes(), err
}
return stdoutBuffer.Bytes(), stderrBuffer.Bytes(), nil
}
var muRunWat2Wasm sync.Mutex
var wat2wasmPath string
func xRunWat2Wasm_exe(_ string, args ...string) (stdout, stderr []byte, err error) {
muRunWat2Wasm.Lock()
defer muRunWat2Wasm.Unlock()
if wat2wasmPath == "" {
logger.Tracef(&config.EnableTrace_app, "wat2wasm not found")
return nil, nil, errors.New("wat2wasm not found")
}
var bufStdout bytes.Buffer
var bufStderr bytes.Buffer
cmd := exec.Command(wat2wasmPath, args...)
cmd.Stdout = &bufStdout
cmd.Stderr = &bufStderr
err = cmd.Run()
stdout = bufStdout.Bytes()
stderr = bufStderr.Bytes()
return
}
func init() {
const baseName = "wa.wat2wasm.exe"
// 1. exe 同级目录存在 wat2wasm ?
wat2wasmPath = filepath.Join(curExeDir(), baseName)
if exeExists(wat2wasmPath) {
return
}
// 2. 当前目录存在 wat2wasm ?
cwd, _ := os.Getwd()
wat2wasmPath = filepath.Join(cwd, baseName)
if exeExists(wat2wasmPath) {
return
}
// 3. 本地系统存在 wat2wasm ?
if s, _ := exec.LookPath(baseName); s != "" {
wat2wasmPath = s
return
}
// 4. wat2wasm 安装到 exe 所在目录 ?
wat2wasmPath = filepath.Join(curExeDir(), baseName)
if err := os.WriteFile(wat2wasmPath, wabt.LoadWat2Wasm(), 0777); err != nil {
logger.Tracef(&config.EnableTrace_app, "install wat2wasm failed: %+v", err)
return
}
}
// 是否为目录
func isDir(path string) bool {
if fi, _ := os.Lstat(path); fi != nil && fi.IsDir() {
return true
}
return false
}
// exe 文件存在
func exeExists(path string) bool {
fi, err := os.Lstat(path)
if err != nil {
return false
}
if !fi.Mode().IsRegular() {
return false
}
return true
}
// 当前执行程序所在目录
func curExeDir() string {
s, err := os.Executable()
if err != nil {
logger.Panicf("os.Executable() failed: %+v", err)
}
return filepath.Dir(s)
}
......@@ -18,10 +18,11 @@ import (
"wa-lang.org/wa/api"
"wa-lang.org/wa/internal/3rdparty/cli"
"wa-lang.org/wa/internal/app"
"wa-lang.org/wa/internal/app/apputil"
"wa-lang.org/wa/internal/app/yacc"
"wa-lang.org/wa/internal/config"
"wa-lang.org/wa/internal/lsp"
"wa-lang.org/wa/internal/wabt"
"wa-lang.org/wa/internal/wazero"
)
func Main() {
......@@ -195,7 +196,7 @@ func Main() {
}
ctx := app.NewApp(build_Options(c))
output, err := ctx.WASM(input)
watOutput, err := ctx.WASM(input)
if err != nil {
fmt.Println(err)
os.Exit(1)
......@@ -206,28 +207,25 @@ func Main() {
if !strings.HasSuffix(watFilename, ".wat") {
watFilename += ".wat"
}
err := os.WriteFile(watFilename, []byte(output), 0666)
err := os.WriteFile(watFilename, []byte(watOutput), 0666)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
if strings.HasSuffix(outfile, ".wasm") {
stdout, stderr, err := apputil.RunWat2Wasm(watFilename)
wasmBytes, err := wabt.Wat2Wasm(watOutput)
if err != nil {
if len(stderr) != 0 {
fmt.Println(string(stderr))
}
fmt.Println(err)
os.Exit(1)
}
if err := os.WriteFile(outfile, stdout, 0666); err != nil {
if err := os.WriteFile(outfile, wasmBytes, 0666); err != nil {
fmt.Println(err)
os.Exit(1)
}
os.Remove(watFilename)
}
} else {
fmt.Println(string(output))
fmt.Println(string(watOutput))
}
return nil
......@@ -526,37 +524,36 @@ func cliRun(c *cli.Context) {
}
var app = app.NewApp(build_Options(c))
var outfile string
var output []byte
var watBytes []byte
var wasmBytes []byte
var err error
if !c.Bool("debug") {
defer os.Remove(outfile)
}
switch {
case strings.HasSuffix(infile, ".wat"):
outfile = infile
output, err = os.ReadFile(infile)
watBytes, err = os.ReadFile(infile)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
wasmBytes, err = wabt.Wat2Wasm(watBytes)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
case strings.HasSuffix(infile, ".wasm"):
outfile = infile
output, err = os.ReadFile(infile)
wasmBytes, err = os.ReadFile(infile)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
default:
outfile = "a.out.wat"
output, err = app.WASM(infile)
watBytes, err = app.WASM(infile)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
if err = os.WriteFile(outfile, []byte(output), 0666); err != nil {
if err = os.WriteFile("a.out.wat", watBytes, 0666); err != nil {
fmt.Println(err)
os.Exit(1)
}
......@@ -567,18 +564,24 @@ func cliRun(c *cli.Context) {
appArgs = c.Args().Slice()[1:]
}
stdoutStderr, err := apputil.RunWasm(app.GetConfig(), outfile, appArgs...)
stdout, stderr, err := wazero.RunWasm(app.GetConfig(), infile, wasmBytes, appArgs...)
if err != nil {
if len(stdoutStderr) > 0 {
fmt.Println(string(stdoutStderr))
if len(stdout) > 0 {
fmt.Fprint(os.Stdout, (stdout))
}
if len(stderr) > 0 {
fmt.Fprint(os.Stderr, (stderr))
}
if exitErr, ok := err.(*sys.ExitError); ok {
os.Exit(int(exitErr.ExitCode()))
}
fmt.Println(err)
}
if len(stdoutStderr) > 0 {
fmt.Println(string(stdoutStderr))
if len(stdout) > 0 {
fmt.Fprint(os.Stdout, (stdout))
}
if len(stderr) > 0 {
fmt.Fprint(os.Stderr, (stderr))
}
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册