all: run test binaries in the correct directory

Test binaries must be run in the source directory of the package to be
tested. This wasn't done, leading to a few "file not found" errors.

This commit implements this. Unfortunately, it does not allow more
packages to be tested as both affected packages (debug/macho and
debug/plan9obj) will still fail with this patch even though the "file
not found" errors are gone.
Этот коммит содержится в:
Ayke van Laethem 2020-09-04 00:25:11 +02:00 коммит произвёл Ron Evans
родитель 57a5b833b2
коммит 88fd2823df
3 изменённых файлов: 80 добавлений и 39 удалений

Просмотреть файл

@ -24,22 +24,35 @@ import (
"tinygo.org/x/go-llvm"
)
// BuildResult is the output of a build. This includes the binary itself and
// some other metadata that is obtained while building the binary.
type BuildResult struct {
// A path to the output binary. It will be removed after Build returns, so
// if it should be kept it must be copied or moved away.
Binary string
// The directory of the main package. This is useful for testing as the test
// binary must be run in the directory of the tested package.
MainDir string
}
// Build performs a single package to executable Go build. It takes in a package
// name, an output path, and set of compile options and from that it manages the
// whole compilation process.
//
// The error value may be of type *MultiError. Callers will likely want to check
// for this case and print such errors individually.
func Build(pkgName, outpath string, config *compileopts.Config, action func(string) error) error {
func Build(pkgName, outpath string, config *compileopts.Config, action func(BuildResult) error) error {
// Compile Go code to IR.
machine, err := compiler.NewTargetMachine(config)
if err != nil {
return err
}
mod, extraFiles, extraLDFlags, errs := compiler.Compile(pkgName, machine, config)
buildOutput, errs := compiler.Compile(pkgName, machine, config)
if errs != nil {
return newMultiError(errs)
}
mod := buildOutput.Mod
if config.Options.PrintIR {
fmt.Println("; Generated LLVM IR:")
@ -196,7 +209,7 @@ func Build(pkgName, outpath string, config *compileopts.Config, action func(stri
}
// Compile C files in packages.
for i, file := range extraFiles {
for i, file := range buildOutput.ExtraFiles {
outpath := filepath.Join(dir, "pkg"+strconv.Itoa(i)+"-"+filepath.Base(file)+".o")
err := runCCompiler(config.Target.Compiler, append(config.CFlags(), "-c", "-o", outpath, file)...)
if err != nil {
@ -205,8 +218,8 @@ func Build(pkgName, outpath string, config *compileopts.Config, action func(stri
ldflags = append(ldflags, outpath)
}
if len(extraLDFlags) > 0 {
ldflags = append(ldflags, extraLDFlags...)
if len(buildOutput.ExtraLDFlags) > 0 {
ldflags = append(ldflags, buildOutput.ExtraLDFlags...)
}
// Link the object files together.
@ -289,7 +302,10 @@ func Build(pkgName, outpath string, config *compileopts.Config, action func(stri
default:
return fmt.Errorf("unknown output binary format: %s", outputBinaryFormat)
}
return action(tmppath)
return action(BuildResult{
Binary: tmppath,
MainDir: buildOutput.MainDir,
})
}
}

Просмотреть файл

@ -127,6 +127,28 @@ func NewTargetMachine(config *compileopts.Config) (llvm.TargetMachine, error) {
return machine, nil
}
// CompilerOutput is returned from the Compile() call. It contains the compile
// output and information necessary to continue to compile and link the program.
type CompilerOutput struct {
// The LLVM module that contains the compiled but not optimized LLVM module
// for all the Go code in the program.
Mod llvm.Module
// ExtraFiles is a list of C source files included in packages that should
// be built and linked together with the main executable to form one
// program. They can be used from CGo, for example.
ExtraFiles []string
// ExtraLDFlags are linker flags obtained during CGo processing. These flags
// must be passed to the linker which links the entire executable.
ExtraLDFlags []string
// MainDir is the absolute directory path to the directory of the main
// package. This is useful for testing: tests must be run in the package
// directory that is being tested.
MainDir string
}
// Compile the given package path or .go file path. Return an error when this
// fails (in any stage). If successful it returns the LLVM module and a list of
// extra C files to be compiled. If not, one or more errors will be returned.
@ -135,7 +157,7 @@ func NewTargetMachine(config *compileopts.Config) (llvm.TargetMachine, error) {
// violation. Eventually, this Compile function should only compile a single
// package and not the whole program, and loading of the program (including CGo
// processing) should be moved outside the compiler package.
func Compile(pkgName string, machine llvm.TargetMachine, config *compileopts.Config) (mod llvm.Module, extrafiles []string, extraldflags []string, errors []error) {
func Compile(pkgName string, machine llvm.TargetMachine, config *compileopts.Config) (output CompilerOutput, errors []error) {
c := &compilerContext{
Config: config,
difiles: make(map[string]llvm.Metadata),
@ -151,6 +173,7 @@ func Compile(pkgName string, machine llvm.TargetMachine, config *compileopts.Con
if c.Debug() {
c.dibuilder = llvm.NewDIBuilder(c.mod)
}
output.Mod = c.mod
c.uintptrType = c.ctx.IntType(c.targetData.PointerSize() * 8)
if c.targetData.PointerSize() <= 4 {
@ -176,20 +199,22 @@ func Compile(pkgName string, machine llvm.TargetMachine, config *compileopts.Con
MaxAlign: int64(c.targetData.PrefTypeAlignment(c.i8ptrType)),
}})
if err != nil {
return c.mod, nil, nil, []error{err}
return output, []error{err}
}
err = lprogram.Parse()
if err != nil {
return c.mod, nil, nil, []error{err}
return output, []error{err}
}
output.ExtraLDFlags = lprogram.LDFlags
output.MainDir = lprogram.MainPkg().Dir
c.ir = ir.NewProgram(lprogram)
// Run a simple dead code elimination pass.
err = c.ir.SimpleDCE()
if err != nil {
return c.mod, nil, nil, []error{err}
return output, []error{err}
}
// Initialize debug information.
@ -328,14 +353,13 @@ func Compile(pkgName string, machine llvm.TargetMachine, config *compileopts.Con
}
// Gather the list of (C) file paths that should be included in the build.
var extraFiles []string
for _, pkg := range c.ir.LoaderProgram.Sorted() {
for _, filename := range pkg.CFiles {
extraFiles = append(extraFiles, filepath.Join(pkg.Dir, filename))
output.ExtraFiles = append(output.ExtraFiles, filepath.Join(pkg.Dir, filename))
}
}
return c.mod, extraFiles, lprogram.LDFlags, c.diagnostics
return output, c.diagnostics
}
// getLLVMRuntimeType obtains a named type from the runtime package and returns

53
main.go
Просмотреть файл

@ -90,10 +90,10 @@ func Build(pkgName, outpath string, options *compileopts.Options) error {
return err
}
return builder.Build(pkgName, outpath, config, func(tmppath string) error {
if err := os.Rename(tmppath, outpath); err != nil {
return builder.Build(pkgName, outpath, config, func(result builder.BuildResult) error {
if err := os.Rename(result.Binary, outpath); err != nil {
// Moving failed. Do a file copy.
inf, err := os.Open(tmppath)
inf, err := os.Open(result.Binary)
if err != nil {
return err
}
@ -126,10 +126,11 @@ func Test(pkgName string, options *compileopts.Options) error {
return err
}
return builder.Build(pkgName, ".elf", config, func(tmppath string) error {
cmd := exec.Command(tmppath)
return builder.Build(pkgName, ".elf", config, func(result builder.BuildResult) error {
cmd := exec.Command(result.Binary)
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
cmd.Dir = result.MainDir
err := cmd.Run()
if err != nil {
// Propagate the exit code
@ -139,7 +140,7 @@ func Test(pkgName string, options *compileopts.Options) error {
}
os.Exit(1)
}
return &commandError{"failed to run compiled binary", tmppath, err}
return &commandError{"failed to run compiled binary", result.Binary, err}
}
return nil
})
@ -183,7 +184,7 @@ func Flash(pkgName, port string, options *compileopts.Options) error {
return errors.New("unknown flash method: " + flashMethod)
}
return builder.Build(pkgName, fileExt, config, func(tmppath string) error {
return builder.Build(pkgName, fileExt, config, func(result builder.BuildResult) error {
// do we need port reset to put MCU into bootloader mode?
if config.Target.PortReset == "true" && flashMethod != "openocd" {
if port == "" {
@ -196,7 +197,7 @@ func Flash(pkgName, port string, options *compileopts.Options) error {
err := touchSerialPortAt1200bps(port)
if err != nil {
return &commandError{"failed to reset port", tmppath, err}
return &commandError{"failed to reset port", result.Binary, err}
}
// give the target MCU a chance to restart into bootloader
time.Sleep(3 * time.Second)
@ -208,7 +209,7 @@ func Flash(pkgName, port string, options *compileopts.Options) error {
// Create the command.
flashCmd := config.Target.FlashCommand
fileToken := "{" + fileExt[1:] + "}"
flashCmd = strings.Replace(flashCmd, fileToken, tmppath, -1)
flashCmd = strings.Replace(flashCmd, fileToken, result.Binary, -1)
if port == "" && strings.Contains(flashCmd, "{port}") {
var err error
@ -238,21 +239,21 @@ func Flash(pkgName, port string, options *compileopts.Options) error {
cmd.Dir = goenv.Get("TINYGOROOT")
err := cmd.Run()
if err != nil {
return &commandError{"failed to flash", tmppath, err}
return &commandError{"failed to flash", result.Binary, err}
}
return nil
case "msd":
switch fileExt {
case ".uf2":
err := flashUF2UsingMSD(config.Target.FlashVolume, tmppath)
err := flashUF2UsingMSD(config.Target.FlashVolume, result.Binary)
if err != nil {
return &commandError{"failed to flash", tmppath, err}
return &commandError{"failed to flash", result.Binary, err}
}
return nil
case ".hex":
err := flashHexUsingMSD(config.Target.FlashVolume, tmppath)
err := flashHexUsingMSD(config.Target.FlashVolume, result.Binary)
if err != nil {
return &commandError{"failed to flash", tmppath, err}
return &commandError{"failed to flash", result.Binary, err}
}
return nil
default:
@ -263,13 +264,13 @@ func Flash(pkgName, port string, options *compileopts.Options) error {
if err != nil {
return err
}
args = append(args, "-c", "program "+filepath.ToSlash(tmppath)+" reset exit")
args = append(args, "-c", "program "+filepath.ToSlash(result.Binary)+" reset exit")
cmd := exec.Command("openocd", args...)
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
err = cmd.Run()
if err != nil {
return &commandError{"failed to flash", tmppath, err}
return &commandError{"failed to flash", result.Binary, err}
}
return nil
default:
@ -294,7 +295,7 @@ func FlashGDB(pkgName string, ocdOutput bool, options *compileopts.Options) erro
return errors.New("gdb not configured in the target specification")
}
return builder.Build(pkgName, "", config, func(tmppath string) error {
return builder.Build(pkgName, "", config, func(result builder.BuildResult) error {
// Find a good way to run GDB.
gdbInterface, openocdInterface := config.Programmer()
switch gdbInterface {
@ -357,7 +358,7 @@ func FlashGDB(pkgName string, ocdOutput bool, options *compileopts.Options) erro
gdbCommands = append(gdbCommands, "target remote :1234")
// Run in an emulator.
args := append(config.Target.Emulator[1:], tmppath, "-s", "-S")
args := append(config.Target.Emulator[1:], result.Binary, "-s", "-S")
daemon = exec.Command(config.Target.Emulator[0], args...)
daemon.Stdout = os.Stdout
daemon.Stderr = os.Stderr
@ -365,7 +366,7 @@ func FlashGDB(pkgName string, ocdOutput bool, options *compileopts.Options) erro
gdbCommands = append(gdbCommands, "target remote :2345")
// Run in an emulator.
args := append(config.Target.Emulator[1:], tmppath, "-g")
args := append(config.Target.Emulator[1:], result.Binary, "-g")
daemon = exec.Command(config.Target.Emulator[0], args...)
daemon.Stdout = os.Stdout
daemon.Stderr = os.Stderr
@ -403,7 +404,7 @@ func FlashGDB(pkgName string, ocdOutput bool, options *compileopts.Options) erro
// Construct and execute a gdb command.
// By default: gdb -ex run <binary>
// Exit GDB with Ctrl-D.
params := []string{tmppath}
params := []string{result.Binary}
for _, cmd := range gdbCommands {
params = append(params, "-ex", cmd)
}
@ -413,7 +414,7 @@ func FlashGDB(pkgName string, ocdOutput bool, options *compileopts.Options) erro
cmd.Stderr = os.Stderr
err := cmd.Run()
if err != nil {
return &commandError{"failed to run gdb with", tmppath, err}
return &commandError{"failed to run gdb with", result.Binary, err}
}
return nil
})
@ -429,10 +430,10 @@ func Run(pkgName string, options *compileopts.Options) error {
return err
}
return builder.Build(pkgName, ".elf", config, func(tmppath string) error {
return builder.Build(pkgName, ".elf", config, func(result builder.BuildResult) error {
if len(config.Target.Emulator) == 0 {
// Run directly.
cmd := exec.Command(tmppath)
cmd := exec.Command(result.Binary)
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
err := cmd.Run()
@ -441,12 +442,12 @@ func Run(pkgName string, options *compileopts.Options) error {
// Workaround for QEMU which always exits with an error.
return nil
}
return &commandError{"failed to run compiled binary", tmppath, err}
return &commandError{"failed to run compiled binary", result.Binary, err}
}
return nil
} else {
// Run in an emulator.
args := append(config.Target.Emulator[1:], tmppath)
args := append(config.Target.Emulator[1:], result.Binary)
cmd := exec.Command(config.Target.Emulator[0], args...)
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
@ -456,7 +457,7 @@ func Run(pkgName string, options *compileopts.Options) error {
// Workaround for QEMU which always exits with an error.
return nil
}
return &commandError{"failed to run emulator with", tmppath, err}
return &commandError{"failed to run emulator with", result.Binary, err}
}
return nil
}