1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132
|
// Package gobuild provides utilities for building programs and tests
// for the debugging session.
package gobuild
import (
"fmt"
"os"
"os/exec"
"runtime"
"strings"
"time"
"github.com/go-delve/delve/pkg/config"
)
// Remove the file at path and issue a warning to stderr if this fails.
// This can be used to remove the temporary binary generated for the session.
func Remove(path string) {
var err error
for i := 0; i < 20; i++ {
err = os.Remove(path)
// Open files can be removed on Unix, but not on Windows, where there also appears
// to be a delay in releasing the binary when the process exits.
// Leaving temporary files behind can be annoying to users, so we try again.
if err == nil || runtime.GOOS != "windows" {
break
}
time.Sleep(1 * time.Millisecond)
}
if err != nil {
fmt.Fprintf(os.Stderr, "could not remove %v: %v\n", path, err)
}
}
// GoBuild builds non-test files in 'pkgs' with the specified 'buildflags'
// and writes the output at 'debugname'.
func GoBuild(debugname string, pkgs []string, buildflags string) error {
args := goBuildArgs(debugname, pkgs, buildflags, false)
return gocommandRun("build", args...)
}
// GoBuildCombinedOutput builds non-test files in 'pkgs' with the specified 'buildflags'
// and writes the output at 'debugname'.
func GoBuildCombinedOutput(debugname string, pkgs []string, buildflags interface{}) (string, []byte, error) {
args, err := goBuildArgs2(debugname, pkgs, buildflags, false)
if err != nil {
return "", nil, err
}
return gocommandCombinedOutput("build", args...)
}
// GoTestBuild builds test files 'pkgs' with the specified 'buildflags'
// and writes the output at 'debugname'.
func GoTestBuild(debugname string, pkgs []string, buildflags string) error {
args := goBuildArgs(debugname, pkgs, buildflags, true)
return gocommandRun("test", args...)
}
// GoTestBuildCombinedOutput builds test files 'pkgs' with the specified 'buildflags'
// and writes the output at 'debugname'.
func GoTestBuildCombinedOutput(debugname string, pkgs []string, buildflags interface{}) (string, []byte, error) {
args, err := goBuildArgs2(debugname, pkgs, buildflags, true)
if err != nil {
return "", nil, err
}
return gocommandCombinedOutput("test", args...)
}
func goBuildArgs(debugname string, pkgs []string, buildflags string, isTest bool) []string {
var args []string
bfv := config.SplitQuotedFields(buildflags, '\'')
if len(bfv) >= 2 && bfv[0] == "-C" {
args = append(args, bfv[:2]...)
bfv = bfv[2:]
} else if len(bfv) >= 1 && strings.HasPrefix(bfv[0], "-C=") {
args = append(args, bfv[0])
bfv = bfv[1:]
}
args = append(args, "-o", debugname)
if isTest {
args = append([]string{"-c"}, args...)
}
args = append(args, "-gcflags", "all=-N -l")
if buildflags != "" {
args = append(args, bfv...)
}
args = append(args, pkgs...)
return args
}
// goBuildArgs2 is like goBuildArgs, but takes either string or []string.
func goBuildArgs2(debugname string, pkgs []string, buildflags interface{}, isTest bool) ([]string, error) {
var args []string
switch buildflags := buildflags.(type) {
case string:
return goBuildArgs(debugname, pkgs, buildflags, isTest), nil
case nil:
case []string:
args = append(args, buildflags...)
default:
return nil, fmt.Errorf("invalid buildflags type %T", buildflags)
}
args = append(args, "-o", debugname)
if isTest {
args = append([]string{"-c"}, args...)
}
args = append(args, "-gcflags", "all=-N -l")
return append(args, pkgs...), nil
}
func gocommandRun(command string, args ...string) error {
_, goBuild := gocommandExecCmd(command, args...)
goBuild.Stderr = os.Stdout
goBuild.Stdout = os.Stderr
return goBuild.Run()
}
func gocommandCombinedOutput(command string, args ...string) (string, []byte, error) {
buildCmd, goBuild := gocommandExecCmd(command, args...)
out, err := goBuild.CombinedOutput()
return buildCmd, out, err
}
func gocommandExecCmd(command string, args ...string) (string, *exec.Cmd) {
allargs := []string{command}
allargs = append(allargs, args...)
goBuild := exec.Command("go", allargs...)
return strings.Join(append([]string{"go"}, allargs...), " "), goBuild
}
|