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

wa build 和 run 命令调整输出文件默认路径

上级 c79fbbc5
......@@ -5,6 +5,8 @@ package appast
import (
"fmt"
"os"
"path/filepath"
"strings"
"wa-lang.org/wa/internal/3rdparty/cli"
"wa-lang.org/wa/internal/ast"
......@@ -16,22 +18,32 @@ var CmdAst = &cli.Command{
Hidden: true,
Name: "ast",
Usage: "parse Wa source code and print ast",
Action: func(c *cli.Context) error {
if c.NArg() == 0 {
fmt.Fprintf(os.Stderr, "no input file")
os.Exit(1)
}
err := PrintAST(c.Args().First())
if err != nil {
fmt.Println(err)
os.Exit(1)
}
return nil
},
Action: CmdAstAction,
}
func CmdAstAction(c *cli.Context) error {
if c.NArg() == 0 {
fmt.Fprintf(os.Stderr, "no input file")
os.Exit(1)
}
err := PrintAST(c.Args().First())
if err != nil {
fmt.Println(err)
os.Exit(1)
}
return nil
}
func PrintAST(filename string) error {
ext := strings.ToLower(filepath.Ext(filename))
if ext != ".wa" && ext != ".wz" {
return fmt.Errorf("%q is not Wa file", filename)
}
if fi, _ := os.Lstat(filename); fi == nil || fi.IsDir() {
return fmt.Errorf("%q not found", filename)
}
fset := token.NewFileSet() // positions are relative to fset
f, err := parser.ParseFile(nil, fset, filename, nil, 0)
if err != nil {
......
......@@ -5,6 +5,7 @@ package appbuild
import (
"fmt"
"os"
"path/filepath"
"strings"
"wa-lang.org/wa/internal/3rdparty/cli"
......@@ -43,76 +44,214 @@ var CmdBuild = &cli.Command{
Usage: "set max memory size",
},
},
Action: func(c *cli.Context) error {
var input string
if c.NArg() > 0 {
input = c.Args().First()
} else {
input, _ = os.Getwd()
Action: CmdBuildAction,
}
func CmdBuildAction(c *cli.Context) error {
input := c.Args().First()
outfile := ""
if input == "" {
input, _ = os.Getwd()
}
var opt = appbase.BuildOptions(c)
_, err := BuildApp(opt, input, outfile)
if err != nil {
return err
}
return err
}
func BuildApp(opt *appbase.Option, input, outfile string) (wasmBytes []byte, err error) {
// 路径是否存在
if _, err := os.Lstat(input); err != nil {
fmt.Printf("%q not found\n", input)
os.Exit(1)
}
// 输出参数是否合法
if outfile != "" && hasExt(outfile, ".wasm") {
fmt.Printf("%q is not valid output path\n", outfile)
os.Exit(1)
}
// 只编译 wat 文件, 输出路径相同, 后缀名调整
if isFile(input) && hasExt(input, ".wat") {
// 设置默认输出目标
if outfile == "" {
outfile = input[:len(input)-len(".wat")] + ".wasm"
}
watData, err := os.ReadFile(input)
if err != nil {
fmt.Printf("read %s failed: %v\n", input, err)
os.Exit(1)
}
wasmBytes, err := wabt.Wat2Wasm(watData)
if err != nil {
fmt.Printf("wat2wasm %s failed: %v\n", input, err)
os.Exit(1)
}
// 写到文件
err = os.WriteFile(outfile, wasmBytes, 0666)
if err != nil {
fmt.Printf("write %s failed: %v\n", outfile, err)
os.Exit(1)
}
// OK
return wasmBytes, nil
}
// 只编译 wa/wz 文件, 输出路径相同, 后缀名调整
if isFile(input) && hasExt(input, ".wa", ".wz") {
_, watOutput, err := buildWat(opt, input)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
outfile := c.String("output")
// 设置默认输出目标
if outfile == "" {
if fi, _ := os.Lstat(input); fi != nil && fi.IsDir() {
// /xxx/yyy/ => /xxx/yyy/output/yyy.wat
outfile = input[:len(input)-len(".wa")] + ".wasm"
}
// wat 写到文件
watOutfile := outfile[:len(outfile)-len(".wasm")] + ".wat"
err = os.WriteFile(watOutfile, watOutput, 0666)
if err != nil {
fmt.Printf("write %s failed: %v\n", outfile, err)
os.Exit(1)
}
// wat 编译为 wasm
wasmBytes, err := wabt.Wat2Wasm(watOutput)
if err != nil {
fmt.Printf("wat2wasm %s failed: %v\n", input, err)
os.Exit(1)
}
// wasm 写到文件
err = os.WriteFile(outfile, wasmBytes, 0666)
if err != nil {
fmt.Printf("write %s failed: %v\n", outfile, err)
os.Exit(1)
}
// OK
return wasmBytes, nil
}
// 构建目录
{
if !isDir(input) {
fmt.Printf("%q is not valid output path\n", outfile)
os.Exit(1)
}
// 尝试读取模块信息
manifest, err := config.LoadManifest(nil, input)
if err != nil {
fmt.Printf("%q is invalid wa moudle\n", input)
os.Exit(1)
}
if !manifest.Valid() {
fmt.Printf("%q is invalid wa module\n", input)
os.Exit(1)
}
if outfile == "" {
if !manifest.IsStd {
outfile = filepath.Join(manifest.Root, "output", manifest.Pkg.Name) + ".wasm"
os.MkdirAll(filepath.Join(manifest.Root, "output"), 0777)
} else {
// /xxx/yyy/zzz.wa => /xxx/yyy/zzz.wat
outfile = "a.out." + manifest.Pkg.Name + ".wasm"
}
outfile = "a.out.wasm"
}
opt := appbase.BuildOptions(c)
watOutput, err := Build(opt, input)
// 编译出 wat 文件
_, watOutput, err := buildWat(opt, input)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
if outfile != "" && outfile != "-" {
watFilename := outfile
if !strings.HasSuffix(watFilename, ".wat") {
watFilename += ".wat"
}
err := os.WriteFile(watFilename, []byte(watOutput), 0666)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
if strings.HasSuffix(outfile, ".wasm") {
wasmBytes, err := wabt.Wat2Wasm(watOutput)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
if err := os.WriteFile(outfile, wasmBytes, 0666); err != nil {
fmt.Println(err)
os.Exit(1)
}
os.Remove(watFilename)
}
} else {
fmt.Println(string(watOutput))
// wat 写到文件
watOutfile := outfile[:len(outfile)-len(".wasm")] + ".wat"
err = os.WriteFile(watOutfile, watOutput, 0666)
if err != nil {
fmt.Printf("write %s failed: %v\n", outfile, err)
os.Exit(1)
}
return nil
},
}
// wat 编译为 wasm
wasmBytes, err := wabt.Wat2Wasm(watOutput)
if err != nil {
fmt.Printf("wat2wasm %s failed: %v\n", input, err)
os.Exit(1)
}
func Build(opt *appbase.Option, filename string) ([]byte, error) {
if _, err := os.Lstat(filename); err != nil {
return nil, fmt.Errorf("%q not found", filename)
// wasm 写到文件
err = os.WriteFile(outfile, wasmBytes, 0666)
if err != nil {
fmt.Printf("write %s failed: %v\n", outfile, err)
os.Exit(1)
}
// OK
return wasmBytes, nil
}
}
func buildWat(opt *appbase.Option, filename string) (*loader.Program, []byte, error) {
cfg := opt.Config()
prog, err := loader.LoadProgram(cfg, filename)
if err != nil {
return nil, err
return prog, nil, err
}
output, err := compiler_wat.New().Compile(prog, "main")
if err != nil {
return nil, err
return prog, nil, err
}
return prog, []byte(output), nil
}
func hasExt(filename string, extList ...string) bool {
ext := strings.ToLower(filepath.Ext(filename))
return strInList(ext, extList)
}
func isDir(filename string) bool {
fi, err := os.Lstat(filename)
if err != nil {
return false
}
return fi.IsDir()
}
return []byte(output), nil
func isFile(filename string) bool {
fi, err := os.Lstat(filename)
if err != nil {
return false
}
if fi.IsDir() {
return false
}
return true
}
func strInList(s string, list []string) bool {
for _, x := range list {
if s == x {
return true
}
}
return false
}
......@@ -11,7 +11,6 @@ import (
"wa-lang.org/wa/internal/app/appbase"
"wa-lang.org/wa/internal/app/appbuild"
"wa-lang.org/wa/internal/config"
"wa-lang.org/wa/internal/wabt"
"wa-lang.org/wa/internal/wazero"
)
......@@ -29,59 +28,21 @@ var CmdRun = &cli.Command{
Usage: "set build tags",
},
},
Action: func(c *cli.Context) error {
Run(c)
return nil
},
Action: CmdRunAction,
}
func Run(c *cli.Context) {
var infile string
if c.NArg() > 0 {
infile = c.Args().First()
} else {
infile, _ = os.Getwd()
func CmdRunAction(c *cli.Context) error {
input := c.Args().First()
outfile := ""
if input == "" {
input, _ = os.Getwd()
}
var opt = appbase.BuildOptions(c)
var watBytes []byte
var wasmBytes []byte
var err error
switch {
case strings.HasSuffix(infile, ".wat"):
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"):
wasmBytes, err = os.ReadFile(infile)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
default:
watBytes, err = appbuild.Build(opt, infile)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
if err = os.WriteFile("a.out.wat", watBytes, 0666); err != nil {
fmt.Println(err)
os.Exit(1)
}
wasmBytes, err = wabt.Wat2Wasm(watBytes)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
wasmBytes, err := appbuild.BuildApp(opt, input, outfile)
if err != nil {
return err
}
var appArgs []string
......@@ -89,7 +50,7 @@ func Run(c *cli.Context) {
appArgs = c.Args().Slice()[1:]
}
stdout, stderr, err := wazero.RunWasm(opt.Config(), infile, wasmBytes, appArgs...)
stdout, stderr, err := wazero.RunWasm(opt.Config(), input, wasmBytes, appArgs...)
if err != nil {
if len(stdout) > 0 {
fmt.Fprint(os.Stdout, string(stdout))
......@@ -108,4 +69,5 @@ func Run(c *cli.Context) {
if len(stderr) > 0 {
fmt.Fprint(os.Stderr, string(stderr))
}
return nil
}
......@@ -7,7 +7,9 @@
package app
import (
"fmt"
"os"
"strings"
"wa-lang.org/wa/internal/3rdparty/cli"
"wa-lang.org/wa/internal/app/appast"
......@@ -67,6 +69,10 @@ func Main() {
// 没有参数时显示 help 信息
cliApp.Action = func(c *cli.Context) error {
if c.NArg() > 0 {
fmt.Println("unknown args:", strings.Join(c.Args().Slice(), " "))
os.Exit(1)
}
cli.ShowAppHelpAndExit(c, 0)
return nil
}
......
......@@ -10,6 +10,8 @@ import (
"io/fs"
"os"
"path/filepath"
"strings"
"unicode"
)
// 模块文件
......@@ -108,11 +110,63 @@ func LoadManifest(vfs fs.FS, appPath string) (p *Manifest, err error) {
return p, nil
}
func (p *Manifest) Valid() bool {
if p.Root == "" || p.MainPkg == "" {
return false
}
if p.Pkg.Name == "" || p.Pkg.Pkgpath == "" {
return false
}
if !isValidAppName(p.Pkg.Name) {
return false
}
if !isValidPkgpath(p.Pkg.Pkgpath) {
return false
}
return true
}
func (p *Manifest) JSONString() string {
d, _ := json.MarshalIndent(p, "", "\t")
return string(d)
}
func isValidAppName(s string) bool {
if s == "" || s[0] == '_' || (s[0] >= '0' && s[0] <= '9') {
return false
}
for _, c := range []rune(s) {
if c == '_' || (c >= '0' && c <= '9') || unicode.IsLetter(c) {
continue
}
return false
}
return true
}
func isValidPkgpath(s string) bool {
if s == "" || s[0] == '_' || (s[0] >= '0' && s[0] <= '9') {
return false
}
for _, c := range []rune(s) {
if c == '_' || c == '.' || c == '/' || (c >= '0' && c <= '9') {
continue
}
if unicode.IsLetter(c) {
continue
}
return false
}
var pkgname = s
if i := strings.LastIndex(s, "/"); i >= 0 {
pkgname = s[i+1:]
}
return isValidAppName(pkgname)
}
// 查找 WaModFile 文件路径
func findManifestPath(vfs fs.FS, pkgpath string) (string, error) {
if pkgpath == "" {
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册