diff --git a/src/cmd/go/build_test.go b/src/cmd/go/build_test.go deleted file mode 100644 index 79bbd545915..00000000000 --- a/src/cmd/go/build_test.go +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright 2016 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package main - -import ( - "os" - "reflect" - "testing" -) - -func TestRemoveDevNull(t *testing.T) { - fi, err := os.Lstat(os.DevNull) - if err != nil { - t.Skip(err) - } - if fi.Mode().IsRegular() { - t.Errorf("Lstat(%s).Mode().IsRegular() = true; expected false", os.DevNull) - } - mayberemovefile(os.DevNull) - _, err = os.Lstat(os.DevNull) - if err != nil { - t.Errorf("mayberemovefile(%s) did remove it; oops", os.DevNull) - } -} - -func TestSplitPkgConfigOutput(t *testing.T) { - for _, test := range []struct { - in []byte - want []string - }{ - {[]byte(`-r:foo -L/usr/white\ space/lib -lfoo\ bar -lbar\ baz`), []string{"-r:foo", "-L/usr/white space/lib", "-lfoo bar", "-lbar baz"}}, - {[]byte(`-lextra\ fun\ arg\\`), []string{`-lextra fun arg\`}}, - {[]byte(`broken flag\`), []string{"broken", "flag"}}, - {[]byte("\textra whitespace\r\n"), []string{"extra", "whitespace"}}, - {[]byte(" \r\n "), nil}, - } { - got := splitPkgConfigOutput(test.in) - if !reflect.DeepEqual(got, test.want) { - t.Errorf("splitPkgConfigOutput(%v) = %v; want %v", test.in, got, test.want) - } - } -} diff --git a/src/cmd/go/clean.go b/src/cmd/go/clean.go index ba62bd4d2e4..10777be57cb 100644 --- a/src/cmd/go/clean.go +++ b/src/cmd/go/clean.go @@ -5,14 +5,16 @@ package main import ( - "cmd/go/internal/base" - "cmd/go/internal/cfg" - "cmd/go/internal/load" "fmt" "io/ioutil" "os" "path/filepath" "strings" + + "cmd/go/internal/base" + "cmd/go/internal/cfg" + "cmd/go/internal/load" + "cmd/go/internal/work" ) var cmdClean = &base.Command{ @@ -74,7 +76,7 @@ func init() { // mentioned explicitly in the docs but they // are part of the build flags. - addBuildFlags(cmdClean) + work.AddBuildFlags(cmdClean) } func runClean(cmd *base.Command, args []string) { @@ -124,8 +126,8 @@ func clean(p *load.Package) { return } - var b builder - b.print = fmt.Print + var b work.Builder + b.Print = fmt.Print packageFile := map[string]bool{} if p.Name != "main" { @@ -176,7 +178,7 @@ func clean(p *load.Package) { } if cfg.BuildN || cfg.BuildX { - b.showcmd(p.Dir, "rm -f %s", strings.Join(allRemove, " ")) + b.Showcmd(p.Dir, "rm -f %s", strings.Join(allRemove, " ")) } toRemove := map[string]bool{} @@ -189,7 +191,7 @@ func clean(p *load.Package) { // TODO: Remove once Makefiles are forgotten. if cleanDir[name] { if cfg.BuildN || cfg.BuildX { - b.showcmd(p.Dir, "rm -r %s", name) + b.Showcmd(p.Dir, "rm -r %s", name) if cfg.BuildN { continue } @@ -212,7 +214,7 @@ func clean(p *load.Package) { if cleanI && p.Internal.Target != "" { if cfg.BuildN || cfg.BuildX { - b.showcmd("", "rm -f %s", p.Internal.Target) + b.Showcmd("", "rm -f %s", p.Internal.Target) } if !cfg.BuildN { removeFile(p.Internal.Target) diff --git a/src/cmd/go/env.go b/src/cmd/go/env.go index 1498ba5361f..b2bd091d859 100644 --- a/src/cmd/go/env.go +++ b/src/cmd/go/env.go @@ -5,13 +5,15 @@ package main import ( - "cmd/go/internal/base" - "cmd/go/internal/cfg" - "cmd/go/internal/load" "fmt" "os" "runtime" "strings" + + "cmd/go/internal/base" + "cmd/go/internal/cfg" + "cmd/go/internal/load" + "cmd/go/internal/work" ) var cmdEnv = &base.Command{ @@ -29,8 +31,8 @@ each named variable on its own line. } func mkEnv() []cfg.EnvVar { - var b builder - b.init() + var b work.Builder + b.Init() env := []cfg.EnvVar{ {"GOARCH", cfg.Goarch}, @@ -48,10 +50,10 @@ func mkEnv() []cfg.EnvVar { {"TERM", "dumb"}, } - if gccgoBin != "" { - env = append(env, cfg.EnvVar{"GCCGO", gccgoBin}) + if work.GccgoBin != "" { + env = append(env, cfg.EnvVar{"GCCGO", work.GccgoBin}) } else { - env = append(env, cfg.EnvVar{"GCCGO", gccgoName}) + env = append(env, cfg.EnvVar{"GCCGO", work.GccgoName}) } switch cfg.Goarch { @@ -61,10 +63,10 @@ func mkEnv() []cfg.EnvVar { env = append(env, cfg.EnvVar{"GO386", os.Getenv("GO386")}) } - cmd := b.gccCmd(".") + cmd := b.GccCmd(".") env = append(env, cfg.EnvVar{"CC", cmd[0]}) env = append(env, cfg.EnvVar{"GOGCCFLAGS", strings.Join(cmd[3:], " ")}) - cmd = b.gxxCmd(".") + cmd = b.GxxCmd(".") env = append(env, cfg.EnvVar{"CXX", cmd[0]}) if cfg.BuildContext.CgoEnabled { @@ -87,11 +89,11 @@ func findEnv(env []cfg.EnvVar, name string) string { // extraEnvVars returns environment variables that should not leak into child processes. func extraEnvVars() []cfg.EnvVar { - var b builder - b.init() - cppflags, cflags, cxxflags, fflags, ldflags := b.cflags(&load.Package{}) + var b work.Builder + b.Init() + cppflags, cflags, cxxflags, fflags, ldflags := b.CFlags(&load.Package{}) return []cfg.EnvVar{ - {"PKG_CONFIG", b.pkgconfigCmd()}, + {"PKG_CONFIG", b.PkgconfigCmd()}, {"CGO_CFLAGS", strings.Join(cflags, " ")}, {"CGO_CPPFLAGS", strings.Join(cppflags, " ")}, {"CGO_CXXFLAGS", strings.Join(cxxflags, " ")}, diff --git a/src/cmd/go/generate.go b/src/cmd/go/generate.go index 63f1f6d19b0..60d4f01e903 100644 --- a/src/cmd/go/generate.go +++ b/src/cmd/go/generate.go @@ -10,6 +10,7 @@ import ( "cmd/go/internal/base" "cmd/go/internal/cfg" "cmd/go/internal/load" + "cmd/go/internal/work" "fmt" "io" "log" @@ -134,7 +135,7 @@ var ( ) func init() { - addBuildFlags(cmdGenerate) + work.AddBuildFlags(cmdGenerate) cmdGenerate.Flag.StringVar(&generateRunFlag, "run", "", "") } diff --git a/src/cmd/go/get.go b/src/cmd/go/get.go index 23fae8d53f2..4e491b2f363 100644 --- a/src/cmd/go/get.go +++ b/src/cmd/go/get.go @@ -9,6 +9,7 @@ import ( "cmd/go/internal/cfg" "cmd/go/internal/load" "cmd/go/internal/str" + "cmd/go/internal/work" "fmt" "go/build" "os" @@ -83,7 +84,7 @@ var getFix = cmdGet.Flag.Bool("fix", false, "") var getInsecure = cmdGet.Flag.Bool("insecure", false, "") func init() { - addBuildFlags(cmdGet) + work.AddBuildFlags(cmdGet) cmdGet.Run = runGet // break init loop } @@ -157,7 +158,7 @@ func runGet(cmd *base.Command, args []string) { return } - installPackages(args, true) + work.InstallPackages(args, true) } // downloadPaths prepares the list of paths to pass to download. diff --git a/src/cmd/go/internal/base/env.go b/src/cmd/go/internal/base/env.go new file mode 100644 index 00000000000..fb5956dfe34 --- /dev/null +++ b/src/cmd/go/internal/base/env.go @@ -0,0 +1,37 @@ +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package base + +import "strings" + +// envForDir returns a copy of the environment +// suitable for running in the given directory. +// The environment is the current process's environment +// but with an updated $PWD, so that an os.Getwd in the +// child will be faster. +func EnvForDir(dir string, base []string) []string { + // Internally we only use rooted paths, so dir is rooted. + // Even if dir is not rooted, no harm done. + return MergeEnvLists([]string{"PWD=" + dir}, base) +} + +// MergeEnvLists merges the two environment lists such that +// variables with the same name in "in" replace those in "out". +// This always returns a newly allocated slice. +func MergeEnvLists(in, out []string) []string { + out = append([]string(nil), out...) +NextVar: + for _, inkv := range in { + k := strings.SplitAfterN(inkv, "=", 2)[0] + for i, outkv := range out { + if strings.HasPrefix(outkv, k) { + out[i] = inkv + continue NextVar + } + } + out = append(out, inkv) + } + return out +} diff --git a/src/cmd/go/internal/base/flag.go b/src/cmd/go/internal/base/flag.go new file mode 100644 index 00000000000..84ea02ad2b9 --- /dev/null +++ b/src/cmd/go/internal/base/flag.go @@ -0,0 +1,33 @@ +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package base + +import ( + "cmd/go/internal/str" + "flag" +) + +// A StringsFlag is a command-line flag that interprets its argument +// as a space-separated list of possibly-quoted strings. +type StringsFlag []string + +func (v *StringsFlag) Set(s string) error { + var err error + *v, err = str.SplitQuotedFields(s) + if *v == nil { + *v = []string{} + } + return err +} + +func (v *StringsFlag) String() string { + return "" +} + +// AddBuildFlagsNX adds the -n and -x build flags to the flag set. +func AddBuildFlagsNX(flags *flag.FlagSet) { + flags.BoolVar(&BuildN, "n", false, "") + flags.BoolVar(&BuildX, "x", false, "") +} diff --git a/src/cmd/go/internal/base/path.go b/src/cmd/go/internal/base/path.go index 1e7f6222a52..f7e985aa596 100644 --- a/src/cmd/go/internal/base/path.go +++ b/src/cmd/go/internal/base/path.go @@ -7,6 +7,7 @@ package base import ( "os" "path/filepath" + "strings" ) var Cwd, _ = os.Getwd() @@ -34,3 +35,10 @@ func RelPaths(paths []string) []string { } return out } + +// IsTestFile reports whether the source file is a set of tests and should therefore +// be excluded from coverage analysis. +func IsTestFile(file string) bool { + // We don't cover tests, only the code they test. + return strings.HasSuffix(file, "_test.go") +} diff --git a/src/cmd/go/internal/str/str.go b/src/cmd/go/internal/str/str.go index d3583b48e44..5d06bbeb259 100644 --- a/src/cmd/go/internal/str/str.go +++ b/src/cmd/go/internal/str/str.go @@ -95,3 +95,47 @@ func Contains(x []string, s string) bool { } return false } + +func isSpaceByte(c byte) bool { + return c == ' ' || c == '\t' || c == '\n' || c == '\r' +} + +// SplitQuotedFields splits s into a list of fields, +// allowing single or double quotes around elements. +// There is no unescaping or other processing within +// quoted fields. +func SplitQuotedFields(s string) ([]string, error) { + // Split fields allowing '' or "" around elements. + // Quotes further inside the string do not count. + var f []string + for len(s) > 0 { + for len(s) > 0 && isSpaceByte(s[0]) { + s = s[1:] + } + if len(s) == 0 { + break + } + // Accepted quoted string. No unescaping inside. + if s[0] == '"' || s[0] == '\'' { + quote := s[0] + s = s[1:] + i := 0 + for i < len(s) && s[i] != quote { + i++ + } + if i >= len(s) { + return nil, fmt.Errorf("unterminated %c string", quote) + } + f = append(f, s[:i]) + s = s[i+1:] + continue + } + i := 0 + for i < len(s) && !isSpaceByte(s[i]) { + i++ + } + f = append(f, s[:i]) + s = s[i:] + } + return f, nil +} diff --git a/src/cmd/go/build.go b/src/cmd/go/internal/work/build.go similarity index 81% rename from src/cmd/go/build.go rename to src/cmd/go/internal/work/build.go index d8f400113ef..830015e9474 100644 --- a/src/cmd/go/build.go +++ b/src/cmd/go/internal/work/build.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -package main +package work import ( "bufio" @@ -34,7 +34,7 @@ import ( "cmd/go/internal/str" ) -var cmdBuild = &base.Command{ +var CmdBuild = &base.Command{ UsageLine: "build [-o output] [-i] [build flags] [packages]", Short: "compile packages and dependencies", Long: ` @@ -145,14 +145,14 @@ See also: go install, go get, go clean. func init() { // break init cycle - cmdBuild.Run = runBuild - cmdInstall.Run = runInstall + CmdBuild.Run = runBuild + CmdInstall.Run = runInstall - cmdBuild.Flag.BoolVar(&cfg.BuildI, "i", false, "") - cmdBuild.Flag.StringVar(&cfg.BuildO, "o", "", "output file") + CmdBuild.Flag.BoolVar(&cfg.BuildI, "i", false, "") + CmdBuild.Flag.StringVar(&cfg.BuildO, "o", "", "output file") - addBuildFlags(cmdBuild) - addBuildFlags(cmdInstall) + AddBuildFlags(CmdBuild) + AddBuildFlags(CmdInstall) } // Note that flags consulted by other parts of the code @@ -162,26 +162,26 @@ var buildAsmflags []string // -asmflags flag var buildGcflags []string // -gcflags flag var buildGccgoflags []string // -gccgoflags flag -var buildToolchain toolchain = noToolchain{} +var BuildToolchain toolchain = noToolchain{} var ldBuildmode string // buildCompiler implements flag.Var. // It implements Set by updating both -// buildToolchain and buildContext.Compiler. +// BuildToolchain and buildContext.Compiler. type buildCompiler struct{} func (c buildCompiler) Set(value string) error { switch value { case "gc": - buildToolchain = gcToolchain{} + BuildToolchain = gcToolchain{} case "gccgo": - buildToolchain = gccgoToolchain{} + BuildToolchain = gccgoToolchain{} default: return fmt.Errorf("unknown compiler %q", value) } cfg.BuildToolchainName = value - cfg.BuildToolchainCompiler = buildToolchain.compiler() - cfg.BuildToolchainLinker = buildToolchain.linker() + cfg.BuildToolchainCompiler = BuildToolchain.compiler() + cfg.BuildToolchainLinker = BuildToolchain.linker() cfg.BuildContext.Compiler = value return nil } @@ -199,33 +199,29 @@ func init() { // addBuildFlags adds the flags common to the build, clean, get, // install, list, run, and test commands. -func addBuildFlags(cmd *base.Command) { +func AddBuildFlags(cmd *base.Command) { cmd.Flag.BoolVar(&cfg.BuildA, "a", false, "") cmd.Flag.BoolVar(&cfg.BuildN, "n", false, "") cmd.Flag.IntVar(&cfg.BuildP, "p", cfg.BuildP, "") cmd.Flag.BoolVar(&cfg.BuildV, "v", false, "") cmd.Flag.BoolVar(&cfg.BuildX, "x", false, "") - cmd.Flag.Var((*stringsFlag)(&buildAsmflags), "asmflags", "") + cmd.Flag.Var((*base.StringsFlag)(&buildAsmflags), "asmflags", "") cmd.Flag.Var(buildCompiler{}, "compiler", "") cmd.Flag.StringVar(&cfg.BuildBuildmode, "buildmode", "default", "") - cmd.Flag.Var((*stringsFlag)(&buildGcflags), "gcflags", "") - cmd.Flag.Var((*stringsFlag)(&buildGccgoflags), "gccgoflags", "") + cmd.Flag.Var((*base.StringsFlag)(&buildGcflags), "gcflags", "") + cmd.Flag.Var((*base.StringsFlag)(&buildGccgoflags), "gccgoflags", "") cmd.Flag.StringVar(&cfg.BuildContext.InstallSuffix, "installsuffix", "", "") - cmd.Flag.Var((*stringsFlag)(&cfg.BuildLdflags), "ldflags", "") + cmd.Flag.Var((*base.StringsFlag)(&cfg.BuildLdflags), "ldflags", "") cmd.Flag.BoolVar(&cfg.BuildLinkshared, "linkshared", false, "") cmd.Flag.StringVar(&cfg.BuildPkgdir, "pkgdir", "", "") cmd.Flag.BoolVar(&cfg.BuildRace, "race", false, "") cmd.Flag.BoolVar(&cfg.BuildMSan, "msan", false, "") - cmd.Flag.Var((*stringsFlag)(&cfg.BuildContext.BuildTags), "tags", "") - cmd.Flag.Var((*stringsFlag)(&cfg.BuildToolexec), "toolexec", "") + cmd.Flag.Var((*base.StringsFlag)(&cfg.BuildContext.BuildTags), "tags", "") + cmd.Flag.Var((*base.StringsFlag)(&cfg.BuildToolexec), "toolexec", "") cmd.Flag.BoolVar(&cfg.BuildWork, "work", false, "") } -func isSpaceByte(c byte) bool { - return c == ' ' || c == '\t' || c == '\n' || c == '\r' -} - // fileExtSplit expects a filename and returns the name // and ext (without the dot). If the file has no // extension, ext will be empty. @@ -238,57 +234,6 @@ func fileExtSplit(file string) (name, ext string) { return } -type stringsFlag []string - -func (v *stringsFlag) Set(s string) error { - var err error - *v, err = splitQuotedFields(s) - if *v == nil { - *v = []string{} - } - return err -} - -func splitQuotedFields(s string) ([]string, error) { - // Split fields allowing '' or "" around elements. - // Quotes further inside the string do not count. - var f []string - for len(s) > 0 { - for len(s) > 0 && isSpaceByte(s[0]) { - s = s[1:] - } - if len(s) == 0 { - break - } - // Accepted quoted string. No unescaping inside. - if s[0] == '"' || s[0] == '\'' { - quote := s[0] - s = s[1:] - i := 0 - for i < len(s) && s[i] != quote { - i++ - } - if i >= len(s) { - return nil, fmt.Errorf("unterminated %c string", quote) - } - f = append(f, s[:i]) - s = s[i+1:] - continue - } - i := 0 - for i < len(s) && !isSpaceByte(s[i]) { - i++ - } - f = append(f, s[:i]) - s = s[i:] - } - return f, nil -} - -func (v *stringsFlag) String() string { - return "" -} - func pkgsMain(pkgs []*load.Package) (res []*load.Package) { for _, p := range pkgs { if p.Name == "main" { @@ -309,7 +254,7 @@ func pkgsNotMain(pkgs []*load.Package) (res []*load.Package) { var pkgsFilter = func(pkgs []*load.Package) []*load.Package { return pkgs } -func buildModeInit() { +func BuildModeInit() { gccgo := cfg.BuildToolchainName == "gccgo" var codegenArg string platform := cfg.Goos + "/" + cfg.Goarch @@ -446,10 +391,10 @@ func buildModeInit() { } func runBuild(cmd *base.Command, args []string) { - instrumentInit() - buildModeInit() - var b builder - b.init() + InstrumentInit() + BuildModeInit() + var b Builder + b.Init() pkgs := load.PackagesForBuild(args) @@ -478,9 +423,9 @@ func runBuild(cmd *base.Command, args []string) { } } - depMode := modeBuild + depMode := ModeBuild if cfg.BuildI { - depMode = modeInstall + depMode = ModeInstall } if cfg.BuildO != "" { @@ -493,29 +438,29 @@ func runBuild(cmd *base.Command, args []string) { p.Internal.Target = cfg.BuildO p.Stale = true // must build - not up to date p.StaleReason = "build -o flag in use" - a := b.action(modeInstall, depMode, p) - b.do(a) + a := b.Action(ModeInstall, depMode, p) + b.Do(a) return } - var a *action + var a *Action if cfg.BuildBuildmode == "shared" { pkgs := pkgsFilter(load.Packages(args)) if libName, err := libname(args, pkgs); err != nil { base.Fatalf("%s", err.Error()) } else { - a = b.libaction(libName, pkgs, modeBuild, depMode) + a = b.libaction(libName, pkgs, ModeBuild, depMode) } } else { - a = &action{} + a = &Action{} for _, p := range pkgsFilter(load.Packages(args)) { - a.deps = append(a.deps, b.action(modeBuild, depMode, p)) + a.Deps = append(a.Deps, b.Action(ModeBuild, depMode, p)) } } - b.do(a) + b.Do(a) } -var cmdInstall = &base.Command{ +var CmdInstall = &base.Command{ UsageLine: "install [build flags] [packages]", Short: "compile and install packages and dependencies", Long: ` @@ -586,16 +531,16 @@ func libname(args []string, pkgs []*load.Package) (string, error) { } func runInstall(cmd *base.Command, args []string) { - installPackages(args, false) + InstallPackages(args, false) } -func installPackages(args []string, forGet bool) { +func InstallPackages(args []string, forGet bool) { if cfg.GOBIN != "" && !filepath.IsAbs(cfg.GOBIN) { base.Fatalf("cannot install, GOBIN must be an absolute path") } - instrumentInit() - buildModeInit() + InstrumentInit() + BuildModeInit() pkgs := pkgsFilter(load.PackagesForBuild(args)) for _, p := range pkgs { @@ -615,42 +560,42 @@ func installPackages(args []string, forGet bool) { } base.ExitIfErrors() - var b builder - b.init() + var b Builder + b.Init() // Set the behavior for `go get` to not error on packages with test files only. b.testFilesOnlyOK = forGet - var a *action + var a *Action if cfg.BuildBuildmode == "shared" { if libName, err := libname(args, pkgs); err != nil { base.Fatalf("%s", err.Error()) } else { - a = b.libaction(libName, pkgs, modeInstall, modeInstall) + a = b.libaction(libName, pkgs, ModeInstall, ModeInstall) } } else { - a = &action{} - var tools []*action + a = &Action{} + var tools []*Action for _, p := range pkgs { // If p is a tool, delay the installation until the end of the build. // This avoids installing assemblers/compilers that are being executed // by other steps in the build. - // cmd/cgo is handled specially in b.action, so that we can + // cmd/cgo is handled specially in b.Action, so that we can // both build and use it in the same 'go install'. - action := b.action(modeInstall, modeInstall, p) + Action := b.Action(ModeInstall, ModeInstall, p) if load.GoTools[p.ImportPath] == load.ToTool && p.ImportPath != "cmd/cgo" { - a.deps = append(a.deps, action.deps...) - action.deps = append(action.deps, a) - tools = append(tools, action) + a.Deps = append(a.Deps, Action.Deps...) + Action.Deps = append(Action.Deps, a) + tools = append(tools, Action) continue } - a.deps = append(a.deps, action) + a.Deps = append(a.Deps, Action) } if len(tools) > 0 { - a = &action{ - deps: tools, + a = &Action{ + Deps: tools, } } } - b.do(a) + b.Do(a) base.ExitIfErrors() // Success. If this command is 'go install' with no arguments @@ -691,15 +636,15 @@ func init() { cfg.Gopath = filepath.SplitList(cfg.BuildContext.GOPATH) } -// A builder holds global state about a build. +// A Builder holds global state about a build. // It does not hold per-package state, because we // build packages in parallel, and the builder is shared. -type builder struct { - work string // the temporary work directory (ends in filepath.Separator) - actionCache map[cacheKey]*action // a cache of already-constructed actions +type Builder struct { + WorkDir string // the temporary work directory (ends in filepath.Separator) + actionCache map[cacheKey]*Action // a cache of already-constructed actions mkdirCache map[string]bool // a cache of created directories flagCache map[string]bool // a cache of supported compiler flags - print func(args ...interface{}) (int, error) + Print func(args ...interface{}) (int, error) testFilesOnlyOK bool // do not error if the packages only have test files @@ -711,67 +656,70 @@ type builder struct { ready actionQueue } -// An action represents a single action in the action graph. -type action struct { - p *load.Package // the package this action works on - deps []*action // actions that must happen before this one - triggers []*action // inverse of deps - cgo *action // action for cgo binary if needed - args []string // additional args for runProgram - testOutput *bytes.Buffer // test output buffer +// NOTE: Much of Action would not need to be exported if not for test. +// Maybe test functionality should move into this package too? - f func(*builder, *action) error // the action itself (nil = no-op) - ignoreFail bool // whether to run f even if dependencies fail +// An Action represents a single action in the action graph. +type Action struct { + Package *load.Package // the package this action works on + Deps []*Action // actions that must happen before this one + Func func(*Builder, *Action) error // the action itself (nil = no-op) + IgnoreFail bool // whether to run f even if dependencies fail + TestOutput *bytes.Buffer // test output buffer + Args []string // additional args for runProgram + + triggers []*Action // inverse of deps + cgo *Action // action for cgo binary if needed // Generated files, directories. - link bool // target is executable, not just package - pkgdir string // the -I or -L argument to use when importing this package - objdir string // directory for intermediate objects - objpkg string // the intermediate package .a file created during the action - target string // goal of the action: the created package or executable + Link bool // target is executable, not just package + Pkgdir string // the -I or -L argument to use when importing this package + Objdir string // directory for intermediate objects + Objpkg string // the intermediate package .a file created during the action + Target string // goal of the action: the created package or executable // Execution state. pending int // number of deps yet to complete priority int // relative execution priority - failed bool // whether the action failed + Failed bool // whether the action failed } // cacheKey is the key for the action cache. type cacheKey struct { - mode buildMode + mode BuildMode p *load.Package shlib string } -// buildMode specifies the build mode: +// BuildMode specifies the build mode: // are we just building things or also installing the results? -type buildMode int +type BuildMode int const ( - modeBuild buildMode = iota - modeInstall + ModeBuild BuildMode = iota + ModeInstall ) -func (b *builder) init() { +func (b *Builder) Init() { var err error - b.print = func(a ...interface{}) (int, error) { + b.Print = func(a ...interface{}) (int, error) { return fmt.Fprint(os.Stderr, a...) } - b.actionCache = make(map[cacheKey]*action) + b.actionCache = make(map[cacheKey]*Action) b.mkdirCache = make(map[string]bool) if cfg.BuildN { - b.work = "$WORK" + b.WorkDir = "$WORK" } else { - b.work, err = ioutil.TempDir("", "go-build") + b.WorkDir, err = ioutil.TempDir("", "go-build") if err != nil { base.Fatalf("%s", err) } if cfg.BuildX || cfg.BuildWork { - fmt.Fprintf(os.Stderr, "WORK=%s\n", b.work) + fmt.Fprintf(os.Stderr, "WORK=%s\n", b.WorkDir) } if !cfg.BuildWork { - workdir := b.work + workdir := b.WorkDir base.AtExit(func() { os.RemoveAll(workdir) }) } } @@ -810,11 +758,11 @@ func readpkglist(shlibpath string) (pkgs []*load.Package) { return } -// action returns the action for applying the given operation (mode) to the package. +// Action returns the action for applying the given operation (mode) to the package. // depMode is the action to use when building dependencies. // action never looks for p in a shared library, but may find p's dependencies in a // shared library if buildLinkshared is true. -func (b *builder) action(mode buildMode, depMode buildMode, p *load.Package) *action { +func (b *Builder) Action(mode BuildMode, depMode BuildMode, p *load.Package) *Action { return b.action1(mode, depMode, p, false, "") } @@ -822,7 +770,7 @@ func (b *builder) action(mode buildMode, depMode buildMode, p *load.Package) *ac // depMode is the action to use when building dependencies. // action1 will look for p in a shared library if lookshared is true. // forShlib is the shared library that p will become part of, if any. -func (b *builder) action1(mode buildMode, depMode buildMode, p *load.Package, lookshared bool, forShlib string) *action { +func (b *Builder) action1(mode BuildMode, depMode BuildMode, p *load.Package, lookshared bool, forShlib string) *Action { shlib := "" if lookshared { shlib = p.Shlib @@ -834,22 +782,22 @@ func (b *builder) action1(mode buildMode, depMode buildMode, p *load.Package, lo return a } if shlib != "" { - key2 := cacheKey{modeInstall, nil, shlib} + key2 := cacheKey{ModeInstall, nil, shlib} a = b.actionCache[key2] if a != nil { b.actionCache[key] = a return a } pkgs := readpkglist(shlib) - a = b.libaction(filepath.Base(shlib), pkgs, modeInstall, depMode) + a = b.libaction(filepath.Base(shlib), pkgs, ModeInstall, depMode) b.actionCache[key2] = a b.actionCache[key] = a return a } - a = &action{p: p, pkgdir: p.Internal.Build.PkgRoot} + a = &Action{Package: p, Pkgdir: p.Internal.Build.PkgRoot} if p.Internal.Pkgdir != "" { // overrides p.t - a.pkgdir = p.Internal.Pkgdir + a.Pkgdir = p.Internal.Pkgdir } b.actionCache[key] = a @@ -858,18 +806,18 @@ func (b *builder) action1(mode buildMode, depMode buildMode, p *load.Package, lo // p is part of a shared library. if p1.Shlib != "" && p1.Shlib != forShlib { // p1 is explicitly part of a different shared library. - // Put the action for that shared library into a.deps. - a.deps = append(a.deps, b.action1(depMode, depMode, p1, true, p1.Shlib)) + // Put the action for that shared library into a.Deps. + a.Deps = append(a.Deps, b.action1(depMode, depMode, p1, true, p1.Shlib)) } else { // p1 is (implicitly or not) part of this shared library. - // Put the action for p1 into a.deps. - a.deps = append(a.deps, b.action1(depMode, depMode, p1, false, forShlib)) + // Put the action for p1 into a.Deps. + a.Deps = append(a.Deps, b.action1(depMode, depMode, p1, false, forShlib)) } } else { // p is not part of a shared library. // If p1 is in a shared library, put the action for that into - // a.deps, otherwise put the action for p1 into a.deps. - a.deps = append(a.deps, b.action1(depMode, depMode, p1, cfg.BuildLinkshared, p1.Shlib)) + // a.Deps, otherwise put the action for p1 into a.Deps. + a.Deps = append(a.Deps, b.action1(depMode, depMode, p1, cfg.BuildLinkshared, p1.Shlib)) } } @@ -885,8 +833,8 @@ func (b *builder) action1(mode buildMode, depMode buildMode, p *load.Package, lo if p1.Error != nil { base.Fatalf("load cmd/cgo: %v", p1.Error) } - a.cgo = b.action(depMode, depMode, p1) - a.deps = append(a.deps, a.cgo) + a.cgo = b.Action(depMode, depMode, p1) + a.Deps = append(a.Deps, a.cgo) } } @@ -899,7 +847,7 @@ func (b *builder) action1(mode buildMode, depMode buildMode, p *load.Package, lo // gccgo standard library is "fake" too. if cfg.BuildToolchainName == "gccgo" { // the target name is needed for cgo. - a.target = p.Internal.Target + a.Target = p.Internal.Target return a } } @@ -907,31 +855,31 @@ func (b *builder) action1(mode buildMode, depMode buildMode, p *load.Package, lo if !p.Stale && p.Internal.Target != "" { // p.Stale==false implies that p.Internal.Target is up-to-date. // Record target name for use by actions depending on this one. - a.target = p.Internal.Target + a.Target = p.Internal.Target return a } if p.Internal.Local && p.Internal.Target == "" { // Imported via local path. No permanent target. - mode = modeBuild + mode = ModeBuild } work := p.Internal.Pkgdir if work == "" { - work = b.work + work = b.WorkDir } - a.objdir = filepath.Join(work, a.p.ImportPath, "_obj") + string(filepath.Separator) - a.objpkg = buildToolchain.pkgpath(work, a.p) - a.link = p.Name == "main" + a.Objdir = filepath.Join(work, a.Package.ImportPath, "_obj") + string(filepath.Separator) + a.Objpkg = BuildToolchain.Pkgpath(work, a.Package) + a.Link = p.Name == "main" switch mode { - case modeInstall: - a.f = (*builder).install - a.deps = []*action{b.action1(modeBuild, depMode, p, lookshared, forShlib)} - a.target = a.p.Internal.Target + case ModeInstall: + a.Func = BuildInstallFunc + a.Deps = []*Action{b.action1(ModeBuild, depMode, p, lookshared, forShlib)} + a.Target = a.Package.Internal.Target // Install header for cgo in c-archive and c-shared modes. if p.UsesCgo() && (cfg.BuildBuildmode == "c-archive" || cfg.BuildBuildmode == "c-shared") { - hdrTarget := a.target[:len(a.target)-len(filepath.Ext(a.target))] + ".h" + hdrTarget := a.Target[:len(a.Target)-len(filepath.Ext(a.Target))] + ".h" if cfg.BuildContext.Compiler == "gccgo" { // For the header file, remove the "lib" // added by go/build, so we generate pkg.h @@ -940,21 +888,21 @@ func (b *builder) action1(mode buildMode, depMode buildMode, p *load.Package, lo file = strings.TrimPrefix(file, "lib") hdrTarget = filepath.Join(dir, file) } - ah := &action{ - p: a.p, - deps: []*action{a.deps[0]}, - f: (*builder).installHeader, - pkgdir: a.pkgdir, - objdir: a.objdir, - target: hdrTarget, + ah := &Action{ + Package: a.Package, + Deps: []*Action{a.Deps[0]}, + Func: (*Builder).installHeader, + Pkgdir: a.Pkgdir, + Objdir: a.Objdir, + Target: hdrTarget, } - a.deps = append(a.deps, ah) + a.Deps = append(a.Deps, ah) } - case modeBuild: - a.f = (*builder).build - a.target = a.objpkg - if a.link { + case ModeBuild: + a.Func = (*Builder).build + a.Target = a.Objpkg + if a.Link { // An executable file. (This is the name of a temporary file.) // Because we run the temporary file in 'go run' and 'go test', // the name will show up in ps listings. If the caller has specified @@ -973,30 +921,30 @@ func (b *builder) action1(mode buildMode, depMode buildMode, p *load.Package, lo // we'll install it as; otherwise the library is only loadable as "a.out". _, name = filepath.Split(p.Internal.Target) } - a.target = a.objdir + filepath.Join("exe", name) + cfg.ExeSuffix + a.Target = a.Objdir + filepath.Join("exe", name) + cfg.ExeSuffix } } return a } -func (b *builder) libaction(libname string, pkgs []*load.Package, mode, depMode buildMode) *action { - a := &action{} +func (b *Builder) libaction(libname string, pkgs []*load.Package, mode, depMode BuildMode) *Action { + a := &Action{} switch mode { default: base.Fatalf("unrecognized mode %v", mode) - case modeBuild: - a.f = (*builder).linkShared - a.target = filepath.Join(b.work, libname) + case ModeBuild: + a.Func = (*Builder).linkShared + a.Target = filepath.Join(b.WorkDir, libname) for _, p := range pkgs { if p.Internal.Target == "" { continue } - a.deps = append(a.deps, b.action(depMode, depMode, p)) + a.Deps = append(a.Deps, b.Action(depMode, depMode, p)) } - case modeInstall: + case ModeInstall: // Currently build mode shared forces external linking mode, and // external linking mode forces an import of runtime/cgo (and // math on arm). So if it was not passed on the command line and @@ -1060,12 +1008,12 @@ func (b *builder) libaction(libname string, pkgs []*load.Package, mode, depMode base.Fatalf("multiple roots %s & %s", libdir, plibdir) } } - a.target = filepath.Join(libdir, libname) + a.Target = filepath.Join(libdir, libname) // Now we can check whether we need to rebuild it. stale := false var built time.Time - if fi, err := os.Stat(a.target); err == nil { + if fi, err := os.Stat(a.Target); err == nil { built = fi.ModTime() } for _, p := range pkgs { @@ -1077,40 +1025,40 @@ func (b *builder) libaction(libname string, pkgs []*load.Package, mode, depMode if err != nil || lstat.ModTime().After(built) { stale = true } - a.deps = append(a.deps, b.action1(depMode, depMode, p, false, a.target)) + a.Deps = append(a.Deps, b.action1(depMode, depMode, p, false, a.Target)) } if stale { - a.f = (*builder).install - buildAction := b.libaction(libname, pkgs, modeBuild, depMode) - a.deps = []*action{buildAction} + a.Func = BuildInstallFunc + buildAction := b.libaction(libname, pkgs, ModeBuild, depMode) + a.Deps = []*Action{buildAction} for _, p := range pkgs { if p.Internal.Target == "" { continue } - shlibnameaction := &action{} - shlibnameaction.f = (*builder).installShlibname - shlibnameaction.target = p.Internal.Target[:len(p.Internal.Target)-2] + ".shlibname" - a.deps = append(a.deps, shlibnameaction) - shlibnameaction.deps = append(shlibnameaction.deps, buildAction) + shlibnameaction := &Action{} + shlibnameaction.Func = (*Builder).installShlibname + shlibnameaction.Target = p.Internal.Target[:len(p.Internal.Target)-2] + ".shlibname" + a.Deps = append(a.Deps, shlibnameaction) + shlibnameaction.Deps = append(shlibnameaction.Deps, buildAction) } } } return a } -// actionList returns the list of actions in the dag rooted at root +// ActionList returns the list of actions in the dag rooted at root // as visited in a depth-first post-order traversal. -func actionList(root *action) []*action { - seen := map[*action]bool{} - all := []*action{} - var walk func(*action) - walk = func(a *action) { +func ActionList(root *Action) []*Action { + seen := map[*Action]bool{} + all := []*Action{} + var walk func(*Action) + walk = func(a *Action) { if seen[a] { return } seen[a] = true - for _, a1 := range a.deps { + for _, a1 := range a.Deps { walk(a1) } all = append(all, a) @@ -1123,20 +1071,20 @@ func actionList(root *action) []*action { // This is needed because if package p depends on package q that is in libr.so, the // action graph looks like p->libr.so->q and so just scanning through p's // dependencies does not find the import dir for q. -func allArchiveActions(root *action) []*action { - seen := map[*action]bool{} - r := []*action{} - var walk func(*action) - walk = func(a *action) { +func allArchiveActions(root *Action) []*Action { + seen := map[*Action]bool{} + r := []*Action{} + var walk func(*Action) + walk = func(a *Action) { if seen[a] { return } seen[a] = true - if strings.HasSuffix(a.target, ".so") || a == root { - for _, a1 := range a.deps { + if strings.HasSuffix(a.Target, ".so") || a == root { + for _, a1 := range a.Deps { walk(a1) } - } else if strings.HasSuffix(a.target, ".a") { + } else if strings.HasSuffix(a.Target, ".a") { r = append(r, a) } } @@ -1145,8 +1093,8 @@ func allArchiveActions(root *action) []*action { } // do runs the action graph rooted at root. -func (b *builder) do(root *action) { - if _, ok := osArchSupportsCgo[cfg.Goos+"/"+cfg.Goarch]; !ok && cfg.BuildContext.Compiler == "gc" { +func (b *Builder) Do(root *Action) { + if _, ok := cfg.OSArchSupportsCgo[cfg.Goos+"/"+cfg.Goarch]; !ok && cfg.BuildContext.Compiler == "gc" { fmt.Fprintf(os.Stderr, "cmd/go: unsupported GOOS/GOARCH pair %s/%s\n", cfg.Goos, cfg.Goarch) os.Exit(2) } @@ -1162,7 +1110,7 @@ func (b *builder) do(root *action) { // ensure that, all else being equal, the execution prefers // to do what it would have done first in a simple depth-first // dependency order traversal. - all := actionList(root) + all := ActionList(root) for i, a := range all { a.priority = i } @@ -1171,10 +1119,10 @@ func (b *builder) do(root *action) { // Initialize per-action execution state. for _, a := range all { - for _, a1 := range a.deps { + for _, a1 := range a.Deps { a1.triggers = append(a1.triggers, a) } - a.pending = len(a.deps) + a.pending = len(a.Deps) if a.pending == 0 { b.ready.push(a) b.readySema <- true @@ -1183,10 +1131,10 @@ func (b *builder) do(root *action) { // Handle runs a single action and takes care of triggering // any actions that are runnable as a result. - handle := func(a *action) { + handle := func(a *Action) { var err error - if a.f != nil && (!a.failed || a.ignoreFail) { - err = a.f(b, a) + if a.Func != nil && (!a.Failed || a.IgnoreFail) { + err = a.Func(b, a) } // The actions run in parallel but all the updates to the @@ -1197,17 +1145,17 @@ func (b *builder) do(root *action) { if err != nil { if err == errPrintedOutput { base.SetExitStatus(2) - } else if _, ok := err.(*build.NoGoError); ok && len(a.p.TestGoFiles) > 0 && b.testFilesOnlyOK { + } else if _, ok := err.(*build.NoGoError); ok && len(a.Package.TestGoFiles) > 0 && b.testFilesOnlyOK { // Ignore the "no buildable Go source files" error for a package with only test files. } else { base.Errorf("%s", err) } - a.failed = true + a.Failed = true } for _, a0 := range a.triggers { - if a.failed { - a0.failed = true + if a.Failed { + a0.Failed = true } if a0.pending--; a0.pending == 0 { b.ready.push(a0) @@ -1258,35 +1206,35 @@ func (b *builder) do(root *action) { } // build is the action for building a single package or command. -func (b *builder) build(a *action) (err error) { +func (b *Builder) build(a *Action) (err error) { // Return an error for binary-only package. // We only reach this if isStale believes the binary form is // either not present or not usable. - if a.p.BinaryOnly { - return fmt.Errorf("missing or invalid package binary for binary-only package %s", a.p.ImportPath) + if a.Package.BinaryOnly { + return fmt.Errorf("missing or invalid package binary for binary-only package %s", a.Package.ImportPath) } // Return an error if the package has CXX files but it's not using // cgo nor SWIG, since the CXX files can only be processed by cgo // and SWIG. - if len(a.p.CXXFiles) > 0 && !a.p.UsesCgo() && !a.p.UsesSwig() { + if len(a.Package.CXXFiles) > 0 && !a.Package.UsesCgo() && !a.Package.UsesSwig() { return fmt.Errorf("can't build package %s because it contains C++ files (%s) but it's not using cgo nor SWIG", - a.p.ImportPath, strings.Join(a.p.CXXFiles, ",")) + a.Package.ImportPath, strings.Join(a.Package.CXXFiles, ",")) } // Same as above for Objective-C files - if len(a.p.MFiles) > 0 && !a.p.UsesCgo() && !a.p.UsesSwig() { + if len(a.Package.MFiles) > 0 && !a.Package.UsesCgo() && !a.Package.UsesSwig() { return fmt.Errorf("can't build package %s because it contains Objective-C files (%s) but it's not using cgo nor SWIG", - a.p.ImportPath, strings.Join(a.p.MFiles, ",")) + a.Package.ImportPath, strings.Join(a.Package.MFiles, ",")) } // Same as above for Fortran files - if len(a.p.FFiles) > 0 && !a.p.UsesCgo() && !a.p.UsesSwig() { + if len(a.Package.FFiles) > 0 && !a.Package.UsesCgo() && !a.Package.UsesSwig() { return fmt.Errorf("can't build package %s because it contains Fortran files (%s) but it's not using cgo nor SWIG", - a.p.ImportPath, strings.Join(a.p.FFiles, ",")) + a.Package.ImportPath, strings.Join(a.Package.FFiles, ",")) } defer func() { - if _, ok := err.(*build.NoGoError); err != nil && err != errPrintedOutput && !(ok && b.testFilesOnlyOK && len(a.p.TestGoFiles) > 0) { - err = fmt.Errorf("go build %s: %v", a.p.ImportPath, err) + if _, ok := err.(*build.NoGoError); err != nil && err != errPrintedOutput && !(ok && b.testFilesOnlyOK && len(a.Package.TestGoFiles) > 0) { + err = fmt.Errorf("go build %s: %v", a.Package.ImportPath, err) } }() if cfg.BuildN { @@ -1295,37 +1243,37 @@ func (b *builder) build(a *action) (err error) { // different sections of the bootstrap script have to // be merged, the banners give patch something // to use to find its context. - b.print("\n#\n# " + a.p.ImportPath + "\n#\n\n") + b.Print("\n#\n# " + a.Package.ImportPath + "\n#\n\n") } if cfg.BuildV { - b.print(a.p.ImportPath + "\n") + b.Print(a.Package.ImportPath + "\n") } // Make build directory. - obj := a.objdir - if err := b.mkdir(obj); err != nil { + obj := a.Objdir + if err := b.Mkdir(obj); err != nil { return err } // make target directory - dir, _ := filepath.Split(a.target) + dir, _ := filepath.Split(a.Target) if dir != "" { - if err := b.mkdir(dir); err != nil { + if err := b.Mkdir(dir); err != nil { return err } } var gofiles, cgofiles, objdirCgofiles, cfiles, sfiles, cxxfiles, objects, cgoObjects, pcCFLAGS, pcLDFLAGS []string - gofiles = append(gofiles, a.p.GoFiles...) - cgofiles = append(cgofiles, a.p.CgoFiles...) - cfiles = append(cfiles, a.p.CFiles...) - sfiles = append(sfiles, a.p.SFiles...) - cxxfiles = append(cxxfiles, a.p.CXXFiles...) + gofiles = append(gofiles, a.Package.GoFiles...) + cgofiles = append(cgofiles, a.Package.CgoFiles...) + cfiles = append(cfiles, a.Package.CFiles...) + sfiles = append(sfiles, a.Package.SFiles...) + cxxfiles = append(cxxfiles, a.Package.CXXFiles...) - if a.p.UsesCgo() || a.p.UsesSwig() { - if pcCFLAGS, pcLDFLAGS, err = b.getPkgConfigFlags(a.p); err != nil { + if a.Package.UsesCgo() || a.Package.UsesSwig() { + if pcCFLAGS, pcLDFLAGS, err = b.getPkgConfigFlags(a.Package); err != nil { return } } @@ -1333,8 +1281,8 @@ func (b *builder) build(a *action) (err error) { // Run SWIG on each .swig and .swigcxx file. // Each run will generate two files, a .go file and a .c or .cxx file. // The .go file will use import "C" and is to be processed by cgo. - if a.p.UsesSwig() { - outGo, outC, outCXX, err := b.swig(a.p, obj, pcCFLAGS) + if a.Package.UsesSwig() { + outGo, outC, outCXX, err := b.swig(a.Package, obj, pcCFLAGS) if err != nil { return err } @@ -1344,7 +1292,7 @@ func (b *builder) build(a *action) (err error) { } // Run cgo. - if a.p.UsesCgo() || a.p.UsesSwig() { + if a.Package.UsesCgo() || a.Package.UsesSwig() { // In a package using cgo, cgo compiles the C, C++ and assembly files with gcc. // There is one exception: runtime/cgo's job is to bridge the // cgo and non-cgo worlds, so it necessarily has files in both. @@ -1352,7 +1300,7 @@ func (b *builder) build(a *action) (err error) { var gccfiles []string gccfiles = append(gccfiles, cfiles...) cfiles = nil - if a.p.Standard && a.p.ImportPath == "runtime/cgo" { + if a.Package.Standard && a.Package.ImportPath == "runtime/cgo" { filter := func(files, nongcc, gcc []string) ([]string, []string) { for _, f := range files { if strings.HasPrefix(f, "gcc_") { @@ -1370,26 +1318,26 @@ func (b *builder) build(a *action) (err error) { } cgoExe := base.Tool("cgo") - if a.cgo != nil && a.cgo.target != "" { - cgoExe = a.cgo.target + if a.cgo != nil && a.cgo.Target != "" { + cgoExe = a.cgo.Target } - outGo, outObj, err := b.cgo(a, cgoExe, obj, pcCFLAGS, pcLDFLAGS, cgofiles, objdirCgofiles, gccfiles, cxxfiles, a.p.MFiles, a.p.FFiles) + outGo, outObj, err := b.cgo(a, cgoExe, obj, pcCFLAGS, pcLDFLAGS, cgofiles, objdirCgofiles, gccfiles, cxxfiles, a.Package.MFiles, a.Package.FFiles) if err != nil { return err } if cfg.BuildToolchainName == "gccgo" { - cgoObjects = append(cgoObjects, filepath.Join(a.objdir, "_cgo_flags")) + cgoObjects = append(cgoObjects, filepath.Join(a.Objdir, "_cgo_flags")) } cgoObjects = append(cgoObjects, outObj...) gofiles = append(gofiles, outGo...) } if len(gofiles) == 0 { - return &build.NoGoError{Dir: a.p.Dir} + return &build.NoGoError{Dir: a.Package.Dir} } // If we're doing coverage, preprocess the .go files and put them in the work directory - if a.p.Internal.CoverMode != "" { + if a.Package.Internal.CoverMode != "" { for i, file := range gofiles { var sourceFile string var coverFile string @@ -1401,12 +1349,12 @@ func (b *builder) build(a *action) (err error) { coverFile = filepath.Join(obj, base) key = strings.TrimSuffix(base, ".cgo1.go") + ".go" } else { - sourceFile = filepath.Join(a.p.Dir, file) + sourceFile = filepath.Join(a.Package.Dir, file) coverFile = filepath.Join(obj, file) key = file } - cover := a.p.Internal.CoverVars[key] - if cover == nil || isTestFile(file) { + cover := a.Package.Internal.CoverVars[key] + if cover == nil || base.IsTestFile(file) { // Not covering this file. continue } @@ -1421,9 +1369,9 @@ func (b *builder) build(a *action) (err error) { inc := b.includeArgs("-I", allArchiveActions(a)) // Compile Go. - ofile, out, err := buildToolchain.gc(b, a.p, a.objpkg, obj, len(sfiles) > 0, inc, gofiles) + ofile, out, err := BuildToolchain.gc(b, a.Package, a.Objpkg, obj, len(sfiles) > 0, inc, gofiles) if len(out) > 0 { - b.showOutput(a.p.Dir, a.p.ImportPath, b.processOutput(out)) + b.showOutput(a.Package.Dir, a.Package.ImportPath, b.processOutput(out)) if err != nil { return errPrintedOutput } @@ -1431,7 +1379,7 @@ func (b *builder) build(a *action) (err error) { if err != nil { return err } - if ofile != a.objpkg { + if ofile != a.Objpkg { objects = append(objects, ofile) } @@ -1441,22 +1389,22 @@ func (b *builder) build(a *action) (err error) { _goos_goarch := "_" + cfg.Goos + "_" + cfg.Goarch _goos := "_" + cfg.Goos _goarch := "_" + cfg.Goarch - for _, file := range a.p.HFiles { + for _, file := range a.Package.HFiles { name, ext := fileExtSplit(file) switch { case strings.HasSuffix(name, _goos_goarch): targ := file[:len(name)-len(_goos_goarch)] + "_GOOS_GOARCH." + ext - if err := b.copyFile(a, obj+targ, filepath.Join(a.p.Dir, file), 0666, true); err != nil { + if err := b.copyFile(a, obj+targ, filepath.Join(a.Package.Dir, file), 0666, true); err != nil { return err } case strings.HasSuffix(name, _goarch): targ := file[:len(name)-len(_goarch)] + "_GOARCH." + ext - if err := b.copyFile(a, obj+targ, filepath.Join(a.p.Dir, file), 0666, true); err != nil { + if err := b.copyFile(a, obj+targ, filepath.Join(a.Package.Dir, file), 0666, true); err != nil { return err } case strings.HasSuffix(name, _goos): targ := file[:len(name)-len(_goos)] + "_GOOS." + ext - if err := b.copyFile(a, obj+targ, filepath.Join(a.p.Dir, file), 0666, true); err != nil { + if err := b.copyFile(a, obj+targ, filepath.Join(a.Package.Dir, file), 0666, true); err != nil { return err } } @@ -1464,7 +1412,7 @@ func (b *builder) build(a *action) (err error) { for _, file := range cfiles { out := file[:len(file)-len(".c")] + ".o" - if err := buildToolchain.cc(b, a.p, obj, obj+out, file); err != nil { + if err := BuildToolchain.cc(b, a.Package, obj, obj+out, file); err != nil { return err } objects = append(objects, out) @@ -1472,7 +1420,7 @@ func (b *builder) build(a *action) (err error) { // Assemble .s files. if len(sfiles) > 0 { - ofiles, err := buildToolchain.asm(b, a.p, obj, sfiles) + ofiles, err := BuildToolchain.asm(b, a.Package, obj, sfiles) if err != nil { return err } @@ -1486,8 +1434,8 @@ func (b *builder) build(a *action) (err error) { objects = append(objects, cgoObjects...) // Add system object files. - for _, syso := range a.p.SysoFiles { - objects = append(objects, filepath.Join(a.p.Dir, syso)) + for _, syso := range a.Package.SysoFiles { + objects = append(objects, filepath.Join(a.Package.Dir, syso)) } // Pack into archive in obj directory. @@ -1496,18 +1444,18 @@ func (b *builder) build(a *action) (err error) { // If the Go compiler wrote an archive and the package is entirely // Go sources, there is no pack to execute at all. if len(objects) > 0 { - if err := buildToolchain.pack(b, a.p, obj, a.objpkg, objects); err != nil { + if err := BuildToolchain.pack(b, a.Package, obj, a.Objpkg, objects); err != nil { return err } } // Link if needed. - if a.link { + if a.Link { // The compiler only cares about direct imports, but the // linker needs the whole dependency tree. - all := actionList(a) + all := ActionList(a) all = all[:len(all)-1] // drop a - if err := buildToolchain.ld(b, a, a.target, all, a.objpkg, objects); err != nil { + if err := BuildToolchain.ld(b, a, a.Target, all, a.Objpkg, objects); err != nil { return err } } @@ -1515,10 +1463,10 @@ func (b *builder) build(a *action) (err error) { return nil } -// pkgconfigCmd returns a pkg-config binary name +// PkgconfigCmd returns a pkg-config binary name // defaultPkgConfig is defined in zdefaultcc.go, written by cmd/dist. -func (b *builder) pkgconfigCmd() string { - return envList("PKG_CONFIG", defaultPkgConfig)[0] +func (b *Builder) PkgconfigCmd() string { + return envList("PKG_CONFIG", cfg.DefaultPkgConfig)[0] } // splitPkgConfigOutput parses the pkg-config output into a slice of @@ -1555,23 +1503,23 @@ func splitPkgConfigOutput(out []byte) []string { } // Calls pkg-config if needed and returns the cflags/ldflags needed to build the package. -func (b *builder) getPkgConfigFlags(p *load.Package) (cflags, ldflags []string, err error) { +func (b *Builder) getPkgConfigFlags(p *load.Package) (cflags, ldflags []string, err error) { if pkgs := p.CgoPkgConfig; len(pkgs) > 0 { var out []byte - out, err = b.runOut(p.Dir, p.ImportPath, nil, b.pkgconfigCmd(), "--cflags", pkgs) + out, err = b.runOut(p.Dir, p.ImportPath, nil, b.PkgconfigCmd(), "--cflags", pkgs) if err != nil { - b.showOutput(p.Dir, b.pkgconfigCmd()+" --cflags "+strings.Join(pkgs, " "), string(out)) - b.print(err.Error() + "\n") + b.showOutput(p.Dir, b.PkgconfigCmd()+" --cflags "+strings.Join(pkgs, " "), string(out)) + b.Print(err.Error() + "\n") err = errPrintedOutput return } if len(out) > 0 { cflags = splitPkgConfigOutput(out) } - out, err = b.runOut(p.Dir, p.ImportPath, nil, b.pkgconfigCmd(), "--libs", pkgs) + out, err = b.runOut(p.Dir, p.ImportPath, nil, b.PkgconfigCmd(), "--libs", pkgs) if err != nil { - b.showOutput(p.Dir, b.pkgconfigCmd()+" --libs "+strings.Join(pkgs, " "), string(out)) - b.print(err.Error() + "\n") + b.showOutput(p.Dir, b.PkgconfigCmd()+" --libs "+strings.Join(pkgs, " "), string(out)) + b.Print(err.Error() + "\n") err = errPrintedOutput return } @@ -1582,34 +1530,34 @@ func (b *builder) getPkgConfigFlags(p *load.Package) (cflags, ldflags []string, return } -func (b *builder) installShlibname(a *action) error { - a1 := a.deps[0] - err := ioutil.WriteFile(a.target, []byte(filepath.Base(a1.target)+"\n"), 0666) +func (b *Builder) installShlibname(a *Action) error { + a1 := a.Deps[0] + err := ioutil.WriteFile(a.Target, []byte(filepath.Base(a1.Target)+"\n"), 0666) if err != nil { return err } if cfg.BuildX { - b.showcmd("", "echo '%s' > %s # internal", filepath.Base(a1.target), a.target) + b.Showcmd("", "echo '%s' > %s # internal", filepath.Base(a1.Target), a.Target) } return nil } -func (b *builder) linkShared(a *action) (err error) { - allactions := actionList(a) +func (b *Builder) linkShared(a *Action) (err error) { + allactions := ActionList(a) allactions = allactions[:len(allactions)-1] - return buildToolchain.ldShared(b, a.deps, a.target, allactions) + return BuildToolchain.ldShared(b, a.Deps, a.Target, allactions) } -// install is the action for installing a single package or executable. -func (b *builder) install(a *action) (err error) { +// BuildInstallFunc is the action for installing a single package or executable. +func BuildInstallFunc(b *Builder, a *Action) (err error) { defer func() { if err != nil && err != errPrintedOutput { - err = fmt.Errorf("go install %s: %v", a.p.ImportPath, err) + err = fmt.Errorf("go install %s: %v", a.Package.ImportPath, err) } }() - a1 := a.deps[0] + a1 := a.Deps[0] perm := os.FileMode(0666) - if a1.link { + if a1.Link { switch cfg.BuildBuildmode { case "c-archive", "c-shared", "plugin": default: @@ -1618,9 +1566,9 @@ func (b *builder) install(a *action) (err error) { } // make target directory - dir, _ := filepath.Split(a.target) + dir, _ := filepath.Split(a.Target) if dir != "" { - if err := b.mkdir(dir); err != nil { + if err := b.Mkdir(dir); err != nil { return err } } @@ -1630,19 +1578,19 @@ func (b *builder) install(a *action) (err error) { // with aggressive buffering, cleaning incrementally like // this keeps the intermediate objects from hitting the disk. if !cfg.BuildWork { - defer os.RemoveAll(a1.objdir) - defer os.Remove(a1.target) + defer os.RemoveAll(a1.Objdir) + defer os.Remove(a1.Target) } - return b.moveOrCopyFile(a, a.target, a1.target, perm, false) + return b.moveOrCopyFile(a, a.Target, a1.Target, perm, false) } // includeArgs returns the -I or -L directory list for access // to the results of the list of actions. -func (b *builder) includeArgs(flag string, all []*action) []string { +func (b *Builder) includeArgs(flag string, all []*Action) []string { inc := []string{} incMap := map[string]bool{ - b.work: true, // handled later + b.WorkDir: true, // handled later cfg.GOROOTpkg: true, "": true, // ignore empty strings } @@ -1651,10 +1599,10 @@ func (b *builder) includeArgs(flag string, all []*action) []string { // This is the $WORK/my/package/_test directory for the // package being built, so there are few of these. for _, a1 := range all { - if a1.p == nil { + if a1.Package == nil { continue } - if dir := a1.pkgdir; dir != a1.p.Internal.Build.PkgRoot && !incMap[dir] { + if dir := a1.Pkgdir; dir != a1.Package.Internal.Build.PkgRoot && !incMap[dir] { incMap[dir] = true inc = append(inc, flag, dir) } @@ -1662,15 +1610,15 @@ func (b *builder) includeArgs(flag string, all []*action) []string { // Also look in $WORK for any non-test packages that have // been built but not installed. - inc = append(inc, flag, b.work) + inc = append(inc, flag, b.WorkDir) // Finally, look in the installed package directories for each action. // First add the package dirs corresponding to GOPATH entries // in the original GOPATH order. need := map[string]*build.Package{} for _, a1 := range all { - if a1.p != nil && a1.pkgdir == a1.p.Internal.Build.PkgRoot { - need[a1.p.Internal.Build.Root] = a1.p.Internal.Build + if a1.Package != nil && a1.Pkgdir == a1.Package.Internal.Build.PkgRoot { + need[a1.Package.Internal.Build.Root] = a1.Package.Internal.Build } } for _, root := range cfg.Gopath { @@ -1682,12 +1630,12 @@ func (b *builder) includeArgs(flag string, all []*action) []string { // Then add anything that's left. for _, a1 := range all { - if a1.p == nil { + if a1.Package == nil { continue } - if dir := a1.pkgdir; dir == a1.p.Internal.Build.PkgRoot && !incMap[dir] { + if dir := a1.Pkgdir; dir == a1.Package.Internal.Build.PkgRoot && !incMap[dir] { incMap[dir] = true - inc = append(inc, flag, a1.p.Internal.Build.PkgTargetRoot) + inc = append(inc, flag, a1.Package.Internal.Build.PkgTargetRoot) } } @@ -1695,9 +1643,9 @@ func (b *builder) includeArgs(flag string, all []*action) []string { } // moveOrCopyFile is like 'mv src dst' or 'cp src dst'. -func (b *builder) moveOrCopyFile(a *action, dst, src string, perm os.FileMode, force bool) error { +func (b *Builder) moveOrCopyFile(a *Action, dst, src string, perm os.FileMode, force bool) error { if cfg.BuildN { - b.showcmd("", "mv %s %s", src, dst) + b.Showcmd("", "mv %s %s", src, dst) return nil } @@ -1724,7 +1672,7 @@ func (b *builder) moveOrCopyFile(a *action, dst, src string, perm os.FileMode, f if err := os.Chmod(src, mode); err == nil { if err := os.Rename(src, dst); err == nil { if cfg.BuildX { - b.showcmd("", "mv %s %s", src, dst) + b.Showcmd("", "mv %s %s", src, dst) } return nil } @@ -1734,9 +1682,9 @@ func (b *builder) moveOrCopyFile(a *action, dst, src string, perm os.FileMode, f } // copyFile is like 'cp src dst'. -func (b *builder) copyFile(a *action, dst, src string, perm os.FileMode, force bool) error { +func (b *Builder) copyFile(a *Action, dst, src string, perm os.FileMode, force bool) error { if cfg.BuildN || cfg.BuildX { - b.showcmd("", "cp %s %s", src, dst) + b.Showcmd("", "cp %s %s", src, dst) if cfg.BuildN { return nil } @@ -1793,31 +1741,31 @@ func (b *builder) copyFile(a *action, dst, src string, perm os.FileMode, force b } // Install the cgo export header file, if there is one. -func (b *builder) installHeader(a *action) error { - src := a.objdir + "_cgo_install.h" +func (b *Builder) installHeader(a *Action) error { + src := a.Objdir + "_cgo_install.h" if _, err := os.Stat(src); os.IsNotExist(err) { // If the file does not exist, there are no exported // functions, and we do not install anything. return nil } - dir, _ := filepath.Split(a.target) + dir, _ := filepath.Split(a.Target) if dir != "" { - if err := b.mkdir(dir); err != nil { + if err := b.Mkdir(dir); err != nil { return err } } - return b.moveOrCopyFile(a, a.target, src, 0666, true) + return b.moveOrCopyFile(a, a.Target, src, 0666, true) } // cover runs, in effect, // go tool cover -mode=b.coverMode -var="varName" -o dst.go src.go -func (b *builder) cover(a *action, dst, src string, perm os.FileMode, varName string) error { - return b.run(a.objdir, "cover "+a.p.ImportPath, nil, +func (b *Builder) cover(a *Action, dst, src string, perm os.FileMode, varName string) error { + return b.run(a.Objdir, "cover "+a.Package.ImportPath, nil, cfg.BuildToolexec, base.Tool("cover"), - "-mode", a.p.Internal.CoverMode, + "-mode", a.Package.Internal.CoverMode, "-var", varName, "-o", dst, src) @@ -1867,14 +1815,14 @@ func mayberemovefile(s string) { // If dir is non-empty and the script is not in dir right now, // fmtcmd inserts "cd dir\n" before the command. // -// fmtcmd replaces the value of b.work with $WORK. +// fmtcmd replaces the value of b.WorkDir with $WORK. // fmtcmd replaces the value of goroot with $GOROOT. // fmtcmd replaces the value of b.gobin with $GOBIN. // // fmtcmd replaces the name of the current directory with dot (.) // but only when it is at the beginning of a space-separated token. // -func (b *builder) fmtcmd(dir string, format string, args ...interface{}) string { +func (b *Builder) fmtcmd(dir string, format string, args ...interface{}) string { cmd := fmt.Sprintf(format, args...) if dir != "" && dir != "/" { cmd = strings.Replace(" "+cmd, " "+dir, " .", -1)[1:] @@ -1883,18 +1831,18 @@ func (b *builder) fmtcmd(dir string, format string, args ...interface{}) string cmd = "cd " + dir + "\n" + cmd } } - if b.work != "" { - cmd = strings.Replace(cmd, b.work, "$WORK", -1) + if b.WorkDir != "" { + cmd = strings.Replace(cmd, b.WorkDir, "$WORK", -1) } return cmd } // showcmd prints the given command to standard output // for the implementation of -n or -x. -func (b *builder) showcmd(dir string, format string, args ...interface{}) { +func (b *Builder) Showcmd(dir string, format string, args ...interface{}) { b.output.Lock() defer b.output.Unlock() - b.print(b.fmtcmd(dir, format, args...) + "\n") + b.Print(b.fmtcmd(dir, format, args...) + "\n") } // showOutput prints "# desc" followed by the given output. @@ -1919,18 +1867,18 @@ func (b *builder) showcmd(dir string, format string, args ...interface{}) { // // showOutput also replaces references to the work directory with $WORK. // -func (b *builder) showOutput(dir, desc, out string) { +func (b *Builder) showOutput(dir, desc, out string) { prefix := "# " + desc suffix := "\n" + out if reldir := base.ShortPath(dir); reldir != dir { suffix = strings.Replace(suffix, " "+dir, " "+reldir, -1) suffix = strings.Replace(suffix, "\n"+dir, "\n"+reldir, -1) } - suffix = strings.Replace(suffix, " "+b.work, " $WORK", -1) + suffix = strings.Replace(suffix, " "+b.WorkDir, " $WORK", -1) b.output.Lock() defer b.output.Unlock() - b.print(prefix, suffix) + b.Print(prefix, suffix) } // errPrintedOutput is a special error indicating that a command failed @@ -1946,7 +1894,7 @@ var cgoTypeSigRe = regexp.MustCompile(`\b_Ctype_\B`) // run runs the command given by cmdline in the directory dir. // If the command fails, run prints information about the failure // and returns a non-nil error. -func (b *builder) run(dir string, desc string, env []string, cmdargs ...interface{}) error { +func (b *Builder) run(dir string, desc string, env []string, cmdargs ...interface{}) error { out, err := b.runOut(dir, desc, env, cmdargs...) if len(out) > 0 { if desc == "" { @@ -1961,7 +1909,7 @@ func (b *builder) run(dir string, desc string, env []string, cmdargs ...interfac } // processOutput prepares the output of runOut to be output to the console. -func (b *builder) processOutput(out []byte) string { +func (b *Builder) processOutput(out []byte) string { if out[len(out)-1] != '\n' { out = append(out, '\n') } @@ -1979,7 +1927,7 @@ func (b *builder) processOutput(out []byte) string { // runOut runs the command given by cmdline in the directory dir. // It returns the command output and any errors that occurred. -func (b *builder) runOut(dir string, desc string, env []string, cmdargs ...interface{}) ([]byte, error) { +func (b *Builder) runOut(dir string, desc string, env []string, cmdargs ...interface{}) ([]byte, error) { cmdline := str.StringList(cmdargs...) if cfg.BuildN || cfg.BuildX { var envcmdline string @@ -1988,7 +1936,7 @@ func (b *builder) runOut(dir string, desc string, env []string, cmdargs ...inter envcmdline += " " } envcmdline += joinUnambiguously(cmdline) - b.showcmd(dir, "%s", envcmdline) + b.Showcmd(dir, "%s", envcmdline) if cfg.BuildN { return nil, nil } @@ -2001,7 +1949,7 @@ func (b *builder) runOut(dir string, desc string, env []string, cmdargs ...inter cmd.Stdout = &buf cmd.Stderr = &buf cmd.Dir = dir - cmd.Env = mergeEnvLists(env, envForDir(cmd.Dir, os.Environ())) + cmd.Env = base.MergeEnvLists(env, base.EnvForDir(cmd.Dir, os.Environ())) err := cmd.Run() // cmd.Run will fail on Unix if some other process has the binary @@ -2083,7 +2031,7 @@ func joinUnambiguously(a []string) string { } // mkdir makes the named directory. -func (b *builder) mkdir(dir string) error { +func (b *Builder) Mkdir(dir string) error { b.exec.Lock() defer b.exec.Unlock() // We can be a little aggressive about being @@ -2094,7 +2042,7 @@ func (b *builder) mkdir(dir string) error { b.mkdirCache[dir] = true if cfg.BuildN || cfg.BuildX { - b.showcmd("", "mkdir -p %s", dir) + b.Showcmd("", "mkdir -p %s", dir) if cfg.BuildN { return nil } @@ -2125,23 +2073,23 @@ func mkAbs(dir, f string) string { type toolchain interface { // gc runs the compiler in a specific directory on a set of files // and returns the name of the generated output file. - gc(b *builder, p *load.Package, archive, obj string, asmhdr bool, importArgs []string, gofiles []string) (ofile string, out []byte, err error) + gc(b *Builder, p *load.Package, archive, obj string, asmhdr bool, importArgs []string, gofiles []string) (ofile string, out []byte, err error) // cc runs the toolchain's C compiler in a directory on a C file // to produce an output file. - cc(b *builder, p *load.Package, objdir, ofile, cfile string) error + cc(b *Builder, p *load.Package, objdir, ofile, cfile string) error // asm runs the assembler in a specific directory on specific files // and returns a list of named output files. - asm(b *builder, p *load.Package, obj string, sfiles []string) ([]string, error) + asm(b *Builder, p *load.Package, obj string, sfiles []string) ([]string, error) // pkgpath builds an appropriate path for a temporary package file. - pkgpath(basedir string, p *load.Package) string + Pkgpath(basedir string, p *load.Package) string // pack runs the archive packer in a specific directory to create // an archive from a set of object files. // typically it is run in the object directory. - pack(b *builder, p *load.Package, objDir, afile string, ofiles []string) error + pack(b *Builder, p *load.Package, objDir, afile string, ofiles []string) error // ld runs the linker to create an executable starting at mainpkg. - ld(b *builder, root *action, out string, allactions []*action, mainpkg string, ofiles []string) error + ld(b *Builder, root *Action, out string, allactions []*Action, mainpkg string, ofiles []string) error // ldShared runs the linker to create a shared library containing the pkgs built by toplevelactions - ldShared(b *builder, toplevelactions []*action, out string, allactions []*action) error + ldShared(b *Builder, toplevelactions []*Action, out string, allactions []*Action) error compiler() string linker() string @@ -2164,32 +2112,32 @@ func (noToolchain) linker() string { return "" } -func (noToolchain) gc(b *builder, p *load.Package, archive, obj string, asmhdr bool, importArgs []string, gofiles []string) (ofile string, out []byte, err error) { +func (noToolchain) gc(b *Builder, p *load.Package, archive, obj string, asmhdr bool, importArgs []string, gofiles []string) (ofile string, out []byte, err error) { return "", nil, noCompiler() } -func (noToolchain) asm(b *builder, p *load.Package, obj string, sfiles []string) ([]string, error) { +func (noToolchain) asm(b *Builder, p *load.Package, obj string, sfiles []string) ([]string, error) { return nil, noCompiler() } -func (noToolchain) pkgpath(basedir string, p *load.Package) string { +func (noToolchain) Pkgpath(basedir string, p *load.Package) string { noCompiler() return "" } -func (noToolchain) pack(b *builder, p *load.Package, objDir, afile string, ofiles []string) error { +func (noToolchain) pack(b *Builder, p *load.Package, objDir, afile string, ofiles []string) error { return noCompiler() } -func (noToolchain) ld(b *builder, root *action, out string, allactions []*action, mainpkg string, ofiles []string) error { +func (noToolchain) ld(b *Builder, root *Action, out string, allactions []*Action, mainpkg string, ofiles []string) error { return noCompiler() } -func (noToolchain) ldShared(b *builder, toplevelactions []*action, out string, allactions []*action) error { +func (noToolchain) ldShared(b *Builder, toplevelactions []*Action, out string, allactions []*Action) error { return noCompiler() } -func (noToolchain) cc(b *builder, p *load.Package, objdir, ofile, cfile string) error { +func (noToolchain) cc(b *Builder, p *load.Package, objdir, ofile, cfile string) error { return noCompiler() } @@ -2204,7 +2152,7 @@ func (gcToolchain) linker() string { return base.Tool("link") } -func (gcToolchain) gc(b *builder, p *load.Package, archive, obj string, asmhdr bool, importArgs []string, gofiles []string) (ofile string, output []byte, err error) { +func (gcToolchain) gc(b *Builder, p *load.Package, archive, obj string, asmhdr bool, importArgs []string, gofiles []string) (ofile string, output []byte, err error) { if archive != "" { ofile = archive } else { @@ -2251,7 +2199,7 @@ func (gcToolchain) gc(b *builder, p *load.Package, archive, obj string, asmhdr b } } - args := []interface{}{cfg.BuildToolexec, base.Tool("compile"), "-o", ofile, "-trimpath", b.work, buildGcflags, gcargs, "-D", p.Internal.LocalPrefix, importArgs} + args := []interface{}{cfg.BuildToolexec, base.Tool("compile"), "-o", ofile, "-trimpath", b.WorkDir, buildGcflags, gcargs, "-D", p.Internal.LocalPrefix, importArgs} if ofile == archive { args = append(args, "-pack") } @@ -2266,10 +2214,10 @@ func (gcToolchain) gc(b *builder, p *load.Package, archive, obj string, asmhdr b return ofile, output, err } -func (gcToolchain) asm(b *builder, p *load.Package, obj string, sfiles []string) ([]string, error) { +func (gcToolchain) asm(b *Builder, p *load.Package, obj string, sfiles []string) ([]string, error) { // Add -I pkg/GOOS_GOARCH so #include "textflag.h" works in .s files. inc := filepath.Join(cfg.GOROOT, "pkg", "include") - args := []interface{}{cfg.BuildToolexec, base.Tool("asm"), "-trimpath", b.work, "-I", obj, "-I", inc, "-D", "GOOS_" + cfg.Goos, "-D", "GOARCH_" + cfg.Goarch, buildAsmflags} + args := []interface{}{cfg.BuildToolexec, base.Tool("asm"), "-trimpath", b.WorkDir, "-I", obj, "-I", inc, "-D", "GOOS_" + cfg.Goos, "-D", "GOARCH_" + cfg.Goarch, buildAsmflags} if p.ImportPath == "runtime" && cfg.Goarch == "386" { for _, arg := range buildAsmflags { if arg == "-dynlink" { @@ -2292,7 +2240,7 @@ func (gcToolchain) asm(b *builder, p *load.Package, obj string, sfiles []string) // toolVerify checks that the command line args writes the same output file // if run using newTool instead. // Unused now but kept around for future use. -func toolVerify(b *builder, p *load.Package, newTool string, ofile string, args []interface{}) error { +func toolVerify(b *Builder, p *load.Package, newTool string, ofile string, args []interface{}) error { newArgs := make([]interface{}, len(args)) copy(newArgs, args) newArgs[1] = base.Tool(newTool) @@ -2315,12 +2263,12 @@ func toolVerify(b *builder, p *load.Package, newTool string, ofile string, args return nil } -func (gcToolchain) pkgpath(basedir string, p *load.Package) string { +func (gcToolchain) Pkgpath(basedir string, p *load.Package) string { end := filepath.FromSlash(p.ImportPath + ".a") return filepath.Join(basedir, end) } -func (gcToolchain) pack(b *builder, p *load.Package, objDir, afile string, ofiles []string) error { +func (gcToolchain) pack(b *Builder, p *load.Package, objDir, afile string, ofiles []string) error { var absOfiles []string for _, f := range ofiles { absOfiles = append(absOfiles, mkAbs(objDir, f)) @@ -2337,7 +2285,7 @@ func (gcToolchain) pack(b *builder, p *load.Package, objDir, afile string, ofile if cfg.BuildN || cfg.BuildX { cmdline := str.StringList("pack", "r", absAfile, absOfiles) - b.showcmd(p.Dir, "%s # internal", joinUnambiguously(cmdline)) + b.Showcmd(p.Dir, "%s # internal", joinUnambiguously(cmdline)) } if cfg.BuildN { return nil @@ -2349,7 +2297,7 @@ func (gcToolchain) pack(b *builder, p *load.Package, objDir, afile string, ofile return nil } -func packInternal(b *builder, afile string, ofiles []string) error { +func packInternal(b *Builder, afile string, ofiles []string) error { dst, err := os.OpenFile(afile, os.O_WRONLY|os.O_APPEND, 0) if err != nil { return err @@ -2429,11 +2377,11 @@ func setextld(ldflags []string, compiler []string) []string { return ldflags } -func (gcToolchain) ld(b *builder, root *action, out string, allactions []*action, mainpkg string, ofiles []string) error { +func (gcToolchain) ld(b *Builder, root *Action, out string, allactions []*Action, mainpkg string, ofiles []string) error { importArgs := b.includeArgs("-L", allactions) - cxx := len(root.p.CXXFiles) > 0 || len(root.p.SwigCXXFiles) > 0 + cxx := len(root.Package.CXXFiles) > 0 || len(root.Package.SwigCXXFiles) > 0 for _, a := range allactions { - if a.p != nil && (len(a.p.CXXFiles) > 0 || len(a.p.SwigCXXFiles) > 0) { + if a.Package != nil && (len(a.Package.CXXFiles) > 0 || len(a.Package.SwigCXXFiles) > 0) { cxx = true } } @@ -2441,13 +2389,13 @@ func (gcToolchain) ld(b *builder, root *action, out string, allactions []*action if cfg.BuildContext.InstallSuffix != "" { ldflags = append(ldflags, "-installsuffix", cfg.BuildContext.InstallSuffix) } - if root.p.Internal.OmitDWARF { + if root.Package.Internal.OmitDWARF { ldflags = append(ldflags, "-w") } if cfg.BuildBuildmode == "plugin" { - pluginpath := root.p.ImportPath + pluginpath := root.Package.ImportPath if pluginpath == "command-line-arguments" { - pluginpath = "plugin/unnamed-" + root.p.Internal.BuildID + pluginpath = "plugin/unnamed-" + root.Package.Internal.BuildID } ldflags = append(ldflags, "-pluginpath", pluginpath) } @@ -2458,14 +2406,14 @@ func (gcToolchain) ld(b *builder, root *action, out string, allactions []*action // Else, use the CC environment variable and defaultCC as fallback. var compiler []string if cxx { - compiler = envList("CXX", defaultCXX) + compiler = envList("CXX", cfg.DefaultCXX) } else { - compiler = envList("CC", defaultCC) + compiler = envList("CC", cfg.DefaultCC) } ldflags = setextld(ldflags, compiler) ldflags = append(ldflags, "-buildmode="+ldBuildmode) - if root.p.Internal.BuildID != "" { - ldflags = append(ldflags, "-buildid="+root.p.Internal.BuildID) + if root.Package.Internal.BuildID != "" { + ldflags = append(ldflags, "-buildid="+root.Package.Internal.BuildID) } ldflags = append(ldflags, cfg.BuildLdflags...) @@ -2481,17 +2429,17 @@ func (gcToolchain) ld(b *builder, root *action, out string, allactions []*action dir, out = filepath.Split(out) } - return b.run(dir, root.p.ImportPath, nil, cfg.BuildToolexec, base.Tool("link"), "-o", out, importArgs, ldflags, mainpkg) + return b.run(dir, root.Package.ImportPath, nil, cfg.BuildToolexec, base.Tool("link"), "-o", out, importArgs, ldflags, mainpkg) } -func (gcToolchain) ldShared(b *builder, toplevelactions []*action, out string, allactions []*action) error { +func (gcToolchain) ldShared(b *Builder, toplevelactions []*Action, out string, allactions []*Action) error { importArgs := b.includeArgs("-L", allactions) ldflags := []string{"-installsuffix", cfg.BuildContext.InstallSuffix} ldflags = append(ldflags, "-buildmode=shared") ldflags = append(ldflags, cfg.BuildLdflags...) cxx := false for _, a := range allactions { - if a.p != nil && (len(a.p.CXXFiles) > 0 || len(a.p.SwigCXXFiles) > 0) { + if a.Package != nil && (len(a.Package.CXXFiles) > 0 || len(a.Package.SwigCXXFiles) > 0) { cxx = true } } @@ -2501,46 +2449,46 @@ func (gcToolchain) ldShared(b *builder, toplevelactions []*action, out string, a // Else, use the CC environment variable and defaultCC as fallback. var compiler []string if cxx { - compiler = envList("CXX", defaultCXX) + compiler = envList("CXX", cfg.DefaultCXX) } else { - compiler = envList("CC", defaultCC) + compiler = envList("CC", cfg.DefaultCC) } ldflags = setextld(ldflags, compiler) for _, d := range toplevelactions { - if !strings.HasSuffix(d.target, ".a") { // omit unsafe etc and actions for other shared libraries + if !strings.HasSuffix(d.Target, ".a") { // omit unsafe etc and actions for other shared libraries continue } - ldflags = append(ldflags, d.p.ImportPath+"="+d.target) + ldflags = append(ldflags, d.Package.ImportPath+"="+d.Target) } return b.run(".", out, nil, cfg.BuildToolexec, base.Tool("link"), "-o", out, importArgs, ldflags) } -func (gcToolchain) cc(b *builder, p *load.Package, objdir, ofile, cfile string) error { +func (gcToolchain) cc(b *Builder, p *load.Package, objdir, ofile, cfile string) error { return fmt.Errorf("%s: C source files not supported without cgo", mkAbs(p.Dir, cfile)) } // The Gccgo toolchain. type gccgoToolchain struct{} -var gccgoName, gccgoBin string +var GccgoName, GccgoBin string func init() { - gccgoName = os.Getenv("GCCGO") - if gccgoName == "" { - gccgoName = "gccgo" + GccgoName = os.Getenv("GCCGO") + if GccgoName == "" { + GccgoName = "gccgo" } - gccgoBin, _ = exec.LookPath(gccgoName) + GccgoBin, _ = exec.LookPath(GccgoName) } func (gccgoToolchain) compiler() string { - return gccgoBin + return GccgoBin } func (gccgoToolchain) linker() string { - return gccgoBin + return GccgoBin } -func (tools gccgoToolchain) gc(b *builder, p *load.Package, archive, obj string, asmhdr bool, importArgs []string, gofiles []string) (ofile string, output []byte, err error) { +func (tools gccgoToolchain) gc(b *Builder, p *load.Package, archive, obj string, asmhdr bool, importArgs []string, gofiles []string) (ofile string, output []byte, err error) { out := "_go_.o" ofile = obj + out gcargs := []string{"-g"} @@ -2560,7 +2508,7 @@ func (tools gccgoToolchain) gc(b *builder, p *load.Package, archive, obj string, return ofile, output, err } -func (tools gccgoToolchain) asm(b *builder, p *load.Package, obj string, sfiles []string) ([]string, error) { +func (tools gccgoToolchain) asm(b *Builder, p *load.Package, obj string, sfiles []string) ([]string, error) { var ofiles []string for _, sfile := range sfiles { ofile := obj + sfile[:len(sfile)-len(".s")] + ".o" @@ -2580,14 +2528,14 @@ func (tools gccgoToolchain) asm(b *builder, p *load.Package, obj string, sfiles return ofiles, nil } -func (gccgoToolchain) pkgpath(basedir string, p *load.Package) string { +func (gccgoToolchain) Pkgpath(basedir string, p *load.Package) string { end := filepath.FromSlash(p.ImportPath + ".a") afile := filepath.Join(basedir, end) // add "lib" to the final element return filepath.Join(filepath.Dir(afile), "lib"+filepath.Base(afile)) } -func (gccgoToolchain) pack(b *builder, p *load.Package, objDir, afile string, ofiles []string) error { +func (gccgoToolchain) pack(b *Builder, p *load.Package, objDir, afile string, ofiles []string) error { var absOfiles []string for _, f := range ofiles { absOfiles = append(absOfiles, mkAbs(objDir, f)) @@ -2595,7 +2543,7 @@ func (gccgoToolchain) pack(b *builder, p *load.Package, objDir, afile string, of return b.run(p.Dir, p.ImportPath, nil, "ar", "rc", mkAbs(objDir, afile), absOfiles) } -func (tools gccgoToolchain) link(b *builder, root *action, out string, allactions []*action, mainpkg string, ofiles []string, buildmode, desc string) error { +func (tools gccgoToolchain) link(b *Builder, root *Action, out string, allactions []*Action, mainpkg string, ofiles []string, buildmode, desc string) error { // gccgo needs explicit linking with all package dependencies, // and all LDFLAGS from cgo dependencies. apackagePathsSeen := make(map[string]bool) @@ -2607,10 +2555,10 @@ func (tools gccgoToolchain) link(b *builder, root *action, out string, allaction cxx := false objc := false fortran := false - if root.p != nil { - cxx = len(root.p.CXXFiles) > 0 || len(root.p.SwigCXXFiles) > 0 - objc = len(root.p.MFiles) > 0 - fortran = len(root.p.FFiles) > 0 + if root.Package != nil { + cxx = len(root.Package.CXXFiles) > 0 || len(root.Package.SwigCXXFiles) > 0 + objc = len(root.Package.MFiles) > 0 + fortran = len(root.Package.FFiles) > 0 } readCgoFlags := func(flagsFile string) error { @@ -2636,7 +2584,7 @@ func (tools gccgoToolchain) link(b *builder, root *action, out string, allaction } readAndRemoveCgoFlags := func(archive string) (string, error) { - newa, err := ioutil.TempFile(b.work, filepath.Base(archive)) + newa, err := ioutil.TempFile(b.WorkDir, filepath.Base(archive)) if err != nil { return "", err } @@ -2658,7 +2606,7 @@ func (tools gccgoToolchain) link(b *builder, root *action, out string, allaction } newarchive := newa.Name() - err = b.run(b.work, desc, nil, "ar", "x", newarchive, "_cgo_flags") + err = b.run(b.WorkDir, desc, nil, "ar", "x", newarchive, "_cgo_flags") if err != nil { return "", err } @@ -2666,27 +2614,27 @@ func (tools gccgoToolchain) link(b *builder, root *action, out string, allaction if err != nil { return "", err } - err = readCgoFlags(filepath.Join(b.work, "_cgo_flags")) + err = readCgoFlags(filepath.Join(b.WorkDir, "_cgo_flags")) if err != nil { return "", err } return newarchive, nil } - actionsSeen := make(map[*action]bool) + actionsSeen := make(map[*Action]bool) // Make a pre-order depth-first traversal of the action graph, taking note of // whether a shared library action has been seen on the way to an action (the // construction of the graph means that if any path to a node passes through // a shared library action, they all do). - var walk func(a *action, seenShlib bool) + var walk func(a *Action, seenShlib bool) var err error - walk = func(a *action, seenShlib bool) { + walk = func(a *Action, seenShlib bool) { if actionsSeen[a] { return } actionsSeen[a] = true - if a.p != nil && !seenShlib { - if a.p.Standard { + if a.Package != nil && !seenShlib { + if a.Package.Standard { return } // We record the target of the first time we see a .a file @@ -2694,12 +2642,12 @@ func (tools gccgoToolchain) link(b *builder, root *action, out string, allaction // rather than the 'build' location (which may not exist any // more). We still need to traverse the dependencies of the // build action though so saying - // if apackagePathsSeen[a.p.ImportPath] { return } + // if apackagePathsSeen[a.Package.ImportPath] { return } // doesn't work. - if !apackagePathsSeen[a.p.ImportPath] { - apackagePathsSeen[a.p.ImportPath] = true - target := a.target - if len(a.p.CgoFiles) > 0 || a.p.UsesSwig() { + if !apackagePathsSeen[a.Package.ImportPath] { + apackagePathsSeen[a.Package.ImportPath] = true + target := a.Target + if len(a.Package.CgoFiles) > 0 || a.Package.UsesSwig() { target, err = readAndRemoveCgoFlags(target) if err != nil { return @@ -2708,18 +2656,18 @@ func (tools gccgoToolchain) link(b *builder, root *action, out string, allaction afiles = append(afiles, target) } } - if strings.HasSuffix(a.target, ".so") { - shlibs = append(shlibs, a.target) + if strings.HasSuffix(a.Target, ".so") { + shlibs = append(shlibs, a.Target) seenShlib = true } - for _, a1 := range a.deps { + for _, a1 := range a.Deps { walk(a1, seenShlib) if err != nil { return } } } - for _, a1 := range root.deps { + for _, a1 := range root.Deps { walk(a1, false) if err != nil { return err @@ -2731,25 +2679,25 @@ func (tools gccgoToolchain) link(b *builder, root *action, out string, allaction // The go tool can dig up runtime/cgo from GOROOT and // think that it should use its CgoLDFLAGS, but gccgo // doesn't use runtime/cgo. - if a.p == nil { + if a.Package == nil { continue } - if !a.p.Standard { - cgoldflags = append(cgoldflags, a.p.CgoLDFLAGS...) + if !a.Package.Standard { + cgoldflags = append(cgoldflags, a.Package.CgoLDFLAGS...) } - if len(a.p.CgoFiles) > 0 { + if len(a.Package.CgoFiles) > 0 { usesCgo = true } - if a.p.UsesSwig() { + if a.Package.UsesSwig() { usesCgo = true } - if len(a.p.CXXFiles) > 0 || len(a.p.SwigCXXFiles) > 0 { + if len(a.Package.CXXFiles) > 0 || len(a.Package.SwigCXXFiles) > 0 { cxx = true } - if len(a.p.MFiles) > 0 { + if len(a.Package.MFiles) > 0 { objc = true } - if len(a.p.FFiles) > 0 { + if len(a.Package.FFiles) > 0 { fortran = true } } @@ -2768,8 +2716,8 @@ func (tools gccgoToolchain) link(b *builder, root *action, out string, allaction ldflags = append(ldflags, cgoldflags...) ldflags = append(ldflags, envList("CGO_LDFLAGS", "")...) - if root.p != nil { - ldflags = append(ldflags, root.p.CgoLDFLAGS...) + if root.Package != nil { + ldflags = append(ldflags, root.Package.CgoLDFLAGS...) } ldflags = str.StringList("-Wl,-(", ldflags, "-Wl,-)") @@ -2861,17 +2809,17 @@ func (tools gccgoToolchain) link(b *builder, root *action, out string, allaction return nil } -func (tools gccgoToolchain) ld(b *builder, root *action, out string, allactions []*action, mainpkg string, ofiles []string) error { - return tools.link(b, root, out, allactions, mainpkg, ofiles, ldBuildmode, root.p.ImportPath) +func (tools gccgoToolchain) ld(b *Builder, root *Action, out string, allactions []*Action, mainpkg string, ofiles []string) error { + return tools.link(b, root, out, allactions, mainpkg, ofiles, ldBuildmode, root.Package.ImportPath) } -func (tools gccgoToolchain) ldShared(b *builder, toplevelactions []*action, out string, allactions []*action) error { - fakeRoot := &action{} - fakeRoot.deps = toplevelactions +func (tools gccgoToolchain) ldShared(b *Builder, toplevelactions []*Action, out string, allactions []*Action) error { + fakeRoot := &Action{} + fakeRoot.Deps = toplevelactions return tools.link(b, fakeRoot, out, allactions, "", nil, "shared", out) } -func (tools gccgoToolchain) cc(b *builder, p *load.Package, objdir, ofile, cfile string) error { +func (tools gccgoToolchain) cc(b *Builder, p *load.Package, objdir, ofile, cfile string) error { inc := filepath.Join(cfg.GOROOT, "pkg", "include") cfile = mkAbs(p.Dir, cfile) defs := []string{"-D", "GOOS_" + cfg.Goos, "-D", "GOARCH_" + cfg.Goarch} @@ -2884,7 +2832,7 @@ func (tools gccgoToolchain) cc(b *builder, p *load.Package, objdir, ofile, cfile defs = append(defs, "-fsplit-stack") } defs = tools.maybePIC(defs) - return b.run(p.Dir, p.ImportPath, nil, envList("CC", defaultCC), "-Wall", "-g", + return b.run(p.Dir, p.ImportPath, nil, envList("CC", cfg.DefaultCC), "-Wall", "-g", "-I", objdir, "-I", inc, "-o", ofile, defs, "-c", cfile) } @@ -2917,22 +2865,22 @@ func gccgoCleanPkgpath(p *load.Package) string { } // gcc runs the gcc C compiler to create an object from a single C file. -func (b *builder) gcc(p *load.Package, out string, flags []string, cfile string) error { - return b.ccompile(p, out, flags, cfile, b.gccCmd(p.Dir)) +func (b *Builder) gcc(p *load.Package, out string, flags []string, cfile string) error { + return b.ccompile(p, out, flags, cfile, b.GccCmd(p.Dir)) } // gxx runs the g++ C++ compiler to create an object from a single C++ file. -func (b *builder) gxx(p *load.Package, out string, flags []string, cxxfile string) error { - return b.ccompile(p, out, flags, cxxfile, b.gxxCmd(p.Dir)) +func (b *Builder) gxx(p *load.Package, out string, flags []string, cxxfile string) error { + return b.ccompile(p, out, flags, cxxfile, b.GxxCmd(p.Dir)) } // gfortran runs the gfortran Fortran compiler to create an object from a single Fortran file. -func (b *builder) gfortran(p *load.Package, out string, flags []string, ffile string) error { +func (b *Builder) gfortran(p *load.Package, out string, flags []string, ffile string) error { return b.ccompile(p, out, flags, ffile, b.gfortranCmd(p.Dir)) } // ccompile runs the given C or C++ compiler and creates an object from a single source file. -func (b *builder) ccompile(p *load.Package, outfile string, flags []string, file string, compiler []string) error { +func (b *Builder) ccompile(p *load.Package, outfile string, flags []string, file string, compiler []string) error { file = mkAbs(p.Dir, file) desc := p.ImportPath output, err := b.runOut(p.Dir, desc, nil, compiler, flags, "-o", outfile, "-c", file) @@ -2948,36 +2896,36 @@ func (b *builder) ccompile(p *load.Package, outfile string, flags []string, file } // gccld runs the gcc linker to create an executable from a set of object files. -func (b *builder) gccld(p *load.Package, out string, flags []string, obj []string) error { +func (b *Builder) gccld(p *load.Package, out string, flags []string, obj []string) error { var cmd []string if len(p.CXXFiles) > 0 || len(p.SwigCXXFiles) > 0 { - cmd = b.gxxCmd(p.Dir) + cmd = b.GxxCmd(p.Dir) } else { - cmd = b.gccCmd(p.Dir) + cmd = b.GccCmd(p.Dir) } return b.run(p.Dir, p.ImportPath, nil, cmd, "-o", out, obj, flags) } // gccCmd returns a gcc command line prefix // defaultCC is defined in zdefaultcc.go, written by cmd/dist. -func (b *builder) gccCmd(objdir string) []string { - return b.ccompilerCmd("CC", defaultCC, objdir) +func (b *Builder) GccCmd(objdir string) []string { + return b.ccompilerCmd("CC", cfg.DefaultCC, objdir) } // gxxCmd returns a g++ command line prefix // defaultCXX is defined in zdefaultcc.go, written by cmd/dist. -func (b *builder) gxxCmd(objdir string) []string { - return b.ccompilerCmd("CXX", defaultCXX, objdir) +func (b *Builder) GxxCmd(objdir string) []string { + return b.ccompilerCmd("CXX", cfg.DefaultCXX, objdir) } // gfortranCmd returns a gfortran command line prefix. -func (b *builder) gfortranCmd(objdir string) []string { +func (b *Builder) gfortranCmd(objdir string) []string { return b.ccompilerCmd("FC", "gfortran", objdir) } // ccompilerCmd returns a command line prefix for the given environment // variable and using the default command when the variable is empty. -func (b *builder) ccompilerCmd(envvar, defcmd, objdir string) []string { +func (b *Builder) ccompilerCmd(envvar, defcmd, objdir string) []string { // NOTE: env.go's mkEnv knows that the first three // strings returned are "gcc", "-I", objdir (and cuts them off). @@ -3014,7 +2962,7 @@ func (b *builder) ccompilerCmd(envvar, defcmd, objdir string) []string { // Tell gcc not to include the work directory in object files. if b.gccSupportsFlag("-fdebug-prefix-map=a=b") { - a = append(a, "-fdebug-prefix-map="+b.work+"=/tmp/go-build") + a = append(a, "-fdebug-prefix-map="+b.WorkDir+"=/tmp/go-build") } // Tell gcc not to include flags in object files, which defeats the @@ -3036,34 +2984,34 @@ func (b *builder) ccompilerCmd(envvar, defcmd, objdir string) []string { // On systems with PIE (position independent executables) enabled by default, // -no-pie must be passed when doing a partial link with -Wl,-r. But -no-pie is // not supported by all compilers. -func (b *builder) gccSupportsNoPie() bool { +func (b *Builder) gccSupportsNoPie() bool { return b.gccSupportsFlag("-no-pie") } // gccSupportsFlag checks to see if the compiler supports a flag. -func (b *builder) gccSupportsFlag(flag string) bool { +func (b *Builder) gccSupportsFlag(flag string) bool { b.exec.Lock() defer b.exec.Unlock() if b, ok := b.flagCache[flag]; ok { return b } if b.flagCache == nil { - src := filepath.Join(b.work, "trivial.c") + src := filepath.Join(b.WorkDir, "trivial.c") if err := ioutil.WriteFile(src, []byte{}, 0666); err != nil { return false } b.flagCache = make(map[string]bool) } - cmdArgs := append(envList("CC", defaultCC), flag, "-c", "trivial.c") + cmdArgs := append(envList("CC", cfg.DefaultCC), flag, "-c", "trivial.c") if cfg.BuildN || cfg.BuildX { - b.showcmd(b.work, "%s", joinUnambiguously(cmdArgs)) + b.Showcmd(b.WorkDir, "%s", joinUnambiguously(cmdArgs)) if cfg.BuildN { return false } } cmd := exec.Command(cmdArgs[0], cmdArgs[1:]...) - cmd.Dir = b.work - cmd.Env = mergeEnvLists([]string{"LC_ALL=C"}, envForDir(cmd.Dir, os.Environ())) + cmd.Dir = b.WorkDir + cmd.Env = base.MergeEnvLists([]string{"LC_ALL=C"}, base.EnvForDir(cmd.Dir, os.Environ())) out, err := cmd.CombinedOutput() supported := err == nil && !bytes.Contains(out, []byte("unrecognized")) b.flagCache[flag] = supported @@ -3071,7 +3019,7 @@ func (b *builder) gccSupportsFlag(flag string) bool { } // gccArchArgs returns arguments to pass to gcc based on the architecture. -func (b *builder) gccArchArgs() []string { +func (b *Builder) gccArchArgs() []string { switch cfg.Goarch { case "386": return []string{"-m32"} @@ -3099,8 +3047,8 @@ func envList(key, def string) []string { return strings.Fields(v) } -// Return the flags to use when invoking the C, C++ or Fortran compilers, or cgo. -func (b *builder) cflags(p *load.Package) (cppflags, cflags, cxxflags, fflags, ldflags []string) { +// CFlags returns the flags to use when invoking the C, C++ or Fortran compilers, or cgo. +func (b *Builder) CFlags(p *load.Package) (cppflags, cflags, cxxflags, fflags, ldflags []string) { defaults := "-g -O2" cppflags = str.StringList(envList("CGO_CPPFLAGS", ""), p.CgoCPPFLAGS) @@ -3113,9 +3061,9 @@ func (b *builder) cflags(p *load.Package) (cppflags, cflags, cxxflags, fflags, l var cgoRe = regexp.MustCompile(`[/\\:]`) -func (b *builder) cgo(a *action, cgoExe, obj string, pcCFLAGS, pcLDFLAGS, cgofiles, objdirCgofiles, gccfiles, gxxfiles, mfiles, ffiles []string) (outGo, outObj []string, err error) { - p := a.p - cgoCPPFLAGS, cgoCFLAGS, cgoCXXFLAGS, cgoFFLAGS, cgoLDFLAGS := b.cflags(p) +func (b *Builder) cgo(a *Action, cgoExe, obj string, pcCFLAGS, pcLDFLAGS, cgofiles, objdirCgofiles, gccfiles, gxxfiles, mfiles, ffiles []string) (outGo, outObj []string, err error) { + p := a.Package + cgoCPPFLAGS, cgoCFLAGS, cgoCXXFLAGS, cgoFFLAGS, cgoLDFLAGS := b.CFlags(p) cgoCPPFLAGS = append(cgoCPPFLAGS, pcCFLAGS...) cgoLDFLAGS = append(cgoLDFLAGS, pcLDFLAGS...) // If we are compiling Objective-C code, then we need to link against libobjc @@ -3277,7 +3225,7 @@ func (b *builder) cgo(a *action, cgoExe, obj string, pcCFLAGS, pcLDFLAGS, cgofil case "gccgo": defunC := obj + "_cgo_defun.c" defunObj := obj + "_cgo_defun.o" - if err := buildToolchain.cc(b, p, obj, defunObj, defunC); err != nil { + if err := BuildToolchain.cc(b, p, obj, defunObj, defunC); err != nil { return nil, nil, err } outObj = append(outObj, defunObj) @@ -3292,7 +3240,7 @@ func (b *builder) cgo(a *action, cgoExe, obj string, pcCFLAGS, pcLDFLAGS, cgofil // dynimport creates a Go source file named importGo containing // //go:cgo_import_dynamic directives for each symbol or library // dynamically imported by the object files outObj. -func (b *builder) dynimport(p *load.Package, obj, importGo, cgoExe string, cflags, cgoLDFLAGS, outObj []string) error { +func (b *Builder) dynimport(p *load.Package, obj, importGo, cgoExe string, cflags, cgoLDFLAGS, outObj []string) error { cfile := obj + "_cgo_main.c" ofile := obj + "_cgo_main.o" if err := b.gcc(p, ofile, cflags, cfile); err != nil { @@ -3321,7 +3269,7 @@ func (b *builder) dynimport(p *load.Package, obj, importGo, cgoExe string, cflag // collect partially links the object files outObj into a single // relocatable object file named ofile. -func (b *builder) collect(p *load.Package, obj, ofile string, cgoLDFLAGS, outObj []string) error { +func (b *Builder) collect(p *load.Package, obj, ofile string, cgoLDFLAGS, outObj []string) error { // When linking relocatable objects, various flags need to be // filtered out as they are inapplicable and can cause some linkers // to fail. @@ -3381,7 +3329,7 @@ func (b *builder) collect(p *load.Package, obj, ofile string, cgoLDFLAGS, outObj // Run SWIG on all SWIG input files. // TODO: Don't build a shared library, once SWIG emits the necessary // pragmas for external linking. -func (b *builder) swig(p *load.Package, obj string, pcCFLAGS []string) (outGo, outC, outCXX []string, err error) { +func (b *Builder) swig(p *load.Package, obj string, pcCFLAGS []string) (outGo, outC, outCXX []string, err error) { if err := b.swigVersionCheck(); err != nil { return nil, nil, nil, err } @@ -3424,7 +3372,7 @@ var ( swigCheck error ) -func (b *builder) swigDoVersionCheck() error { +func (b *Builder) swigDoVersionCheck() error { out, err := b.runOut("", "", nil, "swig", "-version") if err != nil { return err @@ -3477,7 +3425,7 @@ func (b *builder) swigDoVersionCheck() error { return nil } -func (b *builder) swigVersionCheck() error { +func (b *Builder) swigVersionCheck() error { swigCheckOnce.Do(func() { swigCheck = b.swigDoVersionCheck() }) @@ -3499,11 +3447,11 @@ const i int = 1 << 32 // Determine the size of int on the target system for the -intgosize option // of swig >= 2.0.9. Run only once. -func (b *builder) swigDoIntSize(obj string) (intsize string, err error) { +func (b *Builder) swigDoIntSize(obj string) (intsize string, err error) { if cfg.BuildN { return "$INTBITS", nil } - src := filepath.Join(b.work, "swig_intsize.go") + src := filepath.Join(b.WorkDir, "swig_intsize.go") if err = ioutil.WriteFile(src, []byte(swigIntSizeCode), 0666); err != nil { return } @@ -3511,7 +3459,7 @@ func (b *builder) swigDoIntSize(obj string) (intsize string, err error) { p := load.GoFilesPackage(srcs) - if _, _, e := buildToolchain.gc(b, p, "", obj, false, nil, srcs); e != nil { + if _, _, e := BuildToolchain.gc(b, p, "", obj, false, nil, srcs); e != nil { return "32", nil } return "64", nil @@ -3519,7 +3467,7 @@ func (b *builder) swigDoIntSize(obj string) (intsize string, err error) { // Determine the size of int on the target system for the -intgosize option // of swig >= 2.0.9. -func (b *builder) swigIntSize(obj string) (intsize string, err error) { +func (b *Builder) swigIntSize(obj string) (intsize string, err error) { swigIntSizeOnce.Do(func() { swigIntSize, swigIntSizeError = b.swigDoIntSize(obj) }) @@ -3527,8 +3475,8 @@ func (b *builder) swigIntSize(obj string) (intsize string, err error) { } // Run SWIG on one SWIG input file. -func (b *builder) swigOne(p *load.Package, file, obj string, pcCFLAGS []string, cxx bool, intgosize string) (outGo, outC string, err error) { - cgoCPPFLAGS, cgoCFLAGS, cgoCXXFLAGS, _, _ := b.cflags(p) +func (b *Builder) swigOne(p *load.Package, file, obj string, pcCFLAGS []string, cxx bool, intgosize string) (outGo, outC string, err error) { + cgoCPPFLAGS, cgoCFLAGS, cgoCXXFLAGS, _, _ := b.CFlags(p) var cflags []string if cxx { cflags = str.StringList(cgoCPPFLAGS, pcCFLAGS, cgoCXXFLAGS) @@ -3604,7 +3552,7 @@ func (b *builder) swigOne(p *load.Package, file, obj string, pcCFLAGS []string, // other than passing a trailing --build-id=none. So that is what we // do, but only on systems likely to support it, which is to say, // systems that normally use gold or the GNU linker. -func (b *builder) disableBuildID(ldflags []string) []string { +func (b *Builder) disableBuildID(ldflags []string) []string { switch cfg.Goos { case "android", "dragonfly", "linux", "netbsd": ldflags = append(ldflags, "-Wl,--build-id=none") @@ -3613,13 +3561,13 @@ func (b *builder) disableBuildID(ldflags []string) []string { } // An actionQueue is a priority queue of actions. -type actionQueue []*action +type actionQueue []*Action // Implement heap.Interface func (q *actionQueue) Len() int { return len(*q) } func (q *actionQueue) Swap(i, j int) { (*q)[i], (*q)[j] = (*q)[j], (*q)[i] } func (q *actionQueue) Less(i, j int) bool { return (*q)[i].priority < (*q)[j].priority } -func (q *actionQueue) Push(x interface{}) { *q = append(*q, x.(*action)) } +func (q *actionQueue) Push(x interface{}) { *q = append(*q, x.(*Action)) } func (q *actionQueue) Pop() interface{} { n := len(*q) - 1 x := (*q)[n] @@ -3627,15 +3575,15 @@ func (q *actionQueue) Pop() interface{} { return x } -func (q *actionQueue) push(a *action) { +func (q *actionQueue) push(a *Action) { heap.Push(q, a) } -func (q *actionQueue) pop() *action { - return heap.Pop(q).(*action) +func (q *actionQueue) pop() *Action { + return heap.Pop(q).(*Action) } -func instrumentInit() { +func InstrumentInit() { if !cfg.BuildRace && !cfg.BuildMSan { return } diff --git a/src/cmd/go/internal/work/build_test.go b/src/cmd/go/internal/work/build_test.go new file mode 100644 index 00000000000..9101ef1d1b4 --- /dev/null +++ b/src/cmd/go/internal/work/build_test.go @@ -0,0 +1,167 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package work + +import ( + "io/ioutil" + "os" + "path/filepath" + "reflect" + "testing" + + "cmd/go/internal/base" + "cmd/go/internal/cfg" + "cmd/go/internal/load" +) + +func TestRemoveDevNull(t *testing.T) { + fi, err := os.Lstat(os.DevNull) + if err != nil { + t.Skip(err) + } + if fi.Mode().IsRegular() { + t.Errorf("Lstat(%s).Mode().IsRegular() = true; expected false", os.DevNull) + } + mayberemovefile(os.DevNull) + _, err = os.Lstat(os.DevNull) + if err != nil { + t.Errorf("mayberemovefile(%s) did remove it; oops", os.DevNull) + } +} + +func TestSplitPkgConfigOutput(t *testing.T) { + for _, test := range []struct { + in []byte + want []string + }{ + {[]byte(`-r:foo -L/usr/white\ space/lib -lfoo\ bar -lbar\ baz`), []string{"-r:foo", "-L/usr/white space/lib", "-lfoo bar", "-lbar baz"}}, + {[]byte(`-lextra\ fun\ arg\\`), []string{`-lextra fun arg\`}}, + {[]byte(`broken flag\`), []string{"broken", "flag"}}, + {[]byte("\textra whitespace\r\n"), []string{"extra", "whitespace"}}, + {[]byte(" \r\n "), nil}, + } { + got := splitPkgConfigOutput(test.in) + if !reflect.DeepEqual(got, test.want) { + t.Errorf("splitPkgConfigOutput(%v) = %v; want %v", test.in, got, test.want) + } + } +} + +func TestSharedLibName(t *testing.T) { + // TODO(avdva) - make these values platform-specific + prefix := "lib" + suffix := ".so" + testData := []struct { + args []string + pkgs []*load.Package + expected string + expectErr bool + rootedAt string + }{ + { + args: []string{"std"}, + pkgs: []*load.Package{}, + expected: "std", + }, + { + args: []string{"std", "cmd"}, + pkgs: []*load.Package{}, + expected: "std,cmd", + }, + { + args: []string{}, + pkgs: []*load.Package{pkgImportPath("gopkg.in/somelib")}, + expected: "gopkg.in-somelib", + }, + { + args: []string{"./..."}, + pkgs: []*load.Package{pkgImportPath("somelib")}, + expected: "somelib", + rootedAt: "somelib", + }, + { + args: []string{"../somelib", "../somelib"}, + pkgs: []*load.Package{pkgImportPath("somelib")}, + expected: "somelib", + }, + { + args: []string{"../lib1", "../lib2"}, + pkgs: []*load.Package{pkgImportPath("gopkg.in/lib1"), pkgImportPath("gopkg.in/lib2")}, + expected: "gopkg.in-lib1,gopkg.in-lib2", + }, + { + args: []string{"./..."}, + pkgs: []*load.Package{ + pkgImportPath("gopkg.in/dir/lib1"), + pkgImportPath("gopkg.in/lib2"), + pkgImportPath("gopkg.in/lib3"), + }, + expected: "gopkg.in", + rootedAt: "gopkg.in", + }, + { + args: []string{"std", "../lib2"}, + pkgs: []*load.Package{}, + expectErr: true, + }, + { + args: []string{"all", "./"}, + pkgs: []*load.Package{}, + expectErr: true, + }, + { + args: []string{"cmd", "fmt"}, + pkgs: []*load.Package{}, + expectErr: true, + }, + } + for _, data := range testData { + func() { + if data.rootedAt != "" { + tmpGopath, err := ioutil.TempDir("", "gopath") + if err != nil { + t.Fatal(err) + } + oldGopath := cfg.BuildContext.GOPATH + defer func() { + cfg.BuildContext.GOPATH = oldGopath + os.Chdir(base.Cwd) + err := os.RemoveAll(tmpGopath) + if err != nil { + t.Error(err) + } + }() + root := filepath.Join(tmpGopath, "src", data.rootedAt) + err = os.MkdirAll(root, 0755) + if err != nil { + t.Fatal(err) + } + cfg.BuildContext.GOPATH = tmpGopath + os.Chdir(root) + } + computed, err := libname(data.args, data.pkgs) + if err != nil { + if !data.expectErr { + t.Errorf("libname returned an error %q, expected a name", err.Error()) + } + } else if data.expectErr { + t.Errorf("libname returned %q, expected an error", computed) + } else { + expected := prefix + data.expected + suffix + if expected != computed { + t.Errorf("libname returned %q, expected %q", computed, expected) + } + } + }() + } +} + +func pkgImportPath(pkgpath string) *load.Package { + return &load.Package{ + PackagePublic: load.PackagePublic{ + ImportPath: pkgpath, + }, + } +} diff --git a/src/cmd/go/list.go b/src/cmd/go/list.go index 527d2500caa..25b0c96e652 100644 --- a/src/cmd/go/list.go +++ b/src/cmd/go/list.go @@ -9,6 +9,7 @@ import ( "cmd/go/internal/base" "cmd/go/internal/cfg" "cmd/go/internal/load" + "cmd/go/internal/work" "encoding/json" "io" "os" @@ -140,7 +141,7 @@ For more about specifying packages, see 'go help packages'. func init() { cmdList.Run = runList // break init cycle - addBuildFlags(cmdList) + work.AddBuildFlags(cmdList) } var listE = cmdList.Flag.Bool("e", false, "") @@ -149,7 +150,7 @@ var listJson = cmdList.Flag.Bool("json", false, "") var nl = []byte{'\n'} func runList(cmd *base.Command, args []string) { - buildModeInit() + work.BuildModeInit() out := newTrackingWriter(os.Stdout) defer out.w.Flush() diff --git a/src/cmd/go/main.go b/src/cmd/go/main.go index 9376b88e5aa..64cde307c9e 100644 --- a/src/cmd/go/main.go +++ b/src/cmd/go/main.go @@ -16,11 +16,12 @@ import ( "cmd/go/internal/base" "cmd/go/internal/cfg" "cmd/go/internal/help" + "cmd/go/internal/work" ) func init() { base.Commands = []*base.Command{ - cmdBuild, + work.CmdBuild, cmdClean, cmdDoc, cmdEnv, @@ -29,7 +30,7 @@ func init() { cmdFmt, cmdGenerate, cmdGet, - cmdInstall, + work.CmdInstall, cmdList, cmdRun, cmdTest, diff --git a/src/cmd/go/pkg_test.go b/src/cmd/go/pkg_test.go index 6158ec0ffa4..00a7b9d06ac 100644 --- a/src/cmd/go/pkg_test.go +++ b/src/cmd/go/pkg_test.go @@ -5,13 +5,8 @@ package main import ( - "cmd/go/internal/base" - "cmd/go/internal/cfg" "cmd/go/internal/load" "cmd/go/internal/str" - "io/ioutil" - "os" - "path/filepath" "reflect" "strings" "testing" @@ -95,112 +90,3 @@ func pkgImportPath(path string) *load.Package { }, } } - -func TestSharedLibName(t *testing.T) { - // TODO(avdva) - make these values platform-specific - prefix := "lib" - suffix := ".so" - testData := []struct { - args []string - pkgs []*load.Package - expected string - expectErr bool - rootedAt string - }{ - { - args: []string{"std"}, - pkgs: []*load.Package{}, - expected: "std", - }, - { - args: []string{"std", "cmd"}, - pkgs: []*load.Package{}, - expected: "std,cmd", - }, - { - args: []string{}, - pkgs: []*load.Package{pkgImportPath("gopkg.in/somelib")}, - expected: "gopkg.in-somelib", - }, - { - args: []string{"./..."}, - pkgs: []*load.Package{pkgImportPath("somelib")}, - expected: "somelib", - rootedAt: "somelib", - }, - { - args: []string{"../somelib", "../somelib"}, - pkgs: []*load.Package{pkgImportPath("somelib")}, - expected: "somelib", - }, - { - args: []string{"../lib1", "../lib2"}, - pkgs: []*load.Package{pkgImportPath("gopkg.in/lib1"), pkgImportPath("gopkg.in/lib2")}, - expected: "gopkg.in-lib1,gopkg.in-lib2", - }, - { - args: []string{"./..."}, - pkgs: []*load.Package{ - pkgImportPath("gopkg.in/dir/lib1"), - pkgImportPath("gopkg.in/lib2"), - pkgImportPath("gopkg.in/lib3"), - }, - expected: "gopkg.in", - rootedAt: "gopkg.in", - }, - { - args: []string{"std", "../lib2"}, - pkgs: []*load.Package{}, - expectErr: true, - }, - { - args: []string{"all", "./"}, - pkgs: []*load.Package{}, - expectErr: true, - }, - { - args: []string{"cmd", "fmt"}, - pkgs: []*load.Package{}, - expectErr: true, - }, - } - for _, data := range testData { - func() { - if data.rootedAt != "" { - tmpGopath, err := ioutil.TempDir("", "gopath") - if err != nil { - t.Fatal(err) - } - oldGopath := cfg.BuildContext.GOPATH - defer func() { - cfg.BuildContext.GOPATH = oldGopath - os.Chdir(base.Cwd) - err := os.RemoveAll(tmpGopath) - if err != nil { - t.Error(err) - } - }() - root := filepath.Join(tmpGopath, "src", data.rootedAt) - err = os.MkdirAll(root, 0755) - if err != nil { - t.Fatal(err) - } - cfg.BuildContext.GOPATH = tmpGopath - os.Chdir(root) - } - computed, err := libname(data.args, data.pkgs) - if err != nil { - if !data.expectErr { - t.Errorf("libname returned an error %q, expected a name", err.Error()) - } - } else if data.expectErr { - t.Errorf("libname returned %q, expected an error", computed) - } else { - expected := prefix + data.expected + suffix - if expected != computed { - t.Errorf("libname returned %q, expected %q", computed, expected) - } - } - }() - } -} diff --git a/src/cmd/go/run.go b/src/cmd/go/run.go index 5e35dfbb78f..398a298fdc9 100644 --- a/src/cmd/go/run.go +++ b/src/cmd/go/run.go @@ -5,15 +5,17 @@ package main import ( - "cmd/go/internal/base" - "cmd/go/internal/cfg" - "cmd/go/internal/load" - "cmd/go/internal/str" "fmt" "os" "os/exec" "runtime" "strings" + + "cmd/go/internal/base" + "cmd/go/internal/cfg" + "cmd/go/internal/load" + "cmd/go/internal/str" + "cmd/go/internal/work" ) var execCmd []string // -exec flag, for run and test @@ -59,8 +61,8 @@ See also: go build. func init() { cmdRun.Run = runRun // break init loop - addBuildFlags(cmdRun) - cmdRun.Flag.Var((*stringsFlag)(&execCmd), "exec", "") + work.AddBuildFlags(cmdRun) + cmdRun.Flag.Var((*base.StringsFlag)(&execCmd), "exec", "") } func printStderr(args ...interface{}) (int, error) { @@ -68,11 +70,11 @@ func printStderr(args ...interface{}) (int, error) { } func runRun(cmd *base.Command, args []string) { - instrumentInit() - buildModeInit() - var b builder - b.init() - b.print = printStderr + work.InstrumentInit() + work.BuildModeInit() + var b work.Builder + b.Init() + b.Print = printStderr i := 0 for i < len(args) && strings.HasSuffix(args[i], ".go") { i++ @@ -126,17 +128,17 @@ func runRun(cmd *base.Command, args []string) { base.Fatalf("go run: no suitable source files%s", hint) } p.Internal.ExeName = src[:len(src)-len(".go")] // name temporary executable for first go file - a1 := b.action(modeBuild, modeBuild, p) - a := &action{f: (*builder).runProgram, args: cmdArgs, deps: []*action{a1}} - b.do(a) + a1 := b.Action(work.ModeBuild, work.ModeBuild, p) + a := &work.Action{Func: buildRunProgram, Args: cmdArgs, Deps: []*work.Action{a1}} + b.Do(a) } -// runProgram is the action for running a binary that has already +// buildRunProgram is the action for running a binary that has already // been compiled. We ignore exit status. -func (b *builder) runProgram(a *action) error { - cmdline := str.StringList(findExecCmd(), a.deps[0].target, a.args) +func buildRunProgram(b *work.Builder, a *work.Action) error { + cmdline := str.StringList(findExecCmd(), a.Deps[0].Target, a.Args) if cfg.BuildN || cfg.BuildX { - b.showcmd("", "%s", strings.Join(cmdline, " ")) + b.Showcmd("", "%s", strings.Join(cmdline, " ")) if cfg.BuildN { return nil } diff --git a/src/cmd/go/test.go b/src/cmd/go/test.go index 301ad7faaa3..c17507041e6 100644 --- a/src/cmd/go/test.go +++ b/src/cmd/go/test.go @@ -10,6 +10,7 @@ import ( "cmd/go/internal/cfg" "cmd/go/internal/load" "cmd/go/internal/str" + "cmd/go/internal/work" "errors" "fmt" "go/ast" @@ -409,8 +410,8 @@ func runTest(cmd *base.Command, args []string) { findExecCmd() // initialize cached result - instrumentInit() - buildModeInit() + work.InstrumentInit() + work.BuildModeInit() pkgs := load.PackagesForBuild(pkgArgs) if len(pkgs) == 0 { base.Fatalf("no packages to test") @@ -454,8 +455,8 @@ func runTest(cmd *base.Command, args []string) { testC = true } - var b builder - b.init() + var b work.Builder + b.Init() if cfg.BuildI { cfg.BuildV = testV @@ -497,18 +498,18 @@ func runTest(cmd *base.Command, args []string) { } sort.Strings(all) - a := &action{} + a := &work.Action{} for _, p := range load.PackagesForBuild(all) { - a.deps = append(a.deps, b.action(modeInstall, modeInstall, p)) + a.Deps = append(a.Deps, b.Action(work.ModeInstall, work.ModeInstall, p)) } - b.do(a) - if !testC || a.failed { + b.Do(a) + if !testC || a.Failed { return } - b.init() + b.Init() } - var builds, runs, prints []*action + var builds, runs, prints []*work.Action if testCoverPaths != nil { // Load packages that were asked about for coverage. @@ -570,13 +571,13 @@ func runTest(cmd *base.Command, args []string) { } // Ultimately the goal is to print the output. - root := &action{deps: prints} + root := &work.Action{Deps: prints} // Force the printing of results to happen in order, // one at a time. for i, a := range prints { if i > 0 { - a.deps = append(a.deps, prints[i-1]) + a.Deps = append(a.Deps, prints[i-1]) } } @@ -586,9 +587,9 @@ func runTest(cmd *base.Command, args []string) { // Later runs must wait for the previous run's print. for i, run := range runs { if i == 0 { - run.deps = append(run.deps, builds...) + run.Deps = append(run.Deps, builds...) } else { - run.deps = append(run.deps, prints[i-1]) + run.Deps = append(run.Deps, prints[i-1]) } } } @@ -600,26 +601,26 @@ func runTest(cmd *base.Command, args []string) { okBuild[p] = true } warned := false - for _, a := range actionList(root) { - if a.p == nil || okBuild[a.p] { + for _, a := range work.ActionList(root) { + if a.Package == nil || okBuild[a.Package] { continue } - okBuild[a.p] = true // warn at most once + okBuild[a.Package] = true // warn at most once // Don't warn about packages being rebuilt because of // things like coverage analysis. - for _, p1 := range a.p.Internal.Imports { + for _, p1 := range a.Package.Internal.Imports { if p1.Internal.Fake { - a.p.Internal.Fake = true + a.Package.Internal.Fake = true } } - if a.f != nil && !okBuild[a.p] && !a.p.Internal.Fake && !a.p.Internal.Local { + if a.Func != nil && !okBuild[a.Package] && !a.Package.Internal.Fake && !a.Package.Internal.Local { if !warned { fmt.Fprintf(os.Stderr, "warning: building out-of-date packages:\n") warned = true } - fmt.Fprintf(os.Stderr, "\t%s\n", a.p.ImportPath) + fmt.Fprintf(os.Stderr, "\t%s\n", a.Package.ImportPath) } } if warned { @@ -637,7 +638,7 @@ func runTest(cmd *base.Command, args []string) { fmt.Fprintf(os.Stderr, "installing these packages with 'go test %s-i%s' will speed future tests.\n\n", extraOpts, args) } - b.do(root) + b.Do(root) } var windowsBadWords = []string{ @@ -647,11 +648,11 @@ var windowsBadWords = []string{ "update", } -func builderTest(b *builder, p *load.Package) (buildAction, runAction, printAction *action, err error) { +func builderTest(b *work.Builder, p *load.Package) (buildAction, runAction, printAction *work.Action, err error) { if len(p.TestGoFiles)+len(p.XTestGoFiles) == 0 { - build := b.action(modeBuild, modeBuild, p) - run := &action{p: p, deps: []*action{build}} - print := &action{f: builderNoTest, p: p, deps: []*action{run}} + build := b.Action(work.ModeBuild, work.ModeBuild, p) + run := &work.Action{Package: p, Deps: []*work.Action{build}} + print := &work.Action{Func: builderNoTest, Package: p, Deps: []*work.Action{run}} return build, run, print, nil } @@ -736,12 +737,12 @@ func builderTest(b *builder, p *load.Package) (buildAction, runAction, printActi // $WORK/unicode/utf8/_test/unicode/utf8.a. // We write the external test package archive to // $WORK/unicode/utf8/_test/unicode/utf8_test.a. - testDir := filepath.Join(b.work, filepath.FromSlash(p.ImportPath+"/_test")) - ptestObj := buildToolchain.pkgpath(testDir, p) + testDir := filepath.Join(b.WorkDir, filepath.FromSlash(p.ImportPath+"/_test")) + ptestObj := work.BuildToolchain.Pkgpath(testDir, p) // Create the directory for the .a files. ptestDir, _ := filepath.Split(ptestObj) - if err := b.mkdir(ptestDir); err != nil { + if err := b.Mkdir(ptestDir); err != nil { return nil, nil, nil, err } @@ -898,7 +899,7 @@ func builderTest(b *builder, p *load.Package) (buildAction, runAction, printActi if cfg.BuildContext.GOOS == "darwin" { if cfg.BuildContext.GOARCH == "arm" || cfg.BuildContext.GOARCH == "arm64" { t.IsIOS = true - t.NeedCgo = true + t.NeedOS = true } } if t.TestMain == nil { @@ -922,24 +923,24 @@ func builderTest(b *builder, p *load.Package) (buildAction, runAction, printActi load.ComputeStale(pmain) if ptest != p { - a := b.action(modeBuild, modeBuild, ptest) - a.objdir = testDir + string(filepath.Separator) + "_obj_test" + string(filepath.Separator) - a.objpkg = ptestObj - a.target = ptestObj - a.link = false + a := b.Action(work.ModeBuild, work.ModeBuild, ptest) + a.Objdir = testDir + string(filepath.Separator) + "_obj_test" + string(filepath.Separator) + a.Objpkg = ptestObj + a.Target = ptestObj + a.Link = false } if pxtest != nil { - a := b.action(modeBuild, modeBuild, pxtest) - a.objdir = testDir + string(filepath.Separator) + "_obj_xtest" + string(filepath.Separator) - a.objpkg = buildToolchain.pkgpath(testDir, pxtest) - a.target = a.objpkg + a := b.Action(work.ModeBuild, work.ModeBuild, pxtest) + a.Objdir = testDir + string(filepath.Separator) + "_obj_xtest" + string(filepath.Separator) + a.Objpkg = work.BuildToolchain.Pkgpath(testDir, pxtest) + a.Target = a.Objpkg } - a := b.action(modeBuild, modeBuild, pmain) - a.objdir = testDir + string(filepath.Separator) - a.objpkg = filepath.Join(testDir, "main.a") - a.target = filepath.Join(testDir, testBinary) + cfg.ExeSuffix + a := b.Action(work.ModeBuild, work.ModeBuild, pmain) + a.Objdir = testDir + string(filepath.Separator) + a.Objpkg = filepath.Join(testDir, "main.a") + a.Target = filepath.Join(testDir, testBinary) + cfg.ExeSuffix if cfg.Goos == "windows" { // There are many reserved words on Windows that, // if used in the name of an executable, cause Windows @@ -965,7 +966,7 @@ func builderTest(b *builder, p *load.Package) (buildAction, runAction, printActi // we could just do this always on Windows. for _, bad := range windowsBadWords { if strings.Contains(testBinary, bad) { - a.target = filepath.Join(testDir, "test.test") + cfg.ExeSuffix + a.Target = filepath.Join(testDir, "test.test") + cfg.ExeSuffix break } } @@ -981,33 +982,33 @@ func builderTest(b *builder, p *load.Package) (buildAction, runAction, printActi target = filepath.Join(base.Cwd, target) } } - buildAction = &action{ - f: (*builder).install, - deps: []*action{buildAction}, - p: pmain, - target: target, + buildAction = &work.Action{ + Func: work.BuildInstallFunc, + Deps: []*work.Action{buildAction}, + Package: pmain, + Target: target, } runAction = buildAction // make sure runAction != nil even if not running test } if testC { - printAction = &action{p: p, deps: []*action{runAction}} // nop + printAction = &work.Action{Package: p, Deps: []*work.Action{runAction}} // nop } else { // run test - runAction = &action{ - f: builderRunTest, - deps: []*action{buildAction}, - p: p, - ignoreFail: true, + runAction = &work.Action{ + Func: builderRunTest, + Deps: []*work.Action{buildAction}, + Package: p, + IgnoreFail: true, } - cleanAction := &action{ - f: builderCleanTest, - deps: []*action{runAction}, - p: p, + cleanAction := &work.Action{ + Func: builderCleanTest, + Deps: []*work.Action{runAction}, + Package: p, } - printAction = &action{ - f: builderPrintTest, - deps: []*action{cleanAction}, - p: p, + printAction = &work.Action{ + Func: builderPrintTest, + Deps: []*work.Action{cleanAction}, + Package: p, } } @@ -1060,7 +1061,7 @@ func recompileForTest(pmain, preal, ptest *load.Package, testDir string) { } } - // Update p.deps and p.Internal.Imports to use at test copies. + // Update p.Deps and p.Internal.Imports to use at test copies. for i, dep := range p.Internal.Deps { if p1 := testCopy[dep]; p1 != nil && p1 != dep { split() @@ -1105,27 +1106,27 @@ func declareCoverVars(importPath string, files ...string) map[string]*load.Cover var noTestsToRun = []byte("\ntesting: warning: no tests to run\n") // builderRunTest is the action for running a test binary. -func builderRunTest(b *builder, a *action) error { - args := str.StringList(findExecCmd(), a.deps[0].target, testArgs) - a.testOutput = new(bytes.Buffer) +func builderRunTest(b *work.Builder, a *work.Action) error { + args := str.StringList(findExecCmd(), a.Deps[0].Target, testArgs) + a.TestOutput = new(bytes.Buffer) if cfg.BuildN || cfg.BuildX { - b.showcmd("", "%s", strings.Join(args, " ")) + b.Showcmd("", "%s", strings.Join(args, " ")) if cfg.BuildN { return nil } } - if a.failed { + if a.Failed { // We were unable to build the binary. - a.failed = false - fmt.Fprintf(a.testOutput, "FAIL\t%s [build failed]\n", a.p.ImportPath) + a.Failed = false + fmt.Fprintf(a.TestOutput, "FAIL\t%s [build failed]\n", a.Package.ImportPath) base.SetExitStatus(1) return nil } cmd := exec.Command(args[0], args[1:]...) - cmd.Dir = a.p.Dir + cmd.Dir = a.Package.Dir cmd.Env = envForDir(cmd.Dir, cfg.OrigEnv) var buf bytes.Buffer if testStreamOutput { @@ -1138,7 +1139,7 @@ func builderRunTest(b *builder, a *action) error { // If there are any local SWIG dependencies, we want to load // the shared library from the build directory. - if a.p.UsesSwig() { + if a.Package.UsesSwig() { env := cmd.Env found := false prefix := "LD_LIBRARY_PATH=" @@ -1196,23 +1197,23 @@ func builderRunTest(b *builder, a *action) error { if err == nil { norun := "" if testShowPass { - a.testOutput.Write(out) + a.TestOutput.Write(out) } if bytes.HasPrefix(out, noTestsToRun[1:]) || bytes.Contains(out, noTestsToRun) { norun = " [no tests to run]" } - fmt.Fprintf(a.testOutput, "ok \t%s\t%s%s%s\n", a.p.ImportPath, t, coveragePercentage(out), norun) + fmt.Fprintf(a.TestOutput, "ok \t%s\t%s%s%s\n", a.Package.ImportPath, t, coveragePercentage(out), norun) return nil } base.SetExitStatus(1) if len(out) > 0 { - a.testOutput.Write(out) + a.TestOutput.Write(out) // assume printing the test binary's exit status is superfluous } else { - fmt.Fprintf(a.testOutput, "%s\n", err) + fmt.Fprintf(a.TestOutput, "%s\n", err) } - fmt.Fprintf(a.testOutput, "FAIL\t%s\t%s\n", a.p.ImportPath, t) + fmt.Fprintf(a.TestOutput, "FAIL\t%s\t%s\n", a.Package.ImportPath, t) return nil } @@ -1237,28 +1238,28 @@ func coveragePercentage(out []byte) string { } // builderCleanTest is the action for cleaning up after a test. -func builderCleanTest(b *builder, a *action) error { +func builderCleanTest(b *work.Builder, a *work.Action) error { if cfg.BuildWork { return nil } - run := a.deps[0] - testDir := filepath.Join(b.work, filepath.FromSlash(run.p.ImportPath+"/_test")) + run := a.Deps[0] + testDir := filepath.Join(b.WorkDir, filepath.FromSlash(run.Package.ImportPath+"/_test")) os.RemoveAll(testDir) return nil } // builderPrintTest is the action for printing a test result. -func builderPrintTest(b *builder, a *action) error { - clean := a.deps[0] - run := clean.deps[0] - os.Stdout.Write(run.testOutput.Bytes()) - run.testOutput = nil +func builderPrintTest(b *work.Builder, a *work.Action) error { + clean := a.Deps[0] + run := clean.Deps[0] + os.Stdout.Write(run.TestOutput.Bytes()) + run.TestOutput = nil return nil } // builderNoTest is the action for testing a package with no test files. -func builderNoTest(b *builder, a *action) error { - fmt.Printf("? \t%s\t[no test files]\n", a.p.ImportPath) +func builderNoTest(b *work.Builder, a *work.Action) error { + fmt.Printf("? \t%s\t[no test files]\n", a.Package.ImportPath) return nil } diff --git a/src/cmd/go/testflag.go b/src/cmd/go/testflag.go index 28682696ee8..4f519a4af69 100644 --- a/src/cmd/go/testflag.go +++ b/src/cmd/go/testflag.go @@ -5,13 +5,16 @@ package main import ( - "cmd/go/internal/base" - "cmd/go/internal/cfg" "flag" "fmt" "os" "strconv" "strings" + + "cmd/go/internal/base" + "cmd/go/internal/cfg" + "cmd/go/internal/str" + "cmd/go/internal/work" ) // The flag handling part of go test is large and distracting. @@ -66,7 +69,7 @@ var testFlagDefn = []*testFlagSpec{ // add build flags to testFlagDefn func init() { var cmd base.Command - addBuildFlags(&cmd) + work.AddBuildFlags(&cmd) cmd.Flag.VisitAll(func(f *flag.Flag) { if f.Name == "v" { // test overrides the build -v flag @@ -144,7 +147,7 @@ func testFlags(args []string) (packageNames, passToTest []string) { testO = value testNeedBinary = true case "exec": - execCmd, err = splitQuotedFields(value) + execCmd, err = str.SplitQuotedFields(value) if err != nil { base.Fatalf("invalid flag argument for -%s: %v", f.name, err) } diff --git a/src/cmd/go/vet.go b/src/cmd/go/vet.go index 202fd1ca9e2..01e391c8624 100644 --- a/src/cmd/go/vet.go +++ b/src/cmd/go/vet.go @@ -11,10 +11,11 @@ import ( "cmd/go/internal/cfg" "cmd/go/internal/load" "cmd/go/internal/str" + "cmd/go/internal/work" ) func init() { - addBuildFlags(cmdVet) + work.AddBuildFlags(cmdVet) } var cmdVet = &base.Command{