Commit 3c667ef4 authored by Russ Cox's avatar Russ Cox

cmd/go: split out cmd/go/internal/work

This is one CL in a long sequence of changes to break up the
go command from one package into a plausible group of packages.

This sequence is concerned only with moving code, not changing
or cleaning up code. There will still be more cleanup after this sequence.

The entire sequence will be submitted together: it is not a goal
for the tree to build at every step.

For #18653.

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