build: make llgen, cltest, gentests call build.Do

This commit is contained in:
Li Jie
2024-11-26 11:20:15 +08:00
parent 25bc84817a
commit d879d0d924
11 changed files with 87 additions and 172 deletions

View File

@@ -23,7 +23,6 @@ import (
"github.com/goplus/llgo/cl"
"github.com/goplus/llgo/internal/llgen"
"github.com/goplus/llgo/ssa"
"github.com/goplus/mod"
)
@@ -31,15 +30,12 @@ func main() {
dir, _, err := mod.FindGoMod(".")
check(err)
ssa.Initialize(ssa.InitAll | ssa.InitNative)
llgen.Verbose = false
llgenDir(dir + "/cl/_testlibc")
llgenDir(dir + "/cl/_testlibgo")
llgenDir(dir + "/cl/_testrt")
llgenDir(dir + "/cl/_testgo")
llgenDir(dir+"/cl/_testpy", "")
llgenDir(dir+"/cl/_testdata", "")
llgenDir(dir + "/cl/_testpy")
llgenDir(dir + "/cl/_testdata")
}
func isDbgSymEnabled(flagsFile string) bool {
@@ -56,7 +52,7 @@ func isDbgSymEnabled(flagsFile string) bool {
return false
}
func llgenDir(dir string, pkgPath ...string) {
func llgenDir(dir string) {
fis, err := os.ReadDir(dir)
check(err)
for _, fi := range fis {
@@ -69,8 +65,7 @@ func llgenDir(dir string, pkgPath ...string) {
check(os.Chdir(testDir))
dbg := isDbgSymEnabled("flags.txt")
cl.EnableDebugSymbols(dbg)
llgen.SmartDoFile("in.go", pkgPath...)
llgen.SmartDoFile(testDir)
}
}

View File

@@ -17,6 +17,7 @@
package main
import (
"flag"
"fmt"
"os"
@@ -24,11 +25,10 @@ import (
)
func main() {
if len(os.Args) < 2 {
fmt.Fprintln(os.Stderr, "Usage: llgen [flags] <pkg> [pkgPath]")
flag.Parse()
if len(flag.Args()) != 1 {
fmt.Fprintln(os.Stderr, "Usage: llgen [flags] <pkg>")
return
}
llgen.Init()
args := os.Args[1:]
llgen.SmartDoFile(args[0], args[1:]...)
llgen.SmartDoFile(flag.Args()[0])
}

View File

@@ -50,7 +50,7 @@ func InitDebug() {
llssa.SetDebug(llssa.DbgFlagAll)
}
func FromDir(t *testing.T, sel, relDir string, byLLGen bool) {
func FromDir(t *testing.T, sel, relDir string) {
dir, err := os.Getwd()
if err != nil {
t.Fatal("Getwd failed:", err)
@@ -66,7 +66,7 @@ func FromDir(t *testing.T, sel, relDir string, byLLGen bool) {
continue
}
t.Run(name, func(t *testing.T) {
testFrom(t, dir+"/"+name, sel, byLLGen)
testFrom(t, dir+"/"+name, sel)
})
}
}
@@ -121,12 +121,11 @@ func isDbgSymEnabled(flagsFile string) bool {
return false
}
func testFrom(t *testing.T, pkgDir, sel string, byLLGen bool) {
func testFrom(t *testing.T, pkgDir, sel string) {
if sel != "" && !strings.Contains(pkgDir, sel) {
return
}
log.Println("Parsing", pkgDir)
in := pkgDir + "/in.go"
out := pkgDir + "/out.ll"
dbg := isDbgSymEnabled(pkgDir + "/flags.txt")
if dbg {
@@ -139,13 +138,9 @@ func testFrom(t *testing.T, pkgDir, sel string, byLLGen bool) {
t.Fatal("ReadFile failed:", err)
}
expected := string(b)
if byLLGen {
if v := llgen.GenFrom(in); v != expected && expected != ";" { // expected == ";" means skipping out.ll
if v := llgen.GenFrom(pkgDir); v != expected && expected != ";" { // expected == ";" means skipping out.ll
t.Fatalf("\n==> got:\n%s\n==> expected:\n%s\n", v, expected)
}
} else {
TestCompileEx(t, nil, in, expected, dbg)
}
}
func TestCompileEx(t *testing.T, src any, fname, expected string, dbg bool) {

View File

@@ -30,34 +30,37 @@ func testCompile(t *testing.T, src, expected string) {
}
func TestFromTestgo(t *testing.T) {
cltest.FromDir(t, "", "./_testgo", false)
cltest.FromDir(t, "", "./_testgo")
}
func TestFromTestpy(t *testing.T) {
cltest.FromDir(t, "", "./_testpy", false)
cltest.FromDir(t, "", "./_testpy")
}
func TestFromTestlibgo(t *testing.T) {
cltest.FromDir(t, "", "./_testlibgo", true)
cltest.FromDir(t, "", "./_testlibgo")
}
func TestFromTestlibc(t *testing.T) {
cltest.FromDir(t, "", "./_testlibc", true)
cltest.FromDir(t, "", "./_testlibc")
}
func TestFromTestrt(t *testing.T) {
cl.SetDebug(cl.DbgFlagAll)
cltest.FromDir(t, "", "./_testrt", true)
cltest.FromDir(t, "", "./_testrt")
cl.SetDebug(0)
}
func TestFromTestdata(t *testing.T) {
cltest.FromDir(t, "", "./_testdata", false)
cltest.FromDir(t, "", "./_testdata")
}
func TestGoPkgMath(t *testing.T) {
conf := build.NewDefaultConf(build.ModeInstall)
build.Do([]string{"math"}, conf)
_, err := build.Do([]string{"math"}, conf)
if err != nil {
t.Fatal(err)
}
}
func TestVar(t *testing.T) {

View File

@@ -18,6 +18,9 @@
package build
import (
"fmt"
"os"
"github.com/goplus/llgo/cmd/internal/base"
"github.com/goplus/llgo/internal/build"
)
@@ -41,5 +44,9 @@ func runCmd(cmd *base.Command, args []string) {
conf.OutFile = args[1]
args = args[2:]
}
build.Do(args, conf)
_, err := build.Do(args, conf)
if err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
}

View File

@@ -18,6 +18,9 @@
package install
import (
"fmt"
"os"
"github.com/goplus/llgo/cmd/internal/base"
"github.com/goplus/llgo/internal/build"
)
@@ -34,5 +37,9 @@ func init() {
func runCmd(cmd *base.Command, args []string) {
conf := build.NewDefaultConf(build.ModeInstall)
build.Do(args, conf)
_, err := build.Do(args, conf)
if err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
}

View File

@@ -19,6 +19,8 @@ package run
import (
"errors"
"fmt"
"os"
"path/filepath"
"github.com/goplus/llgo/cmd/internal/base"
@@ -63,7 +65,11 @@ func runCmdEx(_ *base.Command, args []string, mode build.Mode) {
args, runArgs, err := parseRunArgs(args)
check(err)
conf.RunArgs = runArgs
build.Do(args, conf)
_, err = build.Do(args, conf)
if err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
}
func parseRunArgs(args []string) ([]string, []string, error) {

View File

@@ -53,6 +53,7 @@ const (
ModeInstall
ModeRun
ModeCmpTest
ModeGen
)
const (
@@ -119,7 +120,7 @@ const (
loadSyntax = loadTypes | packages.NeedSyntax | packages.NeedTypesInfo
)
func Do(args []string, conf *Config) {
func Do(args []string, conf *Config) ([]Package, error) {
flags, patterns, verbose := ParseArgs(args, buildFlags)
cl.EnableDebugSymbols(IsDebugEnabled())
flags = append(flags, "-tags", "llgo")
@@ -159,7 +160,6 @@ func Do(args []string, conf *Config) {
}
initial, err := packages.LoadEx(dedup, sizes, cfg, patterns...)
check(err)
mode := conf.Mode
if len(initial) == 1 && len(initial[0].CompiledGoFiles) > 0 {
if mode == ModeBuild {
@@ -167,11 +167,10 @@ func Do(args []string, conf *Config) {
}
} else if mode == ModeRun {
if len(initial) > 1 {
fmt.Fprintln(os.Stderr, "cannot run multiple packages")
return nil, fmt.Errorf("cannot run multiple packages")
} else {
fmt.Fprintln(os.Stderr, "no Go files in matched packages")
return nil, fmt.Errorf("no Go files in matched packages")
}
return
}
altPkgPaths := altPkgs(initial, llssa.PkgRuntime)
@@ -203,12 +202,21 @@ func Do(args []string, conf *Config) {
ctx := &context{env, cfg, progSSA, prog, dedup, patches, make(map[string]none), initial, mode, 0}
pkgs := buildAllPkgs(ctx, initial, verbose)
if mode == ModeGen {
for _, pkg := range pkgs {
if pkg.Package == initial[0] {
return []*aPackage{pkg}, nil
}
}
return nil, fmt.Errorf("initial package not found")
}
dpkg := buildAllPkgs(ctx, altPkgs[noRt:], verbose)
var linkArgs []string
for _, pkg := range dpkg {
linkArgs = append(linkArgs, pkg.LinkArgs...)
}
if mode != ModeBuild {
nErr := 0
for _, pkg := range initial {
@@ -220,6 +228,7 @@ func Do(args []string, conf *Config) {
os.Exit(nErr)
}
}
return dpkg, nil
}
func setNeedRuntimeOrPyInit(pkg *packages.Package, needRuntime, needPyInit bool) {
@@ -571,6 +580,8 @@ type aPackage struct {
LinkArgs []string
}
type Package = *aPackage
func allPkgs(ctx *context, initial []*packages.Package, verbose bool) (all []*aPackage, errs []*packages.Package) {
prog := ctx.progSSA
built := ctx.built

View File

@@ -16,41 +16,8 @@
package llgen
import (
"os"
"github.com/goplus/llgo/cl"
"github.com/goplus/llgo/internal/build"
"github.com/goplus/llgo/internal/mod"
llssa "github.com/goplus/llgo/ssa"
)
func Init() {
llssa.Initialize(llssa.InitAll)
llssa.SetDebug(llssa.DbgFlagAll)
cl.SetDebug(cl.DbgFlagAll)
cl.EnableDebugSymbols(build.IsDebugEnabled())
}
func PkgPath(dir string) string {
_, pkgPath, err := mod.Load(dir)
check(err)
return pkgPath
}
func Do(pkgPath, inFile, outFile string) {
ret := genFrom(inFile, pkgPath)
err := os.WriteFile(outFile, []byte(ret), 0644)
check(err)
}
func check(err error) {
if err != nil {
panic(err)
}
}
var (
Verbose = true
)

View File

@@ -17,107 +17,30 @@
package llgen
import (
"go/ast"
"go/types"
"os"
"os/exec"
"path/filepath"
"strings"
"github.com/goplus/llgo/cl"
"github.com/goplus/llgo/internal/build"
"github.com/goplus/llgo/internal/packages"
"golang.org/x/tools/go/ssa"
"golang.org/x/tools/go/ssa/ssautil"
llssa "github.com/goplus/llgo/ssa"
)
const (
loadFiles = packages.NeedName | packages.NeedFiles | packages.NeedCompiledGoFiles
loadImports = loadFiles | packages.NeedImports
loadTypes = loadImports | packages.NeedTypes | packages.NeedTypesSizes
loadSyntax = loadTypes | packages.NeedSyntax | packages.NeedTypesInfo
)
func initRtAndPy(prog llssa.Program, cfg *packages.Config) {
var pkgRtAndPy []*packages.Package
load := func() []*packages.Package {
if pkgRtAndPy == nil {
var err error
pkgRtAndPy, err = packages.LoadEx(nil, prog.TypeSizes, cfg, llssa.PkgRuntime, llssa.PkgPython)
check(err)
}
return pkgRtAndPy
}
prog.SetRuntime(func() *types.Package {
rt := load()
return rt[0].Types
})
prog.SetPython(func() *types.Package {
rt := load()
return rt[1].Types
})
}
func GenFrom(fileOrPkg string) string {
return genFrom(fileOrPkg, "")
}
func genFrom(fileOrPkg string, pkgPath string) string {
prog := llssa.NewProgram(nil)
cfg := &packages.Config{
Mode: loadSyntax | packages.NeedDeps,
BuildFlags: []string{"-tags", "llgo"},
}
dedup := packages.NewDeduper()
dedup.SetPkgPath(func(path, name string) string {
if path == "command-line-arguments" {
if pkgPath != "" {
path = pkgPath
} else {
path = name
}
}
return path
})
dedup.SetPreload(func(pkg *types.Package, files []*ast.File) {
cl.ParsePkgSyntax(prog, pkg, files)
})
initial, err := packages.LoadEx(dedup, prog.TypeSizes, cfg, fileOrPkg)
pkg, err := genFrom(fileOrPkg)
check(err)
buildMode := ssa.SanityCheckFunctions | ssa.InstantiateGenerics
if build.IsDebugEnabled() {
buildMode |= ssa.GlobalDebug
}
if !build.IsOptimizeEnabled() {
buildMode |= ssa.NaiveForm
}
_, pkgs := ssautil.AllPackages(initial, buildMode)
pkg := initial[0]
ssaPkg := pkgs[0]
ssaPkg.Build()
initRtAndPy(prog, cfg)
if Verbose {
ssaPkg.WriteTo(os.Stderr)
return pkg.LPkg.String()
}
ret, err := cl.NewPackage(prog, ssaPkg, pkg.Syntax)
check(err)
if prog.NeedPyInit { // call PyInit if needed
ret.PyInit()
func genFrom(pkgPath string) (build.Package, error) {
conf := &build.Config{
Mode: build.ModeGen,
AppExt: build.DefaultAppExt(),
}
return ret.String()
pkgs, err := build.Do([]string{pkgPath}, conf)
if err != nil {
return nil, err
}
return pkgs[0], nil
}
func DoFile(fileOrPkg, outFile string) {
@@ -126,9 +49,12 @@ func DoFile(fileOrPkg, outFile string) {
check(err)
}
func SmartDoFile(inFile string, pkgPath ...string) {
func SmartDoFile(pkgPath ...string) {
pkg, err := genFrom(pkgPath[0])
check(err)
const autgenFile = "llgo_autogen.ll"
dir, _ := filepath.Split(inFile)
dir, _ := filepath.Split(pkg.GoFiles[0])
absDir, _ := filepath.Abs(dir)
absDir = filepath.ToSlash(absDir)
fname := autgenFile
@@ -142,10 +68,8 @@ func SmartDoFile(inFile string, pkgPath ...string) {
return // skip to gen
}
if len(pkgPath) > 0 {
Do(pkgPath[0], inFile, outFile)
} else {
DoFile(inFile, outFile)
if err = os.WriteFile(outFile, []byte(pkg.LPkg.String()), 0644); err != nil {
panic(err)
}
if false && fname == autgenFile {
genZip(absDir, "llgo_autogen.lla", autgenFile)

View File

@@ -30,27 +30,27 @@ func init() {
}
func TestFromTestlibgo(t *testing.T) {
cltest.FromDir(t, "", "../cl/_testlibgo", false)
cltest.FromDir(t, "", "../cl/_testlibgo")
}
func TestFromTestgo(t *testing.T) {
cltest.FromDir(t, "", "../cl/_testgo", false)
cltest.FromDir(t, "", "../cl/_testgo")
}
func TestFromTestpy(t *testing.T) {
cltest.FromDir(t, "", "../cl/_testpy", false)
cltest.FromDir(t, "", "../cl/_testpy")
}
func TestFromTestlibc(t *testing.T) {
cltest.FromDir(t, "", "../cl/_testlibc", true)
cltest.FromDir(t, "", "../cl/_testlibc")
}
func TestFromTestrt(t *testing.T) {
cltest.FromDir(t, "", "../cl/_testrt", true)
cltest.FromDir(t, "", "../cl/_testrt")
}
func TestFromTestdata(t *testing.T) {
cltest.FromDir(t, "", "../cl/_testdata", false)
cltest.FromDir(t, "", "../cl/_testdata")
}
func TestMakeInterface(t *testing.T) {