test: print package name when compilation failed
Before this patch, a compile error would prevent the 'ok' or 'FAIL' line to be printed. That's unexpected. This patch changes the code in such a way that it's obvious a test result line is printed in all cases. To be able to also print the package name, I had to make sure the build result is passed through everywhere even on all the failure paths. This results in a bit of churn, but it's all relatively straightforward. Found while working on Go 1.20.
Этот коммит содержится в:
родитель
911ce3a4bc
коммит
80077ef276
3 изменённых файлов: 67 добавлений и 72 удалений
100
builder/build.go
100
builder/build.go
|
@ -190,12 +190,21 @@ func Build(pkgName, outpath, tmpdir string, config *compileopts.Config) (BuildRe
|
|||
lprogram, err := loader.Load(config, pkgName, config.ClangHeaders, types.Config{
|
||||
Sizes: compiler.Sizes(machine),
|
||||
})
|
||||
if err != nil {
|
||||
return BuildResult{}, err
|
||||
result := BuildResult{
|
||||
ModuleRoot: lprogram.MainPkg().Module.Dir,
|
||||
MainDir: lprogram.MainPkg().Dir,
|
||||
ImportPath: lprogram.MainPkg().ImportPath,
|
||||
}
|
||||
if result.ModuleRoot == "" {
|
||||
// If there is no module root, just the regular root.
|
||||
result.ModuleRoot = lprogram.MainPkg().Root
|
||||
}
|
||||
if err != nil { // failed to load AST
|
||||
return result, err
|
||||
}
|
||||
err = lprogram.Parse()
|
||||
if err != nil {
|
||||
return BuildResult{}, err
|
||||
return result, err
|
||||
}
|
||||
|
||||
// Create the *ssa.Program. This does not yet build the entire SSA of the
|
||||
|
@ -278,7 +287,7 @@ func Build(pkgName, outpath, tmpdir string, config *compileopts.Config) (BuildRe
|
|||
for _, imported := range pkg.Pkg.Imports() {
|
||||
job, ok := packageActionIDJobs[imported.Path()]
|
||||
if !ok {
|
||||
return BuildResult{}, fmt.Errorf("package %s imports %s but couldn't find dependency", pkg.ImportPath, imported.Path())
|
||||
return result, fmt.Errorf("package %s imports %s but couldn't find dependency", pkg.ImportPath, imported.Path())
|
||||
}
|
||||
importedPackages = append(importedPackages, job)
|
||||
actionIDDependencies = append(actionIDDependencies, job)
|
||||
|
@ -573,17 +582,17 @@ func Build(pkgName, outpath, tmpdir string, config *compileopts.Config) (BuildRe
|
|||
// Run jobs to produce the LLVM module.
|
||||
err := runJobs(programJob, config.Options.Semaphore)
|
||||
if err != nil {
|
||||
return BuildResult{}, err
|
||||
return result, err
|
||||
}
|
||||
// Generate output.
|
||||
switch outext {
|
||||
case ".o":
|
||||
llvmBuf, err := machine.EmitToMemoryBuffer(mod, llvm.ObjectFile)
|
||||
if err != nil {
|
||||
return BuildResult{}, err
|
||||
return result, err
|
||||
}
|
||||
defer llvmBuf.Dispose()
|
||||
return BuildResult{}, os.WriteFile(outpath, llvmBuf.Bytes(), 0666)
|
||||
return result, os.WriteFile(outpath, llvmBuf.Bytes(), 0666)
|
||||
case ".bc":
|
||||
var buf llvm.MemoryBuffer
|
||||
if config.UseThinLTO() {
|
||||
|
@ -592,10 +601,10 @@ func Build(pkgName, outpath, tmpdir string, config *compileopts.Config) (BuildRe
|
|||
buf = llvm.WriteBitcodeToMemoryBuffer(mod)
|
||||
}
|
||||
defer buf.Dispose()
|
||||
return BuildResult{}, os.WriteFile(outpath, buf.Bytes(), 0666)
|
||||
return result, os.WriteFile(outpath, buf.Bytes(), 0666)
|
||||
case ".ll":
|
||||
data := []byte(mod.String())
|
||||
return BuildResult{}, os.WriteFile(outpath, data, 0666)
|
||||
return result, os.WriteFile(outpath, data, 0666)
|
||||
default:
|
||||
panic("unreachable")
|
||||
}
|
||||
|
@ -629,19 +638,19 @@ func Build(pkgName, outpath, tmpdir string, config *compileopts.Config) (BuildRe
|
|||
|
||||
// Prepare link command.
|
||||
linkerDependencies := []*compileJob{outputObjectFileJob}
|
||||
executable := filepath.Join(tmpdir, "main")
|
||||
result.Executable = filepath.Join(tmpdir, "main")
|
||||
if config.GOOS() == "windows" {
|
||||
executable += ".exe"
|
||||
result.Executable += ".exe"
|
||||
}
|
||||
tmppath := executable // final file
|
||||
ldflags := append(config.LDFlags(), "-o", executable)
|
||||
result.Binary = result.Executable // final file
|
||||
ldflags := append(config.LDFlags(), "-o", result.Executable)
|
||||
|
||||
// Add compiler-rt dependency if needed. Usually this is a simple load from
|
||||
// a cache.
|
||||
if config.Target.RTLib == "compiler-rt" {
|
||||
job, unlock, err := CompilerRT.load(config, tmpdir)
|
||||
if err != nil {
|
||||
return BuildResult{}, err
|
||||
return result, err
|
||||
}
|
||||
defer unlock()
|
||||
linkerDependencies = append(linkerDependencies, job)
|
||||
|
@ -716,7 +725,7 @@ func Build(pkgName, outpath, tmpdir string, config *compileopts.Config) (BuildRe
|
|||
ldflags = append(ldflags, "--strip-debug")
|
||||
} else {
|
||||
// Other linkers may have different flags.
|
||||
return BuildResult{}, errors.New("cannot remove debug information: unknown linker: " + config.Target.Linker)
|
||||
return result, errors.New("cannot remove debug information: unknown linker: " + config.Target.Linker)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -768,7 +777,7 @@ func Build(pkgName, outpath, tmpdir string, config *compileopts.Config) (BuildRe
|
|||
}
|
||||
err = link(config.Target.Linker, ldflags...)
|
||||
if err != nil {
|
||||
return &commandError{"failed to link", executable, err}
|
||||
return &commandError{"failed to link", result.Executable, err}
|
||||
}
|
||||
|
||||
var calculatedStacks []string
|
||||
|
@ -777,7 +786,7 @@ func Build(pkgName, outpath, tmpdir string, config *compileopts.Config) (BuildRe
|
|||
// Try to determine stack sizes at compile time.
|
||||
// Don't do this by default as it usually doesn't work on
|
||||
// unsupported architectures.
|
||||
calculatedStacks, stackSizes, err = determineStackSizes(mod, executable)
|
||||
calculatedStacks, stackSizes, err = determineStackSizes(mod, result.Executable)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -787,14 +796,14 @@ func Build(pkgName, outpath, tmpdir string, config *compileopts.Config) (BuildRe
|
|||
if config.AutomaticStackSize() {
|
||||
// Modify the .tinygo_stacksizes section that contains a stack size
|
||||
// for each goroutine.
|
||||
err = modifyStackSizes(executable, stackSizeLoads, stackSizes)
|
||||
err = modifyStackSizes(result.Executable, stackSizeLoads, stackSizes)
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not modify stack sizes: %w", err)
|
||||
}
|
||||
}
|
||||
if config.RP2040BootPatch() {
|
||||
// Patch the second stage bootloader CRC into the .boot2 section
|
||||
err = patchRP2040BootCRC(executable)
|
||||
err = patchRP2040BootCRC(result.Executable)
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not patch RP2040 second stage boot loader: %w", err)
|
||||
}
|
||||
|
@ -827,8 +836,8 @@ func Build(pkgName, outpath, tmpdir string, config *compileopts.Config) (BuildRe
|
|||
args = append(args,
|
||||
opt,
|
||||
"-g",
|
||||
executable,
|
||||
"--output", executable,
|
||||
result.Executable,
|
||||
"--output", result.Executable,
|
||||
)
|
||||
|
||||
cmd := exec.Command(goenv.Get("WASMOPT"), args...)
|
||||
|
@ -847,7 +856,7 @@ func Build(pkgName, outpath, tmpdir string, config *compileopts.Config) (BuildRe
|
|||
for _, pkg := range lprogram.Sorted() {
|
||||
packagePathMap[pkg.OriginalDir()] = pkg.Pkg.Path()
|
||||
}
|
||||
sizes, err := loadProgramSize(executable, packagePathMap)
|
||||
sizes, err := loadProgramSize(result.Executable, packagePathMap)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -883,7 +892,7 @@ func Build(pkgName, outpath, tmpdir string, config *compileopts.Config) (BuildRe
|
|||
// is simpler and cannot be parallelized.
|
||||
err = runJobs(linkJob, config.Options.Semaphore)
|
||||
if err != nil {
|
||||
return BuildResult{}, err
|
||||
return result, err
|
||||
}
|
||||
|
||||
// Get an Intel .hex file or .bin file from the .elf file.
|
||||
|
@ -894,56 +903,43 @@ func Build(pkgName, outpath, tmpdir string, config *compileopts.Config) (BuildRe
|
|||
case "hex", "bin":
|
||||
// Extract raw binary, either encoding it as a hex file or as a raw
|
||||
// firmware file.
|
||||
tmppath = filepath.Join(tmpdir, "main"+outext)
|
||||
err := objcopy(executable, tmppath, outputBinaryFormat)
|
||||
result.Binary = filepath.Join(tmpdir, "main"+outext)
|
||||
err := objcopy(result.Executable, result.Binary, outputBinaryFormat)
|
||||
if err != nil {
|
||||
return BuildResult{}, err
|
||||
return result, err
|
||||
}
|
||||
case "uf2":
|
||||
// Get UF2 from the .elf file.
|
||||
tmppath = filepath.Join(tmpdir, "main"+outext)
|
||||
err := convertELFFileToUF2File(executable, tmppath, config.Target.UF2FamilyID)
|
||||
result.Binary = filepath.Join(tmpdir, "main"+outext)
|
||||
err := convertELFFileToUF2File(result.Executable, result.Binary, config.Target.UF2FamilyID)
|
||||
if err != nil {
|
||||
return BuildResult{}, err
|
||||
return result, err
|
||||
}
|
||||
case "esp32", "esp32-img", "esp32c3", "esp8266":
|
||||
// Special format for the ESP family of chips (parsed by the ROM
|
||||
// bootloader).
|
||||
tmppath = filepath.Join(tmpdir, "main"+outext)
|
||||
err := makeESPFirmareImage(executable, tmppath, outputBinaryFormat)
|
||||
result.Binary = filepath.Join(tmpdir, "main"+outext)
|
||||
err := makeESPFirmareImage(result.Executable, result.Binary, outputBinaryFormat)
|
||||
if err != nil {
|
||||
return BuildResult{}, err
|
||||
return result, err
|
||||
}
|
||||
case "nrf-dfu":
|
||||
// special format for nrfutil for Nordic chips
|
||||
tmphexpath := filepath.Join(tmpdir, "main.hex")
|
||||
err := objcopy(executable, tmphexpath, "hex")
|
||||
err := objcopy(result.Executable, tmphexpath, "hex")
|
||||
if err != nil {
|
||||
return BuildResult{}, err
|
||||
return result, err
|
||||
}
|
||||
tmppath = filepath.Join(tmpdir, "main"+outext)
|
||||
err = makeDFUFirmwareImage(config.Options, tmphexpath, tmppath)
|
||||
result.Binary = filepath.Join(tmpdir, "main"+outext)
|
||||
err = makeDFUFirmwareImage(config.Options, tmphexpath, result.Binary)
|
||||
if err != nil {
|
||||
return BuildResult{}, err
|
||||
return result, err
|
||||
}
|
||||
default:
|
||||
return BuildResult{}, fmt.Errorf("unknown output binary format: %s", outputBinaryFormat)
|
||||
return result, fmt.Errorf("unknown output binary format: %s", outputBinaryFormat)
|
||||
}
|
||||
|
||||
// If there's a module root, use that.
|
||||
moduleroot := lprogram.MainPkg().Module.Dir
|
||||
if moduleroot == "" {
|
||||
// if not, just the regular root
|
||||
moduleroot = lprogram.MainPkg().Root
|
||||
}
|
||||
|
||||
return BuildResult{
|
||||
Executable: executable,
|
||||
Binary: tmppath,
|
||||
MainDir: lprogram.MainPkg().Dir,
|
||||
ModuleRoot: moduleroot,
|
||||
ImportPath: lprogram.MainPkg().ImportPath,
|
||||
}, nil
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// createEmbedObjectFile creates a new object file with the given contents, for
|
||||
|
|
37
main.go
37
main.go
|
@ -246,7 +246,8 @@ func Test(pkgName string, stdout, stderr io.Writer, options *compileopts.Options
|
|||
|
||||
buf := bytes.Buffer{}
|
||||
passed := false
|
||||
err = buildAndRun(pkgName, config, &buf, flags, nil, 0, func(cmd *exec.Cmd, result builder.BuildResult) error {
|
||||
var duration time.Duration
|
||||
result, err := buildAndRun(pkgName, config, &buf, flags, nil, 0, func(cmd *exec.Cmd, result builder.BuildResult) error {
|
||||
if testCompileOnly || outpath != "" {
|
||||
// Write test binary to the specified file name.
|
||||
if outpath == "" {
|
||||
|
@ -312,10 +313,7 @@ func Test(pkgName string, stdout, stderr io.Writer, options *compileopts.Options
|
|||
// Run the test.
|
||||
start := time.Now()
|
||||
err = cmd.Run()
|
||||
duration := time.Since(start)
|
||||
|
||||
// Print the result.
|
||||
importPath := strings.TrimSuffix(result.ImportPath, ".test")
|
||||
duration = time.Since(start)
|
||||
passed = err == nil
|
||||
|
||||
// print the test output if
|
||||
|
@ -326,23 +324,23 @@ func Test(pkgName string, stdout, stderr io.Writer, options *compileopts.Options
|
|||
buf.WriteTo(stdout)
|
||||
}
|
||||
|
||||
// final status line
|
||||
if passed {
|
||||
fmt.Fprintf(stdout, "ok \t%s\t%.3fs\n", importPath, duration.Seconds())
|
||||
} else {
|
||||
fmt.Fprintf(stdout, "FAIL\t%s\t%.3fs\n", importPath, duration.Seconds())
|
||||
}
|
||||
if _, ok := err.(*exec.ExitError); ok {
|
||||
// Binary exited with a non-zero exit code, which means the test
|
||||
// failed.
|
||||
// failed. Return nil to avoid printing a useless "exited with
|
||||
// error" error message.
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
})
|
||||
importPath := strings.TrimSuffix(result.ImportPath, ".test")
|
||||
if err, ok := err.(loader.NoTestFilesError); ok {
|
||||
fmt.Fprintf(stdout, "? \t%s\t[no test files]\n", err.ImportPath)
|
||||
// Pretend the test passed - it at least didn't fail.
|
||||
return true, nil
|
||||
} else if passed {
|
||||
fmt.Fprintf(stdout, "ok \t%s\t%.3fs\n", importPath, duration.Seconds())
|
||||
} else {
|
||||
fmt.Fprintf(stdout, "FAIL\t%s\t%.3fs\n", importPath, duration.Seconds())
|
||||
}
|
||||
return passed, err
|
||||
}
|
||||
|
@ -765,16 +763,17 @@ func Run(pkgName string, options *compileopts.Options, cmdArgs []string) error {
|
|||
return err
|
||||
}
|
||||
|
||||
return buildAndRun(pkgName, config, os.Stdout, cmdArgs, nil, 0, func(cmd *exec.Cmd, result builder.BuildResult) error {
|
||||
_, err = buildAndRun(pkgName, config, os.Stdout, cmdArgs, nil, 0, func(cmd *exec.Cmd, result builder.BuildResult) error {
|
||||
return cmd.Run()
|
||||
})
|
||||
return err
|
||||
}
|
||||
|
||||
// buildAndRun builds and runs the given program, writing output to stdout and
|
||||
// errors to os.Stderr. It takes care of emulators (qemu, wasmtime, etc) and
|
||||
// passes command line arguments and evironment variables in a way appropriate
|
||||
// for the given emulator.
|
||||
func buildAndRun(pkgName string, config *compileopts.Config, stdout io.Writer, cmdArgs, environmentVars []string, timeout time.Duration, run func(cmd *exec.Cmd, result builder.BuildResult) error) error {
|
||||
func buildAndRun(pkgName string, config *compileopts.Config, stdout io.Writer, cmdArgs, environmentVars []string, timeout time.Duration, run func(cmd *exec.Cmd, result builder.BuildResult) error) (builder.BuildResult, error) {
|
||||
// Determine whether we're on a system that supports environment variables
|
||||
// and command line parameters (operating systems, WASI) or not (baremetal,
|
||||
// WebAssembly in the browser). If we're on a system without an environment,
|
||||
|
@ -828,7 +827,7 @@ func buildAndRun(pkgName string, config *compileopts.Config, stdout io.Writer, c
|
|||
// Create a temporary directory for intermediary files.
|
||||
tmpdir, err := os.MkdirTemp("", "tinygo")
|
||||
if err != nil {
|
||||
return err
|
||||
return builder.BuildResult{}, err
|
||||
}
|
||||
if !config.Options.Work {
|
||||
defer os.RemoveAll(tmpdir)
|
||||
|
@ -838,7 +837,7 @@ func buildAndRun(pkgName string, config *compileopts.Config, stdout io.Writer, c
|
|||
format, fileExt := config.EmulatorFormat()
|
||||
result, err := builder.Build(pkgName, fileExt, tmpdir, config)
|
||||
if err != nil {
|
||||
return err
|
||||
return result, err
|
||||
}
|
||||
|
||||
// If needed, set a timeout on the command. This is done in tests so
|
||||
|
@ -857,7 +856,7 @@ func buildAndRun(pkgName string, config *compileopts.Config, stdout io.Writer, c
|
|||
} else {
|
||||
emulator, err := config.Emulator(format, result.Binary)
|
||||
if err != nil {
|
||||
return err
|
||||
return result, err
|
||||
}
|
||||
name = emulator[0]
|
||||
emuArgs := append([]string(nil), emulator[1:]...)
|
||||
|
@ -898,9 +897,9 @@ func buildAndRun(pkgName string, config *compileopts.Config, stdout io.Writer, c
|
|||
stdout.Write([]byte(fmt.Sprintf("--- timeout of %s exceeded, terminating...\n", timeout)))
|
||||
err = ctx.Err()
|
||||
}
|
||||
return &commandError{"failed to run compiled binary", result.Binary, err}
|
||||
return result, &commandError{"failed to run compiled binary", result.Binary, err}
|
||||
}
|
||||
return nil
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func touchSerialPortAt1200bps(port string) (err error) {
|
||||
|
|
|
@ -329,7 +329,7 @@ func runTestWithConfig(name string, t *testing.T, options compileopts.Options, c
|
|||
|
||||
// Build the test binary.
|
||||
stdout := &bytes.Buffer{}
|
||||
err = buildAndRun("./"+path, config, stdout, cmdArgs, environmentVars, time.Minute, func(cmd *exec.Cmd, result builder.BuildResult) error {
|
||||
_, err = buildAndRun("./"+path, config, stdout, cmdArgs, environmentVars, time.Minute, func(cmd *exec.Cmd, result builder.BuildResult) error {
|
||||
return cmd.Run()
|
||||
})
|
||||
if err != nil {
|
||||
|
|
Загрузка…
Создание таблицы
Сослаться в новой задаче