main: compile and run a program directly
Do not try to use the ExectutionEngine of Go, instead compile the program in the conventional way and run the binary. This fixes some code duplication that causes slight (but problematic) misbehavior between `tinygo build` and `tinygo run`.
Этот коммит содержится в:
родитель
9ac2f39acc
коммит
95e18f36d0
1 изменённых файлов: 30 добавлений и 64 удалений
72
main.go
72
main.go
|
@ -15,7 +15,6 @@ import (
|
|||
"strings"
|
||||
"syscall"
|
||||
|
||||
"github.com/aykevl/go-llvm"
|
||||
"github.com/aykevl/tinygo/compiler"
|
||||
"github.com/aykevl/tinygo/interp"
|
||||
"github.com/aykevl/tinygo/loader"
|
||||
|
@ -397,58 +396,29 @@ func FlashGDB(pkgName, target, port string, ocdOutput bool, config *BuildConfig)
|
|||
})
|
||||
}
|
||||
|
||||
// Run the specified package directly (using JIT or interpretation).
|
||||
func Run(pkgName string) error {
|
||||
config := compiler.Config{
|
||||
RootDir: sourceDir(),
|
||||
GOPATH: getGopath(),
|
||||
InitInterp: true,
|
||||
}
|
||||
c, err := compiler.NewCompiler(pkgName, config)
|
||||
if err != nil {
|
||||
return errors.New("compiler: " + err.Error())
|
||||
}
|
||||
err = c.Compile(pkgName)
|
||||
if err != nil {
|
||||
return errors.New("compiler: " + err.Error())
|
||||
}
|
||||
if err := c.Verify(); err != nil {
|
||||
return errors.New("compiler error: failed to verify module: " + err.Error())
|
||||
}
|
||||
// -Oz, which is the fastest optimization level (faster than -O0, -O1, -O2
|
||||
// and -Os). Turn off the inliner, as the inliner increases optimization
|
||||
// time.
|
||||
err = c.Optimize(2, 2, 0)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
engine, err := llvm.NewExecutionEngine(c.Module())
|
||||
if err != nil {
|
||||
return errors.New("interpreter setup: " + err.Error())
|
||||
}
|
||||
defer engine.Dispose()
|
||||
|
||||
main := engine.FindFunction("main")
|
||||
if main.IsNil() {
|
||||
return errors.New("could not find main function")
|
||||
}
|
||||
engine.RunFunction(main, nil)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Compile and run the given program in an emulator.
|
||||
func Emulate(pkgName, target string, config *BuildConfig) error {
|
||||
// Compile and run the given program, directly or in an emulator.
|
||||
func Run(pkgName, target string, config *BuildConfig) error {
|
||||
spec, err := LoadTarget(target)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(spec.Emulator) == 0 {
|
||||
return errors.New("no emulator configured for this target")
|
||||
}
|
||||
|
||||
return Compile(pkgName, ".elf", spec, config, func(tmppath string) error {
|
||||
if len(spec.Emulator) == 0 {
|
||||
// Run directly.
|
||||
cmd := exec.Command(tmppath)
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
err := cmd.Run()
|
||||
if err != nil {
|
||||
if err, ok := err.(*exec.ExitError); ok && err.Exited() {
|
||||
// Workaround for QEMU which always exits with an error.
|
||||
return nil
|
||||
}
|
||||
}
|
||||
return err
|
||||
} else {
|
||||
// Run in an emulator.
|
||||
args := append(spec.Emulator[1:], tmppath)
|
||||
cmd := exec.Command(spec.Emulator[0], args...)
|
||||
cmd.Stdout = os.Stdout
|
||||
|
@ -461,6 +431,7 @@ func Emulate(pkgName, target string, config *BuildConfig) error {
|
|||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -585,13 +556,8 @@ func main() {
|
|||
usage()
|
||||
os.Exit(1)
|
||||
}
|
||||
if *target == "" {
|
||||
err := Run(flag.Arg(0))
|
||||
err := Run(flag.Arg(0), *target, config)
|
||||
handleCompilerError(err)
|
||||
} else {
|
||||
err := Emulate(flag.Arg(0), *target, config)
|
||||
handleCompilerError(err)
|
||||
}
|
||||
case "clean":
|
||||
// remove cache directory
|
||||
dir := cacheDir()
|
||||
|
|
Загрузка…
Создание таблицы
Сослаться в новой задаче