Commit b03a5f66 authored by Russ Cox's avatar Russ Cox

cmd/go: fixes

* Install tools into tool dir always
  (Fixes issue 3049.  Fixes issue 2868.  Fixes issue 2925.)
* Make packages depend on compiler, linker (Fixes issue 3036.)
* Do not recompile packages across roots (Fixes issue 3149.)
* Allow use of binary-only packages (Fixes issue 2775.)
* Avoid duplicate cgo dependencies (Fixes issue 3001.)
* Show less in go get -x.  (Fixes issue 2926.)
* Do not force repo root for existing checkout (Fixes issue 2969.)
* Show full syntax error list always (Fixes issue 2811.)
* Clean arguments before processing (Fixes issue 3034.)
* Add flags for compiler, linker arguments (Fixes issue 2996.)
* Pass flags in make.bash (Fixes issue 3091.)
* Unify build flags, defined in one place.
* Clean up error messages (Fixes issue 3075.  Fixes issue 2923.)
* Support local import paths (Fixes issue 3118.)
* Allow top-level package outside $GOPATH (Fixes issue 3009.)

In addition to these fixes, all commands now take a list of
go files as a way to specify a single package, just as go build and
go run always have.  This means you can:

        go list -json x.go
        go fix x.go
        go vet x.go
        go test x_test.go

Preliminary tests in test.bash.
Mainly testing things that the ordinary build does not.
I don't mind if the script doesn't run on Windows.

I expect that gccgo support is now broken, and I hope that
people will feel free to file issues and/or send CLs to fix it.  :-)

R=golang-dev, dsymonds, r, rogpeppe
CC=golang-dev
https://golang.org/cl/5708054
parent ebe1664d
...@@ -23,7 +23,7 @@ import ( ...@@ -23,7 +23,7 @@ import (
) )
var cmdBuild = &Command{ var cmdBuild = &Command{
UsageLine: "build [-a] [-n] [-o output] [-p n] [-v] [-x] [-work] [importpath... | gofiles...]", UsageLine: "build [-o output] [build flags] [packages]",
Short: "compile packages and dependencies", Short: "compile packages and dependencies",
Long: ` Long: `
Build compiles the packages named by the import paths, Build compiles the packages named by the import paths,
...@@ -33,25 +33,43 @@ If the arguments are a list of .go files, build treats them as a list ...@@ -33,25 +33,43 @@ If the arguments are a list of .go files, build treats them as a list
of source files specifying a single package. of source files specifying a single package.
When the command line specifies a single main package, When the command line specifies a single main package,
build writes the resulting executable to output (default a.out). build writes the resulting executable to output.
Otherwise build compiles the packages but discards the results, Otherwise build compiles the packages but discards the results,
serving only as a check that the packages can be built. serving only as a check that the packages can be built.
The -a flag forces rebuilding of packages that are already up-to-date. The -o flag specifies the output file name. If not specified, the
The -n flag prints the commands but does not run them. name is packagename.a (for a non-main package) or the base
The -v flag prints the names of packages as they are compiled. name of the first source file (for a main package).
The -x flag prints the commands.
The build flags are shared by the build, install, run, and test commands:
The -o flag specifies the output file name.
It is an error to use -o when the command line specifies multiple packages. -a
force rebuilding of packages that are already up-to-date.
The -p flag specifies the number of builds that can be run in parallel. -n
The default is the number of CPUs available. print the commands but does not run them.
-p n
The -work flag causes build to print the name of the temporary work the number of builds that can be run in parallel.
directory and not delete it when exiting. The default is the number of CPUs available.
-v
For more about import paths, see 'go help importpath'. print the names of packages as they are compiled.
-work
print the name of the temporary work directory and
do not delete it when exiting.
-x
print the commands.
-gccgoflags 'arg list'
arguments to pass on each gccgo compiler/linker invocation
-gcflags 'arg list'
arguments to pass on each 5g, 6g, or 8g compiler invocation
-ldflags 'flag list'
arguments to pass on each 5l, 6l, or 8l linker invocation
-tags 'tag list'
a list of build tags to consider satisfied during the build.
See the documentation for the go/build package for
more information about build tags.
For more about specifying packages, see 'go help packages'.
See also: go install, go get, go clean. See also: go install, go get, go clean.
`, `,
...@@ -73,9 +91,12 @@ var buildP = runtime.NumCPU() // -p flag ...@@ -73,9 +91,12 @@ var buildP = runtime.NumCPU() // -p flag
var buildV bool // -v flag var buildV bool // -v flag
var buildX bool // -x flag var buildX bool // -x flag
var buildO = cmdBuild.Flag.String("o", "", "output file") var buildO = cmdBuild.Flag.String("o", "", "output file")
var buildWork bool // -work flag var buildWork bool // -work flag
var buildGcflags []string // -gcflags flag
var buildLdflags []string // -ldflags flag
var buildGccgoflags []string // -gccgoflags flag
var buildContext = build.DefaultContext var buildContext = build.Default
// addBuildFlags adds the flags common to the build and install commands. // addBuildFlags adds the flags common to the build and install commands.
func addBuildFlags(cmd *Command) { func addBuildFlags(cmd *Command) {
...@@ -85,20 +106,16 @@ func addBuildFlags(cmd *Command) { ...@@ -85,20 +106,16 @@ func addBuildFlags(cmd *Command) {
cmd.Flag.BoolVar(&buildV, "v", false, "") cmd.Flag.BoolVar(&buildV, "v", false, "")
cmd.Flag.BoolVar(&buildX, "x", false, "") cmd.Flag.BoolVar(&buildX, "x", false, "")
cmd.Flag.BoolVar(&buildWork, "work", false, "") cmd.Flag.BoolVar(&buildWork, "work", false, "")
cmd.Flag.Var((*stringsFlag)(&buildGcflags), "gcflags", "")
// TODO(rsc): This -t flag is used by buildscript.sh but cmd.Flag.Var((*stringsFlag)(&buildLdflags), "ldflags", "")
// not documented. Should be documented but the cmd.Flag.Var((*stringsFlag)(&buildGccgoflags), "gccgoflags", "")
// usage lines are getting too long. Probably need to say cmd.Flag.Var((*stringsFlag)(&buildContext.BuildTags), "tags", "")
// that these flags are applicable to every command and
// document them in one help message instead of on every
// command's help message.
cmd.Flag.Var((*stringsFlag)(&buildContext.BuildTags), "t", "")
} }
type stringsFlag []string type stringsFlag []string
func (v *stringsFlag) Set(s string) error { func (v *stringsFlag) Set(s string) error {
*v = append(*v, s) *v = strings.Fields(s)
return nil return nil
} }
...@@ -110,17 +127,11 @@ func runBuild(cmd *Command, args []string) { ...@@ -110,17 +127,11 @@ func runBuild(cmd *Command, args []string) {
var b builder var b builder
b.init() b.init()
var pkgs []*Package pkgs := packagesForBuild(args)
if len(args) > 0 && strings.HasSuffix(args[0], ".go") {
pkg := goFilesPackage(args, "")
pkgs = append(pkgs, pkg)
} else {
pkgs = packagesForBuild(args)
}
if len(pkgs) == 1 && pkgs[0].Name == "main" && *buildO == "" { if len(pkgs) == 1 && pkgs[0].Name == "main" && *buildO == "" {
_, *buildO = path.Split(pkgs[0].ImportPath) _, *buildO = path.Split(pkgs[0].ImportPath)
if b.goos == "windows" { if goos == "windows" {
*buildO += ".exe" *buildO += ".exe"
} }
} }
...@@ -145,24 +156,14 @@ func runBuild(cmd *Command, args []string) { ...@@ -145,24 +156,14 @@ func runBuild(cmd *Command, args []string) {
} }
var cmdInstall = &Command{ var cmdInstall = &Command{
UsageLine: "install [-a] [-n] [-p n] [-v] [-x] [-work] [importpath...]", UsageLine: "install [build flags] [packages]",
Short: "compile and install packages and dependencies", Short: "compile and install packages and dependencies",
Long: ` Long: `
Install compiles and installs the packages named by the import paths, Install compiles and installs the packages named by the import paths,
along with their dependencies. along with their dependencies.
The -a flag forces reinstallation of packages that are already up-to-date. For more about the build flags, see 'go help build'.
The -n flag prints the commands but does not run them. For more about specifying packages, see 'go help packages'.
The -v flag prints the names of packages as they are compiled.
The -x flag prints the commands.
The -p flag specifies the number of builds that can be run in parallel.
The default is the number of CPUs available.
The -work flag causes build to print the name of the temporary work
directory and not delete it when exiting.
For more about import paths, see 'go help importpath'.
See also: go build, go get, go clean. See also: go build, go get, go clean.
`, `,
...@@ -171,6 +172,13 @@ See also: go build, go get, go clean. ...@@ -171,6 +172,13 @@ See also: go build, go get, go clean.
func runInstall(cmd *Command, args []string) { func runInstall(cmd *Command, args []string) {
pkgs := packagesForBuild(args) pkgs := packagesForBuild(args)
for _, p := range pkgs {
if p.Target == "" && (!p.Standard || p.ImportPath != "unsafe") {
errorf("go install: no install location for %s", p.ImportPath)
}
}
exitIfErrors()
var b builder var b builder
b.init() b.init()
a := &action{} a := &action{}
...@@ -180,16 +188,32 @@ func runInstall(cmd *Command, args []string) { ...@@ -180,16 +188,32 @@ func runInstall(cmd *Command, args []string) {
b.do(a) b.do(a)
} }
// Global build parameters (used during package load)
var (
goarch string
goos string
archChar string
exeSuffix string
)
func init() {
goarch = buildContext.GOARCH
goos = buildContext.GOOS
if goos == "windows" {
exeSuffix = ".exe"
}
var err error
archChar, err = build.ArchChar(goarch)
if err != nil {
fatalf("%s", err)
}
}
// A builder holds global state about a build. // A builder holds global state about a build.
// It does not hold per-package state, because eventually we will // It does not hold per-package state, because we
// build packages in parallel, and the builder will be 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) work string // the temporary work directory (ends in filepath.Separator)
arch string // e.g., "6"
goarch string // the $GOARCH
goos string // the $GOOS
exe string // the executable suffix - "" or ".exe"
gcflags []string // additional flags for Go compiler
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
print func(args ...interface{}) (int, error) print func(args ...interface{}) (int, error)
...@@ -243,26 +267,25 @@ const ( ...@@ -243,26 +267,25 @@ const (
) )
var ( var (
gobin = build.Path[0].BinDir() goroot = filepath.Clean(runtime.GOROOT())
goroot = build.Path[0].Path gobin = defaultGobin()
gorootSrcPkg = filepath.Join(goroot, "src/pkg")
gorootPkg = filepath.Join(goroot, "pkg")
gorootSrc = filepath.Join(goroot, "src")
) )
func defaultGobin() string {
if s := os.Getenv("GOBIN"); s != "" {
return s
}
return filepath.Join(goroot, "bin")
}
func (b *builder) init() { func (b *builder) init() {
var err error var err error
b.print = fmt.Print b.print = fmt.Print
b.actionCache = make(map[cacheKey]*action) b.actionCache = make(map[cacheKey]*action)
b.mkdirCache = make(map[string]bool) b.mkdirCache = make(map[string]bool)
b.goarch = buildContext.GOARCH
b.goos = buildContext.GOOS
if b.goos == "windows" {
b.exe = ".exe"
}
b.gcflags = strings.Fields(os.Getenv("GCFLAGS"))
b.arch, err = build.ArchChar(b.goarch)
if err != nil {
fatalf("%s", err)
}
if buildN { if buildN {
b.work = "$WORK" b.work = "$WORK"
...@@ -281,21 +304,26 @@ func (b *builder) init() { ...@@ -281,21 +304,26 @@ func (b *builder) init() {
} }
// goFilesPackage creates a package for building a collection of Go files // goFilesPackage creates a package for building a collection of Go files
// (typically named on the command line). If target is given, the package // (typically named on the command line). The target is named p.a for
// target is target. Otherwise, the target is named p.a for
// package p or named after the first Go file for package main. // package p or named after the first Go file for package main.
func goFilesPackage(gofiles []string, target string) *Package { func goFilesPackage(gofiles []string) *Package {
// TODO: Remove this restriction. // TODO: Remove this restriction.
for _, f := range gofiles { for _, f := range gofiles {
if !strings.HasSuffix(f, ".go") || strings.Contains(f, "/") || strings.Contains(f, string(filepath.Separator)) { if !strings.HasSuffix(f, ".go") {
fatalf("named files must be in current directory and .go files") fatalf("named files must be .go files")
} }
} }
// Synthesize fake "directory" that only shows those two files, var stk importStack
ctxt := buildContext
ctxt.UseAllFiles = true
// Synthesize fake "directory" that only shows the named files,
// to make it look like this is a standard package or // to make it look like this is a standard package or
// command directory. // command directory. So that local imports resolve
var dir []os.FileInfo // consistently, the files must all be in the same directory.
var dirent []os.FileInfo
var dir string
for _, file := range gofiles { for _, file := range gofiles {
fi, err := os.Stat(file) fi, err := os.Stat(file)
if err != nil { if err != nil {
...@@ -304,36 +332,38 @@ func goFilesPackage(gofiles []string, target string) *Package { ...@@ -304,36 +332,38 @@ func goFilesPackage(gofiles []string, target string) *Package {
if fi.IsDir() { if fi.IsDir() {
fatalf("%s is a directory, should be a Go file", file) fatalf("%s is a directory, should be a Go file", file)
} }
dir = append(dir, fi) dir1, _ := filepath.Split(file)
} if dir == "" {
ctxt := buildContext dir = dir1
ctxt.ReadDir = func(string) ([]os.FileInfo, error) { return dir, nil } } else if dir != dir1 {
pwd, _ := os.Getwd() fatalf("named files must all be in one directory; have %s and %s", dir, dir1)
var stk importStack
pkg := scanPackage(&ctxt, &build.Tree{Path: "."}, "<command line>", "<command line>", pwd+"/.", &stk, true)
if pkg.Error != nil {
fatalf("%s", pkg.Error)
}
printed := map[error]bool{}
for _, err := range pkg.DepsErrors {
// Since these are errors in dependencies,
// the same error might show up multiple times,
// once in each package that depends on it.
// Only print each once.
if !printed[err] {
printed[err] = true
errorf("%s", err)
} }
dirent = append(dirent, fi)
} }
if target != "" { ctxt.ReadDir = func(string) ([]os.FileInfo, error) { return dirent, nil }
pkg.target = target
} else if pkg.Name == "main" { if !filepath.IsAbs(dir) {
pkg.target = gofiles[0][:len(gofiles[0])-len(".go")] dir = filepath.Join(cwd, dir)
} else {
pkg.target = pkg.Name + ".a"
} }
pkg.ImportPath = "_/" + pkg.target
exitIfErrors() bp, err := ctxt.ImportDir(dir, 0)
pkg := new(Package)
pkg.load(&stk, bp, err)
pkg.ImportPath = "command-line arguments"
if *buildO == "" {
if pkg.Name == "main" {
_, elem := filepath.Split(gofiles[0])
*buildO = elem[:len(elem)-len(".go")]
} else {
*buildO = pkg.Name + ".a"
}
}
pkg.target = ""
pkg.Target = ""
pkg.Stale = true
computeStale([]*Package{pkg})
return pkg return pkg
} }
...@@ -346,7 +376,7 @@ func (b *builder) action(mode buildMode, depMode buildMode, p *Package) *action ...@@ -346,7 +376,7 @@ func (b *builder) action(mode buildMode, depMode buildMode, p *Package) *action
return a return a
} }
a = &action{p: p, pkgdir: p.t.PkgDir()} a = &action{p: p, pkgdir: p.build.PkgRoot}
if p.pkgdir != "" { // overrides p.t if p.pkgdir != "" { // overrides p.t
a.pkgdir = p.pkgdir a.pkgdir = p.pkgdir
} }
...@@ -362,7 +392,7 @@ func (b *builder) action(mode buildMode, depMode buildMode, p *Package) *action ...@@ -362,7 +392,7 @@ func (b *builder) action(mode buildMode, depMode buildMode, p *Package) *action
// using cgo, to make sure we do not overwrite the binary while // using cgo, to make sure we do not overwrite the binary while
// a package is using it. If this is a cross-build, then the cgo we // a package is using it. If this is a cross-build, then the cgo we
// are writing is not the cgo we need to use. // are writing is not the cgo we need to use.
if b.goos == runtime.GOOS && b.goarch == runtime.GOARCH { if goos == runtime.GOOS && goarch == runtime.GOARCH {
if len(p.CgoFiles) > 0 || p.Standard && p.ImportPath == "runtime/cgo" { if len(p.CgoFiles) > 0 || p.Standard && p.ImportPath == "runtime/cgo" {
var stk importStack var stk importStack
p1 := loadPackage("cmd/cgo", &stk) p1 := loadPackage("cmd/cgo", &stk)
...@@ -388,15 +418,21 @@ func (b *builder) action(mode buildMode, depMode buildMode, p *Package) *action ...@@ -388,15 +418,21 @@ func (b *builder) action(mode buildMode, depMode buildMode, p *Package) *action
} }
} }
if !p.Stale && !buildA && p.target != "" { if !p.Stale && p.target != "" {
// p.Stale==false implies that p.target is up-to-date. // p.Stale==false implies that p.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.target a.target = p.target
return a return a
} }
a.objdir = filepath.Join(b.work, filepath.FromSlash(a.p.ImportPath+"/_obj")) + string(filepath.Separator) prefix := "obj"
a.objpkg = buildToolchain.pkgpath(b.work, a.p) if p.target == "" && p.Dir == p.ImportPath {
// Imported via local path. No permanent target.
mode = modeBuild
prefix = "local"
}
a.objdir = filepath.Join(b.work, prefix, a.p.ImportPath, "_obj") + string(filepath.Separator)
a.objpkg = buildToolchain.pkgpath(b.work+"/"+prefix, a.p, false)
a.link = p.Name == "main" a.link = p.Name == "main"
switch mode { switch mode {
...@@ -410,7 +446,7 @@ func (b *builder) action(mode buildMode, depMode buildMode, p *Package) *action ...@@ -410,7 +446,7 @@ func (b *builder) action(mode buildMode, depMode buildMode, p *Package) *action
if a.link { if a.link {
// An executable file. // An executable file.
// (This is the name of a temporary file.) // (This is the name of a temporary file.)
a.target = a.objdir + "a.out" + b.exe a.target = a.objdir + "a.out" + exeSuffix
} }
} }
...@@ -560,7 +596,7 @@ func (b *builder) build(a *action) error { ...@@ -560,7 +596,7 @@ func (b *builder) build(a *action) error {
// Run cgo. // Run cgo.
if len(a.p.CgoFiles) > 0 { if len(a.p.CgoFiles) > 0 {
// In a package using cgo, cgo compiles the C and assembly files with gcc. // In a package using cgo, cgo compiles the 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.
// In that case gcc only gets the gcc_* files. // In that case gcc only gets the gcc_* files.
...@@ -599,9 +635,32 @@ func (b *builder) build(a *action) error { ...@@ -599,9 +635,32 @@ func (b *builder) build(a *action) error {
// Prepare Go import path list. // Prepare Go import path list.
inc := b.includeArgs("-I", a.deps) inc := b.includeArgs("-I", a.deps)
// In what directory shall we run the Go compiler?
// We only pass absolute paths, so most of the time it doesn't matter.
// Default to the root directory.
// However, if the package contains local imports (./ or ../)
// then we need to run the compiler in a directory in the parallel
// tree of local package objects, so that those imports resolve to the
// compiled package objects.
gcdir := filepath.Clean("/")
for _, imp := range a.p.Imports {
if build.IsLocalImport(imp) {
dir := a.p.Dir
if filepath.Separator == '\\' {
// Avoid use of : on Windows.
dir = strings.Replace(dir, ":", "_", -1)
}
gcdir = filepath.Join(b.work, "local", dir)
if err := b.mkdir(gcdir); err != nil {
return err
}
break
}
}
// Compile Go. // Compile Go.
if len(gofiles) > 0 { if len(gofiles) > 0 {
if out, err := buildToolchain.gc(b, a.p, obj, inc, gofiles); err != nil { if out, err := buildToolchain.gc(b, a.p, obj, gcdir, inc, gofiles); err != nil {
return err return err
} else { } else {
objects = append(objects, out) objects = append(objects, out)
...@@ -611,31 +670,31 @@ func (b *builder) build(a *action) error { ...@@ -611,31 +670,31 @@ func (b *builder) build(a *action) error {
// Copy .h files named for goos or goarch or goos_goarch // Copy .h files named for goos or goarch or goos_goarch
// to names using GOOS and GOARCH. // to names using GOOS and GOARCH.
// For example, defs_linux_amd64.h becomes defs_GOOS_GOARCH.h. // For example, defs_linux_amd64.h becomes defs_GOOS_GOARCH.h.
_goos_goarch := "_" + b.goos + "_" + b.goarch + ".h" _goos_goarch := "_" + goos + "_" + goarch + ".h"
_goos := "_" + b.goos + ".h" _goos := "_" + goos + ".h"
_goarch := "_" + b.goarch + ".h" _goarch := "_" + goarch + ".h"
for _, file := range a.p.HFiles { for _, file := range a.p.HFiles {
switch { switch {
case strings.HasSuffix(file, _goos_goarch): case strings.HasSuffix(file, _goos_goarch):
targ := file[:len(file)-len(_goos_goarch)] + "_GOOS_GOARCH.h" targ := file[:len(file)-len(_goos_goarch)] + "_GOOS_GOARCH.h"
if err := b.copyFile(obj+targ, filepath.Join(a.p.Dir, file), 0666); err != nil { if err := b.copyFile(a, obj+targ, filepath.Join(a.p.Dir, file), 0666); err != nil {
return err return err
} }
case strings.HasSuffix(file, _goarch): case strings.HasSuffix(file, _goarch):
targ := file[:len(file)-len(_goarch)] + "_GOARCH.h" targ := file[:len(file)-len(_goarch)] + "_GOARCH.h"
if err := b.copyFile(obj+targ, filepath.Join(a.p.Dir, file), 0666); err != nil { if err := b.copyFile(a, obj+targ, filepath.Join(a.p.Dir, file), 0666); err != nil {
return err return err
} }
case strings.HasSuffix(file, _goos): case strings.HasSuffix(file, _goos):
targ := file[:len(file)-len(_goos)] + "_GOOS.h" targ := file[:len(file)-len(_goos)] + "_GOOS.h"
if err := b.copyFile(obj+targ, filepath.Join(a.p.Dir, file), 0666); err != nil { if err := b.copyFile(a, obj+targ, filepath.Join(a.p.Dir, file), 0666); err != nil {
return err return err
} }
} }
} }
for _, file := range cfiles { for _, file := range cfiles {
out := file[:len(file)-len(".c")] + "." + b.arch out := file[:len(file)-len(".c")] + "." + archChar
if err := buildToolchain.cc(b, a.p, obj, obj+out, file); err != nil { if err := buildToolchain.cc(b, a.p, obj, obj+out, file); err != nil {
return err return err
} }
...@@ -644,7 +703,7 @@ func (b *builder) build(a *action) error { ...@@ -644,7 +703,7 @@ func (b *builder) build(a *action) error {
// Assemble .s files. // Assemble .s files.
for _, file := range sfiles { for _, file := range sfiles {
out := file[:len(file)-len(".s")] + "." + b.arch out := file[:len(file)-len(".s")] + "." + archChar
if err := buildToolchain.asm(b, a.p, obj, obj+out, file); err != nil { if err := buildToolchain.asm(b, a.p, obj, obj+out, file); err != nil {
return err return err
} }
...@@ -701,7 +760,7 @@ func (b *builder) install(a *action) error { ...@@ -701,7 +760,7 @@ func (b *builder) install(a *action) error {
defer os.Remove(a1.target) defer os.Remove(a1.target)
} }
return b.copyFile(a.target, a1.target, perm) return b.copyFile(a, a.target, a1.target, perm)
} }
// includeArgs returns the -I or -L directory list for access // includeArgs returns the -I or -L directory list for access
...@@ -709,16 +768,16 @@ func (b *builder) install(a *action) error { ...@@ -709,16 +768,16 @@ func (b *builder) install(a *action) error {
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.work + "/obj": true, // handled later
build.Path[0].PkgDir(): true, // goroot gorootPkg: true,
"": true, // ignore empty strings "": true, // ignore empty strings
} }
// Look in the temporary space for results of test-specific actions. // Look in the temporary space for results of test-specific actions.
// 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 dir := a1.pkgdir; dir != a1.p.t.PkgDir() && !incMap[dir] { if dir := a1.pkgdir; dir != a1.p.build.PkgRoot && !incMap[dir] {
incMap[dir] = true incMap[dir] = true
inc = append(inc, flag, dir) inc = append(inc, flag, dir)
} }
...@@ -726,11 +785,11 @@ func (b *builder) includeArgs(flag string, all []*action) []string { ...@@ -726,11 +785,11 @@ 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.work+"/obj")
// Finally, look in the installed package directories for each action. // Finally, look in the installed package directories for each action.
for _, a1 := range all { for _, a1 := range all {
if dir := a1.pkgdir; dir == a1.p.t.PkgDir() && !incMap[dir] { if dir := a1.pkgdir; dir == a1.p.build.PkgRoot && !incMap[dir] {
if _, ok := buildToolchain.(gccgoToolchain); ok { if _, ok := buildToolchain.(gccgoToolchain); ok {
dir = filepath.Join(filepath.Dir(dir), "gccgo", filepath.Base(dir)) dir = filepath.Join(filepath.Dir(dir), "gccgo", filepath.Base(dir))
} }
...@@ -743,7 +802,7 @@ func (b *builder) includeArgs(flag string, all []*action) []string { ...@@ -743,7 +802,7 @@ func (b *builder) includeArgs(flag string, all []*action) []string {
} }
// copyFile is like 'cp src dst'. // copyFile is like 'cp src dst'.
func (b *builder) copyFile(dst, src string, perm os.FileMode) error { func (b *builder) copyFile(a *action, dst, src string, perm os.FileMode) error {
if buildN || buildX { if buildN || buildX {
b.showcmd("", "cp %s %s", src, dst) b.showcmd("", "cp %s %s", src, dst)
if buildN { if buildN {
...@@ -889,8 +948,7 @@ func (b *builder) showcmd(dir string, format string, args ...interface{}) { ...@@ -889,8 +948,7 @@ func (b *builder) showcmd(dir string, format string, args ...interface{}) {
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
pwd, _ := os.Getwd() if reldir := shortPath(dir); reldir != dir {
if reldir, err := filepath.Rel(pwd, dir); err == nil && len(reldir) < len(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)
} }
...@@ -901,6 +959,14 @@ func (b *builder) showOutput(dir, desc, out string) { ...@@ -901,6 +959,14 @@ func (b *builder) showOutput(dir, desc, out string) {
b.print(prefix, suffix) b.print(prefix, suffix)
} }
// shortPath returns an absolute or relative name for path, whatever is shorter.
func shortPath(path string) string {
if rel, err := filepath.Rel(cwd, path); err == nil && len(rel) < len(path) {
return rel
}
return path
}
// relPaths returns a copy of paths with absolute paths // relPaths returns a copy of paths with absolute paths
// made relative to the current directory if they would be shorter. // made relative to the current directory if they would be shorter.
func relPaths(paths []string) []string { func relPaths(paths []string) []string {
...@@ -926,7 +992,7 @@ var errPrintedOutput = errors.New("already printed output - no need to show erro ...@@ -926,7 +992,7 @@ var errPrintedOutput = errors.New("already printed output - no need to show erro
// run runs the command given by cmdline in the directory dir. // run runs the command given by cmdline in the directory dir.
// If the commnd fails, run prints information about the failure // If the commnd 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, cmdargs ...interface{}) error { func (b *builder) run(dir, shortenDir string, desc string, cmdargs ...interface{}) error {
out, err := b.runOut(dir, desc, cmdargs...) out, err := b.runOut(dir, desc, cmdargs...)
if len(out) > 0 { if len(out) > 0 {
if out[len(out)-1] != '\n' { if out[len(out)-1] != '\n' {
...@@ -935,7 +1001,7 @@ func (b *builder) run(dir string, desc string, cmdargs ...interface{}) error { ...@@ -935,7 +1001,7 @@ func (b *builder) run(dir string, desc string, cmdargs ...interface{}) error {
if desc == "" { if desc == "" {
desc = b.fmtcmd(dir, "%s", strings.Join(stringList(cmdargs...), " ")) desc = b.fmtcmd(dir, "%s", strings.Join(stringList(cmdargs...), " "))
} }
b.showOutput(dir, desc, string(out)) b.showOutput(shortenDir, desc, string(out))
if err != nil { if err != nil {
err = errPrintedOutput err = errPrintedOutput
} }
...@@ -1006,22 +1072,26 @@ func mkAbs(dir, f string) string { ...@@ -1006,22 +1072,26 @@ 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 *Package, obj string, importArgs []string, gofiles []string) (ofile string, err error) // The compiler runs in the directory dir.
gc(b *builder, p *Package, obj, dir string, importArgs []string, gofiles []string) (ofile string, 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 *Package, objdir, ofile, cfile string) error cc(b *builder, p *Package, objdir, ofile, cfile string) error
// asm runs the assembler in a specific directory on a specific file // asm runs the assembler in a specific directory on a specific file
// to generate the named output file. // to generate the named output file.
asm(b *builder, p *Package, obj, ofile, sfile string) error asm(b *builder, p *Package, obj, ofile, sfile string) error
// pkgpath creates the appropriate destination path for a package file. // pkgpath creates the appropriate destination path for a package file.
pkgpath(basedir string, p *Package) string pkgpath(basedir string, p *Package, install bool) 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 *Package, objDir, afile string, ofiles []string) error pack(b *builder, p *Package, objDir, afile string, ofiles []string) error
// ld runs the linker to create a package starting at mainpkg. // ld runs the linker to create a package starting at mainpkg.
ld(b *builder, p *Package, out string, allactions []*action, mainpkg string, ofiles []string) error ld(b *builder, p *Package, out string, allactions []*action, mainpkg string, ofiles []string) error
compiler() string
linker() string
} }
type goToolchain struct{} type goToolchain struct{}
...@@ -1030,6 +1100,7 @@ type gccgoToolchain struct{} ...@@ -1030,6 +1100,7 @@ type gccgoToolchain struct{}
var buildToolchain toolchain var buildToolchain toolchain
func init() { func init() {
// TODO(rsc): Decide how to trigger gccgo. Issue 3157.
if os.Getenv("GC") == "gccgo" { if os.Getenv("GC") == "gccgo" {
buildToolchain = gccgoToolchain{} buildToolchain = gccgoToolchain{}
} else { } else {
...@@ -1039,8 +1110,16 @@ func init() { ...@@ -1039,8 +1110,16 @@ func init() {
// The Go toolchain. // The Go toolchain.
func (goToolchain) gc(b *builder, p *Package, obj string, importArgs []string, gofiles []string) (ofile string, err error) { func (goToolchain) compiler() string {
out := "_go_." + b.arch return tool(archChar + "g")
}
func (goToolchain) linker() string {
return tool(archChar + "l")
}
func (goToolchain) gc(b *builder, p *Package, obj, dir string, importArgs []string, gofiles []string) (ofile string, err error) {
out := "_go_." + archChar
ofile = obj + out ofile = obj + out
gcargs := []string{"-p", p.ImportPath} gcargs := []string{"-p", p.ImportPath}
if p.Standard && p.ImportPath == "runtime" { if p.Standard && p.ImportPath == "runtime" {
...@@ -1049,20 +1128,24 @@ func (goToolchain) gc(b *builder, p *Package, obj string, importArgs []string, g ...@@ -1049,20 +1128,24 @@ func (goToolchain) gc(b *builder, p *Package, obj string, importArgs []string, g
gcargs = append(gcargs, "-+") gcargs = append(gcargs, "-+")
} }
args := stringList(tool(b.arch+"g"), "-o", ofile, b.gcflags, gcargs, importArgs) args := stringList(tool(archChar+"g"), "-o", ofile, buildGcflags, gcargs, importArgs)
for _, f := range gofiles { for _, f := range gofiles {
args = append(args, mkAbs(p.Dir, f)) args = append(args, mkAbs(p.Dir, f))
} }
return ofile, b.run(p.Dir, p.ImportPath, args) return ofile, b.run(dir, p.Dir, p.ImportPath, args)
} }
func (goToolchain) asm(b *builder, p *Package, obj, ofile, sfile string) error { func (goToolchain) asm(b *builder, p *Package, obj, ofile, sfile string) error {
sfile = mkAbs(p.Dir, sfile) sfile = mkAbs(p.Dir, sfile)
return b.run(p.Dir, p.ImportPath, tool(b.arch+"a"), "-I", obj, "-o", ofile, "-DGOOS_"+b.goos, "-DGOARCH_"+b.goarch, sfile) return b.run(p.Dir, p.Dir, p.ImportPath, tool(archChar+"a"), "-I", obj, "-o", ofile, "-DGOOS_"+goos, "-DGOARCH_"+goarch, sfile)
} }
func (goToolchain) pkgpath(basedir string, p *Package) string { func (goToolchain) pkgpath(basedir string, p *Package, install bool) string {
return filepath.Join(basedir, filepath.FromSlash(p.ImportPath+".a")) end := filepath.FromSlash(p.ImportPath + ".a")
if install {
return filepath.Join(basedir, buildContext.GOOS+"_"+buildContext.GOARCH, end)
}
return filepath.Join(basedir, end)
} }
func (goToolchain) pack(b *builder, p *Package, objDir, afile string, ofiles []string) error { func (goToolchain) pack(b *builder, p *Package, objDir, afile string, ofiles []string) error {
...@@ -1070,25 +1153,35 @@ func (goToolchain) pack(b *builder, p *Package, objDir, afile string, ofiles []s ...@@ -1070,25 +1153,35 @@ func (goToolchain) pack(b *builder, p *Package, objDir, afile string, ofiles []s
for _, f := range ofiles { for _, f := range ofiles {
absOfiles = append(absOfiles, mkAbs(objDir, f)) absOfiles = append(absOfiles, mkAbs(objDir, f))
} }
return b.run(p.Dir, p.ImportPath, tool("pack"), "grc", mkAbs(objDir, afile), absOfiles) return b.run(p.Dir, p.Dir, p.ImportPath, tool("pack"), "grc", mkAbs(objDir, afile), absOfiles)
} }
func (goToolchain) ld(b *builder, p *Package, out string, allactions []*action, mainpkg string, ofiles []string) error { func (goToolchain) ld(b *builder, p *Package, out string, allactions []*action, mainpkg string, ofiles []string) error {
importArgs := b.includeArgs("-L", allactions) importArgs := b.includeArgs("-L", allactions)
return b.run(p.Dir, p.ImportPath, tool(b.arch+"l"), "-o", out, importArgs, mainpkg) return b.run(p.Dir, p.Dir, p.ImportPath, tool(archChar+"l"), "-o", out, importArgs, buildLdflags, mainpkg)
} }
func (goToolchain) cc(b *builder, p *Package, objdir, ofile, cfile string) error { func (goToolchain) cc(b *builder, p *Package, objdir, ofile, cfile string) error {
inc := filepath.Join(goroot, "pkg", fmt.Sprintf("%s_%s", b.goos, b.goarch)) inc := filepath.Join(goroot, "pkg", fmt.Sprintf("%s_%s", goos, goarch))
cfile = mkAbs(p.Dir, cfile) cfile = mkAbs(p.Dir, cfile)
return b.run(p.Dir, p.ImportPath, tool(b.arch+"c"), "-FVw", return b.run(p.Dir, p.Dir, p.ImportPath, tool(archChar+"c"), "-FVw",
"-I", objdir, "-I", inc, "-o", ofile, "-I", objdir, "-I", inc, "-o", ofile,
"-DGOOS_"+b.goos, "-DGOARCH_"+b.goarch, cfile) "-DGOOS_"+goos, "-DGOARCH_"+goarch, cfile)
} }
// The Gccgo toolchain. // The Gccgo toolchain.
func (gccgoToolchain) gc(b *builder, p *Package, obj string, importArgs []string, gofiles []string) (ofile string, err error) { var gccgoBin, _ = exec.LookPath("gccgo")
func (gccgoToolchain) compiler() string {
return gccgoBin
}
func (gccgoToolchain) linker() string {
return gccgoBin
}
func (gccgoToolchain) gc(b *builder, p *Package, obj, dir string, importArgs []string, gofiles []string) (ofile string, err error) {
out := p.Name + ".o" out := p.Name + ".o"
ofile = obj + out ofile = obj + out
gcargs := []string{"-g"} gcargs := []string{"-g"}
...@@ -1099,21 +1192,23 @@ func (gccgoToolchain) gc(b *builder, p *Package, obj string, importArgs []string ...@@ -1099,21 +1192,23 @@ func (gccgoToolchain) gc(b *builder, p *Package, obj string, importArgs []string
gcargs = append(gcargs, "-fgo-prefix=go_"+p.ImportPath) gcargs = append(gcargs, "-fgo-prefix=go_"+p.ImportPath)
} }
} }
args := stringList("gccgo", importArgs, "-c", b.gcflags, gcargs, "-o", ofile) args := stringList("gccgo", importArgs, "-c", gcargs, "-o", ofile, buildGccgoflags)
for _, f := range gofiles { for _, f := range gofiles {
args = append(args, mkAbs(p.Dir, f)) args = append(args, mkAbs(p.Dir, f))
} }
return ofile, b.run(p.Dir, p.ImportPath, args) return ofile, b.run(dir, p.Dir, p.ImportPath, args)
} }
func (gccgoToolchain) asm(b *builder, p *Package, obj, ofile, sfile string) error { func (gccgoToolchain) asm(b *builder, p *Package, obj, ofile, sfile string) error {
sfile = mkAbs(p.Dir, sfile) sfile = mkAbs(p.Dir, sfile)
return b.run(p.Dir, p.ImportPath, "gccgo", "-I", obj, "-o", ofile, "-DGOOS_"+b.goos, "-DGOARCH_"+b.goarch, sfile) return b.run(p.Dir, p.Dir, p.ImportPath, "gccgo", "-I", obj, "-o", ofile, "-DGOOS_"+goos, "-DGOARCH_"+goarch, sfile)
} }
func (gccgoToolchain) pkgpath(basedir string, p *Package) string { func (gccgoToolchain) pkgpath(basedir string, p *Package, install bool) string {
afile := filepath.Join(basedir, filepath.FromSlash(p.ImportPath+".a")) // NOTE: Apparently gccgo does not distinguish different trees
// prepend "lib" to the basename // using goos_goarch, so install is ignored here.
afile := filepath.Join(basedir, "gccgo", filepath.FromSlash(p.ImportPath+".a"))
// 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))
} }
...@@ -1122,7 +1217,7 @@ func (gccgoToolchain) pack(b *builder, p *Package, objDir, afile string, ofiles ...@@ -1122,7 +1217,7 @@ func (gccgoToolchain) pack(b *builder, p *Package, objDir, afile string, ofiles
for _, f := range ofiles { for _, f := range ofiles {
absOfiles = append(absOfiles, mkAbs(objDir, f)) absOfiles = append(absOfiles, mkAbs(objDir, f))
} }
return b.run(p.Dir, p.ImportPath, "ar", "cru", mkAbs(objDir, afile), absOfiles) return b.run(p.Dir, p.Dir, p.ImportPath, "ar", "cru", mkAbs(objDir, afile), absOfiles)
} }
func (tools gccgoToolchain) ld(b *builder, p *Package, out string, allactions []*action, mainpkg string, ofiles []string) error { func (tools gccgoToolchain) ld(b *builder, p *Package, out string, allactions []*action, mainpkg string, ofiles []string) error {
...@@ -1140,26 +1235,27 @@ func (tools gccgoToolchain) ld(b *builder, p *Package, out string, allactions [] ...@@ -1140,26 +1235,27 @@ func (tools gccgoToolchain) ld(b *builder, p *Package, out string, allactions []
ldflags = append(ldflags, a.p.CgoLDFLAGS...) ldflags = append(ldflags, a.p.CgoLDFLAGS...)
} }
} }
return b.run(p.Dir, p.ImportPath, "gccgo", "-o", out, ofiles, "-Wl,-(", afiles, ldflags, "-Wl,-)")
return b.run(p.Dir, p.Dir, p.ImportPath, "gccgo", "-o", out, buildGccgoflags, ofiles, "-Wl,-(", afiles, ldflags, "-Wl,-)")
} }
func (gccgoToolchain) cc(b *builder, p *Package, objdir, ofile, cfile string) error { func (gccgoToolchain) cc(b *builder, p *Package, objdir, ofile, cfile string) error {
inc := filepath.Join(goroot, "pkg", fmt.Sprintf("%s_%s", b.goos, b.goarch)) inc := filepath.Join(goroot, "pkg", fmt.Sprintf("%s_%s", goos, goarch))
cfile = mkAbs(p.Dir, cfile) cfile = mkAbs(p.Dir, cfile)
return b.run(p.Dir, p.ImportPath, "gcc", "-Wall", "-g", return b.run(p.Dir, p.Dir, p.ImportPath, "gcc", "-Wall", "-g",
"-I", objdir, "-I", inc, "-o", ofile, "-I", objdir, "-I", inc, "-o", ofile,
"-DGOOS_"+b.goos, "-DGOARCH_"+b.goarch, "-c", cfile) "-DGOOS_"+goos, "-DGOARCH_"+goarch, "-c", cfile)
} }
// 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 *Package, out string, flags []string, cfile string) error { func (b *builder) gcc(p *Package, out string, flags []string, cfile string) error {
cfile = mkAbs(p.Dir, cfile) cfile = mkAbs(p.Dir, cfile)
return b.run(p.Dir, p.ImportPath, b.gccCmd(p.Dir), flags, "-o", out, "-c", cfile) return b.run(p.Dir, p.Dir, p.ImportPath, b.gccCmd(p.Dir), flags, "-o", out, "-c", cfile)
} }
// 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 *Package, out string, flags []string, obj []string) error { func (b *builder) gccld(p *Package, out string, flags []string, obj []string) error {
return b.run(p.Dir, p.ImportPath, b.gccCmd(p.Dir), "-o", out, obj, flags) return b.run(p.Dir, p.Dir, p.ImportPath, b.gccCmd(p.Dir), "-o", out, obj, flags)
} }
// gccCmd returns a gcc command line prefix // gccCmd returns a gcc command line prefix
...@@ -1169,10 +1265,10 @@ func (b *builder) gccCmd(objdir string) []string { ...@@ -1169,10 +1265,10 @@ func (b *builder) gccCmd(objdir string) []string {
// Definitely want -fPIC but on Windows gcc complains // Definitely want -fPIC but on Windows gcc complains
// "-fPIC ignored for target (all code is position independent)" // "-fPIC ignored for target (all code is position independent)"
if b.goos != "windows" { if goos != "windows" {
a = append(a, "-fPIC") a = append(a, "-fPIC")
} }
switch b.arch { switch archChar {
case "8": case "8":
a = append(a, "-m32") a = append(a, "-m32")
case "6": case "6":
...@@ -1181,7 +1277,7 @@ func (b *builder) gccCmd(objdir string) []string { ...@@ -1181,7 +1277,7 @@ func (b *builder) gccCmd(objdir string) []string {
// gcc-4.5 and beyond require explicit "-pthread" flag // gcc-4.5 and beyond require explicit "-pthread" flag
// for multithreading with pthread library. // for multithreading with pthread library.
if buildContext.CgoEnabled { if buildContext.CgoEnabled {
switch b.goos { switch goos {
case "windows": case "windows":
a = append(a, "-mthreads") a = append(a, "-mthreads")
default: default:
...@@ -1198,14 +1294,14 @@ func envList(key string) []string { ...@@ -1198,14 +1294,14 @@ func envList(key string) []string {
var cgoRe = regexp.MustCompile(`[/\\:]`) var cgoRe = regexp.MustCompile(`[/\\:]`)
func (b *builder) cgo(p *Package, cgoExe, obj string, gccfiles []string) (outGo, outObj []string, err error) { func (b *builder) cgo(p *Package, cgoExe, obj string, gccfiles []string) (outGo, outObj []string, err error) {
if b.goos != toolGOOS { if goos != toolGOOS {
return nil, nil, errors.New("cannot use cgo when compiling for a different operating system") return nil, nil, errors.New("cannot use cgo when compiling for a different operating system")
} }
cgoCFLAGS := stringList(envList("CGO_CFLAGS"), p.info.CgoCFLAGS) cgoCFLAGS := stringList(envList("CGO_CFLAGS"), p.CgoCFLAGS)
cgoLDFLAGS := stringList(envList("CGO_LDFLAGS"), p.info.CgoLDFLAGS) cgoLDFLAGS := stringList(envList("CGO_LDFLAGS"), p.CgoLDFLAGS)
if pkgs := p.info.CgoPkgConfig; len(pkgs) > 0 { if pkgs := p.CgoPkgConfig; len(pkgs) > 0 {
out, err := b.runOut(p.Dir, p.ImportPath, "pkg-config", "--cflags", pkgs) out, err := b.runOut(p.Dir, p.ImportPath, "pkg-config", "--cflags", pkgs)
if err != nil { if err != nil {
b.showOutput(p.Dir, "pkg-config --cflags "+strings.Join(pkgs, " "), string(out)) b.showOutput(p.Dir, "pkg-config --cflags "+strings.Join(pkgs, " "), string(out))
...@@ -1249,13 +1345,13 @@ func (b *builder) cgo(p *Package, cgoExe, obj string, gccfiles []string) (outGo, ...@@ -1249,13 +1345,13 @@ func (b *builder) cgo(p *Package, cgoExe, obj string, gccfiles []string) (outGo,
if _, ok := buildToolchain.(gccgoToolchain); ok { if _, ok := buildToolchain.(gccgoToolchain); ok {
cgoflags = append(cgoflags, "-gccgo") cgoflags = append(cgoflags, "-gccgo")
} }
if err := b.run(p.Dir, p.ImportPath, cgoExe, "-objdir", obj, cgoflags, "--", cgoCFLAGS, p.CgoFiles); err != nil { if err := b.run(p.Dir, p.Dir, p.ImportPath, cgoExe, "-objdir", obj, cgoflags, "--", cgoCFLAGS, p.CgoFiles); err != nil {
return nil, nil, err return nil, nil, err
} }
outGo = append(outGo, gofiles...) outGo = append(outGo, gofiles...)
// cc _cgo_defun.c // cc _cgo_defun.c
defunObj := obj + "_cgo_defun." + b.arch defunObj := obj + "_cgo_defun." + archChar
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
} }
...@@ -1293,12 +1389,12 @@ func (b *builder) cgo(p *Package, cgoExe, obj string, gccfiles []string) (outGo, ...@@ -1293,12 +1389,12 @@ func (b *builder) cgo(p *Package, cgoExe, obj string, gccfiles []string) (outGo,
// cgo -dynimport // cgo -dynimport
importC := obj + "_cgo_import.c" importC := obj + "_cgo_import.c"
if err := b.run(p.Dir, p.ImportPath, cgoExe, "-objdir", obj, "-dynimport", dynobj, "-dynout", importC); err != nil { if err := b.run(p.Dir, p.Dir, p.ImportPath, cgoExe, "-objdir", obj, "-dynimport", dynobj, "-dynout", importC); err != nil {
return nil, nil, err return nil, nil, err
} }
// cc _cgo_import.ARCH // cc _cgo_import.ARCH
importObj := obj + "_cgo_import." + b.arch importObj := obj + "_cgo_import." + archChar
if err := buildToolchain.cc(b, p, obj, importObj, importC); err != nil { if err := buildToolchain.cc(b, p, obj, importObj, importC); err != nil {
return nil, nil, err return nil, nil, err
} }
......
...@@ -13,7 +13,7 @@ import ( ...@@ -13,7 +13,7 @@ import (
) )
var cmdClean = &Command{ var cmdClean = &Command{
UsageLine: "clean [-i] [-r] [-n] [-x] [importpath...]", UsageLine: "clean [-i] [-r] [-n] [-x] [packages]",
Short: "remove object files", Short: "remove object files",
Long: ` Long: `
Clean removes object files from package source directories. Clean removes object files from package source directories.
...@@ -50,6 +50,8 @@ The -r flag causes clean to be applied recursively to all the ...@@ -50,6 +50,8 @@ The -r flag causes clean to be applied recursively to all the
dependencies of the packages named by the import paths. dependencies of the packages named by the import paths.
The -x flag causes clean to print remove commands as it executes them. The -x flag causes clean to print remove commands as it executes them.
For more about specifying packages, see 'go help packages'.
`, `,
} }
......
...@@ -28,7 +28,7 @@ Use "go help [command]" for more information about a command. ...@@ -28,7 +28,7 @@ Use "go help [command]" for more information about a command.
Additional help topics: Additional help topics:
gopath GOPATH environment variable gopath GOPATH environment variable
importpath description of import paths packages description of package lists
remote remote import path syntax remote remote import path syntax
testflag description of testing flags testflag description of testing flags
testfunc description of testing functions testfunc description of testing functions
...@@ -40,7 +40,7 @@ Compile packages and dependencies ...@@ -40,7 +40,7 @@ Compile packages and dependencies
Usage: Usage:
go build [-a] [-n] [-o output] [-p n] [-v] [-x] [importpath... | gofiles...] go build [-o output] [build flags] [packages]
Build compiles the packages named by the import paths, Build compiles the packages named by the import paths,
along with their dependencies, but it does not install the results. along with their dependencies, but it does not install the results.
...@@ -53,18 +53,37 @@ build writes the resulting executable to output (default a.out). ...@@ -53,18 +53,37 @@ build writes the resulting executable to output (default a.out).
Otherwise build compiles the packages but discards the results, Otherwise build compiles the packages but discards the results,
serving only as a check that the packages can be built. serving only as a check that the packages can be built.
The -a flag forces rebuilding of packages that are already up-to-date.
The -n flag prints the commands but does not run them.
The -v flag prints the names of packages as they are compiled.
The -x flag prints the commands.
The -o flag specifies the output file name. The -o flag specifies the output file name.
It is an error to use -o when the command line specifies multiple packages.
The -p flag specifies the number of builds that can be run in parallel. The build flags are shared by the build, install, run, and test commands:
The default is the number of CPUs available.
For more about import paths, see 'go help importpath'. -a
force rebuilding of packages that are already up-to-date.
-n
print the commands but does not run them.
-p n
the number of builds that can be run in parallel.
The default is the number of CPUs available.
-v
print the names of packages as they are compiled.
-work
print the name of the temporary work directory and
do not delete it when exiting.
-x
print the commands.
-gccgoflags 'arg list'
arguments to pass on each gccgo compiler/linker invocation
-gcflags 'arg list'
arguments to pass on each 5g, 6g, or 8g compiler invocation
-ldflags 'flag list'
arguments to pass on each 5l, 6l, or 8l linker invocation
-tags 'tag list'
a list of build tags to consider satisfied during the build.
See the documentation for the go/build package for
more information about build tags.
For more about specifying packages, see 'go help packages'.
See also: go install, go get, go clean. See also: go install, go get, go clean.
...@@ -73,7 +92,7 @@ Remove object files ...@@ -73,7 +92,7 @@ Remove object files
Usage: Usage:
go clean [-i] [-r] [-n] [-x] [importpath...] go clean [-i] [-r] [-n] [-x] [packages]
Clean removes object files from package source directories. Clean removes object files from package source directories.
The go command builds most objects in a temporary directory, The go command builds most objects in a temporary directory,
...@@ -110,18 +129,20 @@ dependencies of the packages named by the import paths. ...@@ -110,18 +129,20 @@ dependencies of the packages named by the import paths.
The -x flag causes clean to print remove commands as it executes them. The -x flag causes clean to print remove commands as it executes them.
For more about specifying packages, see 'go help packages'.
Run godoc on package sources Run godoc on package sources
Usage: Usage:
go doc [importpath...] go doc [packages]
Doc runs the godoc command on the packages named by the Doc runs the godoc command on the packages named by the
import paths. import paths.
For more about godoc, see 'godoc godoc'. For more about godoc, see 'godoc godoc'.
For more about import paths, see 'go help importpath'. For more about specifying packages, see 'go help packages'.
To run godoc with specific options, run godoc itself. To run godoc with specific options, run godoc itself.
...@@ -132,12 +153,12 @@ Run go tool fix on packages ...@@ -132,12 +153,12 @@ Run go tool fix on packages
Usage: Usage:
go fix [importpath...] go fix [packages]
Fix runs the Go fix command on the packages named by the import paths. Fix runs the Go fix command on the packages named by the import paths.
For more about fix, see 'godoc fix'. For more about fix, see 'godoc fix'.
For more about import paths, see 'go help importpath'. For more about specifying packages, see 'go help packages'.
To run fix with specific options, run 'go tool fix'. To run fix with specific options, run 'go tool fix'.
...@@ -148,13 +169,13 @@ Run gofmt on package sources ...@@ -148,13 +169,13 @@ Run gofmt on package sources
Usage: Usage:
go fmt [importpath...] go fmt [packages]
Fmt runs the command 'gofmt -l -w' on the packages named Fmt runs the command 'gofmt -l -w' on the packages named
by the import paths. It prints the names of the files that are modified. by the import paths. It prints the names of the files that are modified.
For more about gofmt, see 'godoc gofmt'. For more about gofmt, see 'godoc gofmt'.
For more about import paths, see 'go help importpath'. For more about specifying packages, see 'go help packages'.
To run gofmt with specific options, run gofmt itself. To run gofmt with specific options, run gofmt itself.
...@@ -165,7 +186,7 @@ Download and install packages and dependencies ...@@ -165,7 +186,7 @@ Download and install packages and dependencies
Usage: Usage:
go get [-a] [-d] [-fix] [-n] [-p n] [-u] [-v] [-x] [importpath...] go get [-a] [-d] [-fix] [-n] [-p n] [-u] [-v] [-x] [packages]
Get downloads and installs the packages named by the import paths, Get downloads and installs the packages named by the import paths,
along with their dependencies. along with their dependencies.
...@@ -180,12 +201,12 @@ The -fix flag instructs get to run the fix tool on the downloaded packages ...@@ -180,12 +201,12 @@ The -fix flag instructs get to run the fix tool on the downloaded packages
before resolving dependencies or building the code. before resolving dependencies or building the code.
The -u flag instructs get to use the network to update the named packages The -u flag instructs get to use the network to update the named packages
and their dependencies. By default, get uses the network to check out and their dependencies. By default, get uses the network to check out
missing packages but does not use it to look for updates to existing packages. missing packages but does not use it to look for updates to existing packages.
TODO: Explain versions better. TODO: Explain versions better.
For more about import paths, see 'go help importpath'. For more about specifying packages, see 'go help packages'.
For more about how 'go get' finds source code to For more about how 'go get' finds source code to
download, see 'go help remote'. download, see 'go help remote'.
...@@ -197,20 +218,13 @@ Compile and install packages and dependencies ...@@ -197,20 +218,13 @@ Compile and install packages and dependencies
Usage: Usage:
go install [-a] [-n] [-p n] [-v] [-x] [importpath...] go install [build flags] [packages]
Install compiles and installs the packages named by the import paths, Install compiles and installs the packages named by the import paths,
along with their dependencies. along with their dependencies.
The -a flag forces reinstallation of packages that are already up-to-date. For more about the build flags, see 'go help build'.
The -n flag prints the commands but does not run them. For more about specifying packages, see 'go help packages'.
The -v flag prints the names of packages as they are compiled.
The -x flag prints the commands.
The -p flag specifies the number of builds that can be run in parallel.
The default is the number of CPUs available.
For more about import paths, see 'go help importpath'.
See also: go build, go get, go clean. See also: go build, go get, go clean.
...@@ -219,7 +233,7 @@ List packages ...@@ -219,7 +233,7 @@ List packages
Usage: Usage:
go list [-e] [-f format] [-json] [importpath...] go list [-e] [-f format] [-json] [packages]
List lists the packages named by the import paths, one per line. List lists the packages named by the import paths, one per line.
...@@ -274,20 +288,18 @@ printing. Erroneous packages will have a non-empty ImportPath and ...@@ -274,20 +288,18 @@ printing. Erroneous packages will have a non-empty ImportPath and
a non-nil Error field; other information may or may not be missing a non-nil Error field; other information may or may not be missing
(zeroed). (zeroed).
For more about import paths, see 'go help importpath'. For more about specifying packages, see 'go help packages'.
Compile and run Go program Compile and run Go program
Usage: Usage:
go run [-a] [-n] [-x] gofiles... [arguments...] go run [build flags] gofiles... [arguments...]
Run compiles and runs the main package comprising the named Go source files. Run compiles and runs the main package comprising the named Go source files.
The -a flag forces reinstallation of packages that are already up-to-date. For more about build flags, see 'go help build'.
The -n flag prints the commands but does not run them.
The -x flag prints the commands.
See also: go build. See also: go build.
...@@ -296,7 +308,7 @@ Test packages ...@@ -296,7 +308,7 @@ Test packages
Usage: Usage:
go test [-c] [-file a.go -file b.go ...] [-i] [-p n] [-x] [importpath...] [flags for test binary] go test [-c] [-i] [build flags] [packages] [flags for test binary]
'Go test' automates testing the packages named by the import paths. 'Go test' automates testing the packages named by the import paths.
It prints a summary of the test results in the format: It prints a summary of the test results in the format:
...@@ -314,17 +326,23 @@ benchmark functions, and example functions. See 'go help testfunc' for more. ...@@ -314,17 +326,23 @@ benchmark functions, and example functions. See 'go help testfunc' for more.
By default, go test needs no arguments. It compiles and tests the package By default, go test needs no arguments. It compiles and tests the package
with source in the current directory, including tests, and runs the tests. with source in the current directory, including tests, and runs the tests.
If file names are given (with flag -file=test.go, one per extra test source file),
only those test files are added to the package. (The non-test files are always
compiled.)
The package is built in a temporary directory so it does not interfere with the The package is built in a temporary directory so it does not interfere with the
non-test installation. non-test installation.
See 'go help testflag' for details about flags handled by 'go test' In addition to the build flags, the flags handled by 'go test' itself are:
and the test binary.
See 'go help importpath' for more about import paths. -c Compile the test binary to pkg.test but do not run it.
-i
Install packages that are dependencies of the test.
Do not run the test.
The test binary also accepts flags that control execution of the test; these
flags are also accessible by 'go test'. See 'go help testflag' for details.
For more about build flags, see 'go help build'.
For more about specifying packages, see 'go help packages'.
See also: go build, go vet. See also: go build, go vet.
...@@ -333,11 +351,14 @@ Run specified go tool ...@@ -333,11 +351,14 @@ Run specified go tool
Usage: Usage:
go tool command [args...] go tool [-n] command [args...]
Tool runs the go tool command identified by the arguments. Tool runs the go tool command identified by the arguments.
With no arguments it prints the list of known tools. With no arguments it prints the list of known tools.
The -n flag causes tool to print the command that would be
executed but not execute it.
For more about each tool command, see 'go tool command -h'. For more about each tool command, see 'go tool command -h'.
...@@ -354,12 +375,12 @@ Run go tool vet on packages ...@@ -354,12 +375,12 @@ Run go tool vet on packages
Usage: Usage:
go vet [importpath...] go vet [packages]
Vet runs the Go vet command on the packages named by the import paths. Vet runs the Go vet command on the packages named by the import paths.
For more about vet, see 'godoc vet'. For more about vet, see 'godoc vet'.
For more about import paths, see 'go help importpath'. For more about specifying packages, see 'go help packages'.
To run the vet tool with specific options, run 'go tool vet'. To run the vet tool with specific options, run 'go tool vet'.
...@@ -421,11 +442,13 @@ but new packages are always downloaded into the first directory ...@@ -421,11 +442,13 @@ but new packages are always downloaded into the first directory
in the list. in the list.
Description of import paths Description of package lists
Many commands apply to a set of packages:
Many commands apply to a set of packages named by import paths: go action [packages]
go action [importpath...] Usually, [packages] is a list of import paths.
An import path that is a rooted path or that begins with An import path that is a rooted path or that begins with
a . or .. element is interpreted as a file system path and a . or .. element is interpreted as a file system path and
...@@ -449,8 +472,9 @@ An import path is a pattern if it includes one or more "..." wildcards, ...@@ -449,8 +472,9 @@ An import path is a pattern if it includes one or more "..." wildcards,
each of which can match any string, including the empty string and each of which can match any string, including the empty string and
strings containing slashes. Such a pattern expands to all package strings containing slashes. Such a pattern expands to all package
directories found in the GOPATH trees with names matching the directories found in the GOPATH trees with names matching the
patterns. For example, encoding/... expands to all packages patterns. For example, encoding/... expands to all package
in the encoding tree. in subdirectories of the encoding tree, while net... expands to
net and all its subdirectories.
An import path can also name a package to be downloaded from An import path can also name a package to be downloaded from
a remote repository. Run 'go help remote' for details. a remote repository. Run 'go help remote' for details.
...@@ -462,6 +486,11 @@ internally at Google all begin with 'google', and paths ...@@ -462,6 +486,11 @@ internally at Google all begin with 'google', and paths
denoting remote repositories begin with the path to the code, denoting remote repositories begin with the path to the code,
such as 'code.google.com/p/project'. such as 'code.google.com/p/project'.
As a special case, if the package list is a list of .go files from a
single directory, the command is applied to a single synthesized
package made up of exactly those files, ignoring any build constraints
in those files and ignoring any other files in the directory.
Remote import path syntax Remote import path syntax
...@@ -541,24 +570,7 @@ Description of testing flags ...@@ -541,24 +570,7 @@ Description of testing flags
The 'go test' command takes both flags that apply to 'go test' itself The 'go test' command takes both flags that apply to 'go test' itself
and flags that apply to the resulting test binary. and flags that apply to the resulting test binary.
The flags handled by 'go test' are: The test binary, called pkg.test, where pkg is the name of the
-c Compile the test binary to pkg.test but do not run it.
-file a.go
Use only the tests in the source file a.go.
Multiple -file flags may be provided.
-i
Install packages that are dependencies of the test.
-p n
Compile and test up to n packages in parallel.
The default value is the number of CPUs available.
-x Print each subcommand go test executes.
The resulting test binary, called pkg.test, where pkg is the name of the
directory containing the package sources, has its own flags: directory containing the package sources, has its own flags:
-test.v -test.v
...@@ -606,7 +618,7 @@ directory containing the package sources, has its own flags: ...@@ -606,7 +618,7 @@ directory containing the package sources, has its own flags:
The default is 1 second. The default is 1 second.
-test.cpu 1,2,4 -test.cpu 1,2,4
Specify a list of GOMAXPROCS values for which the tests or Specify a list of GOMAXPROCS values for which the tests or
benchmarks should be executed. The default is the current value benchmarks should be executed. The default is the current value
of GOMAXPROCS. of GOMAXPROCS.
...@@ -614,9 +626,9 @@ For convenience, each of these -test.X flags of the test binary is ...@@ -614,9 +626,9 @@ For convenience, each of these -test.X flags of the test binary is
also available as the flag -X in 'go test' itself. Flags not listed also available as the flag -X in 'go test' itself. Flags not listed
here are passed through unaltered. For instance, the command here are passed through unaltered. For instance, the command
go test -x -v -cpuprofile=prof.out -dir=testdata -update -file x_test.go go test -x -v -cpuprofile=prof.out -dir=testdata -update
will compile the test binary using x_test.go and then run it as will compile the test binary and then run it as
pkg.test -test.v -test.cpuprofile=prof.out -dir=testdata -update pkg.test -test.v -test.cpuprofile=prof.out -dir=testdata -update
...@@ -637,8 +649,10 @@ A benchmark function is one named BenchmarkXXX and should have the signature, ...@@ -637,8 +649,10 @@ A benchmark function is one named BenchmarkXXX and should have the signature,
An example function is similar to a test function but, instead of using *testing.T An example function is similar to a test function but, instead of using *testing.T
to report success or failure, prints output to os.Stdout and os.Stderr. to report success or failure, prints output to os.Stdout and os.Stderr.
That output is compared against the function's doc comment. That output is compared against the function's "Output:" comment, which
An example without a doc comment is compiled but not executed. must be the last comment in the function body (see example below). An
example with no such comment, or with no text after "Output:" is compiled
but not executed.
Godoc displays the body of ExampleXXX to demonstrate the use Godoc displays the body of ExampleXXX to demonstrate the use
of the function, constant, or variable XXX. An example of a method M with of the function, constant, or variable XXX. An example of a method M with
...@@ -648,11 +662,16 @@ where xxx is a suffix not beginning with an upper case letter. ...@@ -648,11 +662,16 @@ where xxx is a suffix not beginning with an upper case letter.
Here is an example of an example: Here is an example of an example:
// The output of this example function.
func ExamplePrintln() { func ExamplePrintln() {
Println("The output of this example function.") Println("The output of\nthis example.")
// Output: The output of
// this example.
} }
The entire test file is presented as the example when it contains a single
example function, at least one other function, type, variable, or constant
declaration, and no test or benchmark functions.
See the documentation of the testing package for more information. See the documentation of the testing package for more information.
......
...@@ -6,13 +6,13 @@ package main ...@@ -6,13 +6,13 @@ package main
var cmdFix = &Command{ var cmdFix = &Command{
Run: runFix, Run: runFix,
UsageLine: "fix [importpath...]", UsageLine: "fix [packages]",
Short: "run go tool fix on packages", Short: "run go tool fix on packages",
Long: ` Long: `
Fix runs the Go fix command on the packages named by the import paths. Fix runs the Go fix command on the packages named by the import paths.
For more about fix, see 'godoc fix'. For more about fix, see 'godoc fix'.
For more about import paths, see 'go help importpath'. For more about specifying packages, see 'go help packages'.
To run fix with specific options, run 'go tool fix'. To run fix with specific options, run 'go tool fix'.
......
...@@ -6,14 +6,14 @@ package main ...@@ -6,14 +6,14 @@ package main
var cmdFmt = &Command{ var cmdFmt = &Command{
Run: runFmt, Run: runFmt,
UsageLine: "fmt [importpath...]", UsageLine: "fmt [packages]",
Short: "run gofmt on package sources", Short: "run gofmt on package sources",
Long: ` Long: `
Fmt runs the command 'gofmt -l -w' on the packages named Fmt runs the command 'gofmt -l -w' on the packages named
by the import paths. It prints the names of the files that are modified. by the import paths. It prints the names of the files that are modified.
For more about gofmt, see 'godoc gofmt'. For more about gofmt, see 'godoc gofmt'.
For more about import paths, see 'go help importpath'. For more about specifying packages, see 'go help packages'.
To run gofmt with specific options, run gofmt itself. To run gofmt with specific options, run gofmt itself.
...@@ -32,14 +32,14 @@ func runFmt(cmd *Command, args []string) { ...@@ -32,14 +32,14 @@ func runFmt(cmd *Command, args []string) {
var cmdDoc = &Command{ var cmdDoc = &Command{
Run: runDoc, Run: runDoc,
UsageLine: "doc [importpath...]", UsageLine: "doc [packages]",
Short: "run godoc on package sources", Short: "run godoc on package sources",
Long: ` Long: `
Doc runs the godoc command on the packages named by the Doc runs the godoc command on the packages named by the
import paths. import paths.
For more about godoc, see 'godoc godoc'. For more about godoc, see 'godoc godoc'.
For more about import paths, see 'go help importpath'. For more about specifying packages, see 'go help packages'.
To run godoc with specific options, run godoc itself. To run godoc with specific options, run godoc itself.
...@@ -49,6 +49,10 @@ See also: go fix, go fmt, go vet. ...@@ -49,6 +49,10 @@ See also: go fix, go fmt, go vet.
func runDoc(cmd *Command, args []string) { func runDoc(cmd *Command, args []string) {
for _, pkg := range packages(args) { for _, pkg := range packages(args) {
if pkg.ImportPath == "command-line arguments" {
errorf("go doc: cannot use package file list")
continue
}
run("godoc", pkg.Dir) run("godoc", pkg.Dir)
} }
} }
...@@ -8,7 +8,6 @@ package main ...@@ -8,7 +8,6 @@ package main
import ( import (
"fmt" "fmt"
"go/build"
"os" "os"
"path/filepath" "path/filepath"
"runtime" "runtime"
...@@ -17,7 +16,7 @@ import ( ...@@ -17,7 +16,7 @@ import (
) )
var cmdGet = &Command{ var cmdGet = &Command{
UsageLine: "get [-a] [-d] [-fix] [-n] [-p n] [-u] [-v] [-x] [importpath...]", UsageLine: "get [-a] [-d] [-fix] [-n] [-p n] [-u] [-v] [-x] [packages]",
Short: "download and install packages and dependencies", Short: "download and install packages and dependencies",
Long: ` Long: `
Get downloads and installs the packages named by the import paths, Get downloads and installs the packages named by the import paths,
...@@ -33,12 +32,12 @@ The -fix flag instructs get to run the fix tool on the downloaded packages ...@@ -33,12 +32,12 @@ The -fix flag instructs get to run the fix tool on the downloaded packages
before resolving dependencies or building the code. before resolving dependencies or building the code.
The -u flag instructs get to use the network to update the named packages The -u flag instructs get to use the network to update the named packages
and their dependencies. By default, get uses the network to check out and their dependencies. By default, get uses the network to check out
missing packages but does not use it to look for updates to existing packages. missing packages but does not use it to look for updates to existing packages.
TODO: Explain versions better. TODO: Explain versions better.
For more about import paths, see 'go help importpath'. For more about specifying packages, see 'go help packages'.
For more about how 'go get' finds source code to For more about how 'go get' finds source code to
download, see 'go help remote'. download, see 'go help remote'.
...@@ -151,22 +150,35 @@ func download(arg string, stk *importStack) { ...@@ -151,22 +150,35 @@ func download(arg string, stk *importStack) {
// downloadPackage runs the create or download command // downloadPackage runs the create or download command
// to make the first copy of or update a copy of the given package. // to make the first copy of or update a copy of the given package.
func downloadPackage(p *Package) error { func downloadPackage(p *Package) error {
// Analyze the import path to determine the version control system, var (
// repository, and the import path for the root of the repository. vcs *vcsCmd
vcs, repo, rootPath, err := vcsForImportPath(p.ImportPath) repo, rootPath string
err error
)
if p.build.SrcRoot != "" {
// Directory exists. Look for checkout along path to src.
vcs, rootPath, err = vcsForDir(p)
repo = "<local>" // should be unused; make distinctive
} else {
// Analyze the import path to determine the version control system,
// repository, and the import path for the root of the repository.
vcs, repo, rootPath, err = vcsForImportPath(p.ImportPath)
}
if err != nil { if err != nil {
return err return err
} }
if p.t == nil {
if p.build.SrcRoot == "" {
// Package not found. Put in first directory of $GOPATH or else $GOROOT. // Package not found. Put in first directory of $GOPATH or else $GOROOT.
p.t = build.Path[0] // $GOROOT if list := filepath.SplitList(buildContext.GOPATH); len(list) > 0 {
if len(build.Path) > 1 { p.build.SrcRoot = filepath.Join(list[0], "src")
p.t = build.Path[1] // first in $GOPATH p.build.PkgRoot = filepath.Join(list[0], "pkg")
} else {
p.build.SrcRoot = filepath.Join(goroot, "src", "pkg")
p.build.PkgRoot = filepath.Join(goroot, "pkg")
} }
p.Dir = filepath.Join(p.t.SrcDir(), p.ImportPath)
} }
root := filepath.Join(p.t.SrcDir(), rootPath) root := filepath.Join(p.build.SrcRoot, rootPath)
// If we've considered this repository already, don't do it again. // If we've considered this repository already, don't do it again.
if downloadRootCache[root] { if downloadRootCache[root] {
return nil return nil
...@@ -206,6 +218,14 @@ func downloadPackage(p *Package) error { ...@@ -206,6 +218,14 @@ func downloadPackage(p *Package) error {
} }
} }
if buildN {
// Do not show tag sync in -n; it's noise more than anything,
// and since we're not running commands, no tag will be found.
// But avoid printing nothing.
fmt.Fprintf(os.Stderr, "# cd %s; %s sync/update\n", root, vcs.cmd)
return nil
}
// Select and sync to appropriate version of the repository. // Select and sync to appropriate version of the repository.
tags, err := vcs.tags(root) tags, err := vcs.tags(root)
if err != nil { if err != nil {
......
...@@ -4,13 +4,15 @@ ...@@ -4,13 +4,15 @@
package main package main
var helpImportpath = &Command{ var helpPackages = &Command{
UsageLine: "importpath", UsageLine: "packages",
Short: "description of import paths", Short: "description of package lists",
Long: ` Long: `
Many commands apply to a set of packages named by import paths: Many commands apply to a set of packages:
go action [importpath...] go action [packages]
Usually, [packages] is a list of import paths.
An import path that is a rooted path or that begins with An import path that is a rooted path or that begins with
a . or .. element is interpreted as a file system path and a . or .. element is interpreted as a file system path and
...@@ -34,7 +36,7 @@ An import path is a pattern if it includes one or more "..." wildcards, ...@@ -34,7 +36,7 @@ An import path is a pattern if it includes one or more "..." wildcards,
each of which can match any string, including the empty string and each of which can match any string, including the empty string and
strings containing slashes. Such a pattern expands to all package strings containing slashes. Such a pattern expands to all package
directories found in the GOPATH trees with names matching the directories found in the GOPATH trees with names matching the
patterns. For example, encoding/... expands to all package patterns. For example, encoding/... expands to all packages
in subdirectories of the encoding tree, while net... expands to in subdirectories of the encoding tree, while net... expands to
net and all its subdirectories. net and all its subdirectories.
...@@ -47,6 +49,11 @@ unique prefix that belongs to you. For example, paths used ...@@ -47,6 +49,11 @@ unique prefix that belongs to you. For example, paths used
internally at Google all begin with 'google', and paths internally at Google all begin with 'google', and paths
denoting remote repositories begin with the path to the code, denoting remote repositories begin with the path to the code,
such as 'code.google.com/p/project'. such as 'code.google.com/p/project'.
As a special case, if the package list is a list of .go files from a
single directory, the command is applied to a single synthesized
package made up of exactly those files, ignoring any build constraints
in those files and ignoring any other files in the directory.
`, `,
} }
......
...@@ -13,7 +13,7 @@ import ( ...@@ -13,7 +13,7 @@ import (
) )
var cmdList = &Command{ var cmdList = &Command{
UsageLine: "list [-e] [-f format] [-json] [importpath...]", UsageLine: "list [-e] [-f format] [-json] [packages]",
Short: "list packages", Short: "list packages",
Long: ` Long: `
List lists the packages named by the import paths, one per line. List lists the packages named by the import paths, one per line.
...@@ -69,7 +69,7 @@ printing. Erroneous packages will have a non-empty ImportPath and ...@@ -69,7 +69,7 @@ printing. Erroneous packages will have a non-empty ImportPath and
a non-nil Error field; other information may or may not be missing a non-nil Error field; other information may or may not be missing
(zeroed). (zeroed).
For more about import paths, see 'go help importpath'. For more about specifying packages, see 'go help packages'.
`, `,
} }
......
...@@ -88,7 +88,7 @@ var commands = []*Command{ ...@@ -88,7 +88,7 @@ var commands = []*Command{
cmdVet, cmdVet,
helpGopath, helpGopath,
helpImportpath, helpPackages,
helpRemote, helpRemote,
helpTestflag, helpTestflag,
helpTestfunc, helpTestfunc,
...@@ -251,7 +251,24 @@ func importPaths(args []string) []string { ...@@ -251,7 +251,24 @@ func importPaths(args []string) []string {
} }
var out []string var out []string
for _, a := range args { for _, a := range args {
if isLocalPath(a) && strings.Contains(a, "...") { // Arguments are supposed to be import paths, but
// as a courtesy to Windows developers, rewrite \ to /
// in command-line arguments. Handles .\... and so on.
if filepath.Separator == '\\' {
a = strings.Replace(a, `\`, `/`, -1)
}
// Put argument in canonical form, but preserve leading ./.
if strings.HasPrefix(a, "./") {
a = "./" + path.Clean(a)
if a == "./." {
a = "."
}
} else {
a = path.Clean(a)
}
if build.IsLocalImport(a) && strings.Contains(a, "...") {
out = append(out, allPackagesInFS(a)...) out = append(out, allPackagesInFS(a)...)
continue continue
} }
...@@ -350,7 +367,6 @@ func allPackages(pattern string) []string { ...@@ -350,7 +367,6 @@ func allPackages(pattern string) []string {
var pkgs []string var pkgs []string
// Commands // Commands
goroot := build.Path[0].Path
cmd := filepath.Join(goroot, "src/cmd") + string(filepath.Separator) cmd := filepath.Join(goroot, "src/cmd") + string(filepath.Separator)
filepath.Walk(cmd, func(path string, fi os.FileInfo, err error) error { filepath.Walk(cmd, func(path string, fi os.FileInfo, err error) error {
if err != nil || !fi.IsDir() || path == cmd { if err != nil || !fi.IsDir() || path == cmd {
...@@ -362,7 +378,7 @@ func allPackages(pattern string) []string { ...@@ -362,7 +378,7 @@ func allPackages(pattern string) []string {
return filepath.SkipDir return filepath.SkipDir
} }
_, err = build.ScanDir(path) _, err = build.ImportDir(path, 0)
if err != nil { if err != nil {
return nil return nil
} }
...@@ -378,11 +394,11 @@ func allPackages(pattern string) []string { ...@@ -378,11 +394,11 @@ func allPackages(pattern string) []string {
return nil return nil
}) })
for _, t := range build.Path { for _, src := range buildContext.SrcDirs() {
if pattern == "std" && !t.Goroot { if pattern == "std" && src != gorootSrcPkg {
continue continue
} }
src := t.SrcDir() + string(filepath.Separator) src = filepath.Clean(src) + string(filepath.Separator)
filepath.Walk(src, func(path string, fi os.FileInfo, err error) error { filepath.Walk(src, func(path string, fi os.FileInfo, err error) error {
if err != nil || !fi.IsDir() || path == src { if err != nil || !fi.IsDir() || path == src {
return nil return nil
...@@ -403,21 +419,13 @@ func allPackages(pattern string) []string { ...@@ -403,21 +419,13 @@ func allPackages(pattern string) []string {
} }
have[name] = true have[name] = true
_, err = build.ScanDir(path) _, err = build.ImportDir(path, 0)
if err != nil && strings.Contains(err.Error(), "no Go source files") { if err != nil && strings.Contains(err.Error(), "no Go source files") {
return nil return nil
} }
if match(name) { if match(name) {
pkgs = append(pkgs, name) pkgs = append(pkgs, name)
} }
// Avoid go/build test data.
// TODO: Move it into a testdata directory.
if path == filepath.Join(build.Path[0].SrcDir(), "go/build") {
return filepath.SkipDir
}
return nil return nil
}) })
} }
...@@ -465,7 +473,7 @@ func allPackagesInFS(pattern string) []string { ...@@ -465,7 +473,7 @@ func allPackagesInFS(pattern string) []string {
if !match(name) { if !match(name) {
return nil return nil
} }
if _, err = build.ScanDir(path); err != nil { if _, err = build.ImportDir(path, 0); err != nil {
return nil return nil
} }
pkgs = append(pkgs, name) pkgs = append(pkgs, name)
...@@ -494,10 +502,3 @@ func stringList(args ...interface{}) []string { ...@@ -494,10 +502,3 @@ func stringList(args ...interface{}) []string {
} }
return x return x
} }
// isLocalPath returns true if arg is an import path denoting
// a local file system directory. That is, it returns true if the
// path begins with ./ or ../ .
func isLocalPath(arg string) bool {
return arg == "." || arg == ".." || strings.HasPrefix(arg, "./") || strings.HasPrefix(arg, "../")
}
...@@ -6,10 +6,11 @@ package main ...@@ -6,10 +6,11 @@ package main
import ( import (
"bytes" "bytes"
"errors"
"fmt" "fmt"
"go/build" "go/build"
"go/doc"
"go/scanner" "go/scanner"
"go/token"
"os" "os"
"path/filepath" "path/filepath"
"sort" "sort"
...@@ -22,42 +23,78 @@ type Package struct { ...@@ -22,42 +23,78 @@ type Package struct {
// Note: These fields are part of the go command's public API. // Note: These fields are part of the go command's public API.
// See list.go. It is okay to add fields, but not to change or // See list.go. It is okay to add fields, but not to change or
// remove existing ones. Keep in sync with list.go // remove existing ones. Keep in sync with list.go
ImportPath string // import path of package in dir Dir string `json:",omitempty"` // directory containing package sources
ImportPath string `json:",omitempty"` // import path of package in dir
Name string `json:",omitempty"` // package name Name string `json:",omitempty"` // package name
Doc string `json:",omitempty"` // package documentation string Doc string `json:",omitempty"` // package documentation string
Dir string `json:",omitempty"` // directory containing package sources
Target string `json:",omitempty"` // install path Target string `json:",omitempty"` // install path
Version string `json:",omitempty"` // version of installed package (TODO) Goroot bool `json:",omitempty"` // is this package found in the Go root?
Standard bool `json:",omitempty"` // is this package part of the standard Go library? Standard bool `json:",omitempty"` // is this package part of the standard Go library?
Stale bool `json:",omitempty"` // would 'go install' do anything for this package? Stale bool `json:",omitempty"` // would 'go install' do anything for this package?
Incomplete bool `json:",omitempty"` // was there an error loading this package or dependencies? Incomplete bool `json:",omitempty"` // was there an error loading this package or dependencies?
Error *PackageError `json:",omitempty"` // error loading this package (not dependencies) Error *PackageError `json:",omitempty"` // error loading this package (not dependencies)
Root string `json:",omitempty"` // root dir of tree this package belongs to
// Source files // Source files
GoFiles []string `json:",omitempty"` // .go source files (excluding CgoFiles, TestGoFiles and XTestGoFiles) GoFiles []string `json:",omitempty"` // .go source files (excluding CgoFiles, TestGoFiles XTestGoFiles)
TestGoFiles []string `json:",omitempty"` // _test.go source files internal to the package they are testing CgoFiles []string `json:",omitempty"` // .go sources files that import "C"
XTestGoFiles []string `json:",omitempty"` //_test.go source files external to the package they are testing CFiles []string `json:",omitempty"` // .c source files
CFiles []string `json:",omitempty"` // .c source files HFiles []string `json:",omitempty"` // .h source files
HFiles []string `json:",omitempty"` // .h source files SFiles []string `json:",omitempty"` // .s source files
SFiles []string `json:",omitempty"` // .s source files
CgoFiles []string `json:",omitempty"` // .go sources files that import "C" // Cgo directives
CgoCFLAGS []string `json:",omitempty"` // cgo: flags for C compiler CgoCFLAGS []string `json:",omitempty"` // cgo: flags for C compiler
CgoLDFLAGS []string `json:",omitempty"` // cgo: flags for linker CgoLDFLAGS []string `json:",omitempty"` // cgo: flags for linker
CgoPkgConfig []string `json:",omitempty"` // cgo: pkg-config names
// Dependency information // Dependency information
Imports []string `json:",omitempty"` // import paths used by this package Imports []string `json:",omitempty"` // import paths used by this package
Deps []string `json:",omitempty"` // all (recursively) imported dependencies Deps []string `json:",omitempty"` // all (recursively) imported dependencies
DepsErrors []*PackageError `json:",omitempty"` // errors loading dependencies DepsErrors []*PackageError `json:",omitempty"` // errors loading dependencies
// Test information
TestGoFiles []string `json:",omitempty"` // _test.go files in package
TestImports []string `json:",omitempty"` // imports from TestGoFiles
XTestGoFiles []string `json:",omitempty"` // _test.go files outside package
XTestImports []string `json:",omitempty"` // imports from XTestGoFiles
// Unexported fields are not part of the public API. // Unexported fields are not part of the public API.
t *build.Tree build *build.Package
pkgdir string pkgdir string // overrides build.PkgDir
info *build.DirInfo imports []*Package
imports []*Package deps []*Package
deps []*Package gofiles []string // GoFiles+CgoFiles+TestGoFiles+XTestGoFiles files, absolute paths
gofiles []string // GoFiles+CgoFiles+TestGoFiles+XTestGoFiles files, absolute paths target string // installed file for this package (may be executable)
target string // installed file for this package (may be executable) fake bool // synthesized package
fake bool // synthesized package forceBuild bool // this package must be rebuilt
local bool // imported via local path (./ or ../)
}
func (p *Package) copyBuild(pp *build.Package) {
p.build = pp
p.Dir = pp.Dir
p.ImportPath = pp.ImportPath
p.Name = pp.Name
p.Doc = pp.Doc
p.Root = pp.Root
// TODO? Target
p.Goroot = pp.Goroot
p.Standard = p.Goroot && p.ImportPath != "" && !strings.Contains(p.ImportPath, ".")
p.GoFiles = pp.GoFiles
p.CgoFiles = pp.CgoFiles
p.CFiles = pp.CFiles
p.HFiles = pp.HFiles
p.SFiles = pp.SFiles
p.CgoCFLAGS = pp.CgoCFLAGS
p.CgoLDFLAGS = pp.CgoLDFLAGS
p.CgoPkgConfig = pp.CgoPkgConfig
p.Imports = pp.Imports
p.TestGoFiles = pp.TestGoFiles
p.TestImports = pp.TestImports
p.XTestGoFiles = pp.XTestGoFiles
p.XTestImports = pp.XTestImports
} }
// A PackageError describes an error loading information about a package. // A PackageError describes an error loading information about a package.
...@@ -69,9 +106,11 @@ type PackageError struct { ...@@ -69,9 +106,11 @@ type PackageError struct {
func (p *PackageError) Error() string { func (p *PackageError) Error() string {
if p.Pos != "" { if p.Pos != "" {
return strings.Join(p.ImportStack, "\n\timports ") + ": " + p.Pos + ": " + p.Err // Omit import stack. The full path to the file where the error
// is the most important thing.
return p.Pos + ": " + p.Err
} }
return strings.Join(p.ImportStack, "\n\timports ") + ": " + p.Err return "package " + strings.Join(p.ImportStack, "\n\timports ") + ": " + p.Err
} }
// An importStack is a stack of import paths. // An importStack is a stack of import paths.
...@@ -122,86 +161,46 @@ func reloadPackage(arg string, stk *importStack) *Package { ...@@ -122,86 +161,46 @@ func reloadPackage(arg string, stk *importStack) *Package {
return loadPackage(arg, stk) return loadPackage(arg, stk)
} }
// loadPackage scans directory named by arg, // loadImport scans the directory named by path, which must be an import path,
// which is either an import path or a file system path // but possibly a local import path (an absolute file system path or one beginning
// (if the latter, must be rooted or begin with . or ..), // with ./ or ../). A local relative path is interpreted relative to srcDir.
// and returns a *Package describing the package // It returns a *Package describing the package found in that directory.
// found in that directory. func loadImport(path string, srcDir string, stk *importStack, importPos []token.Position) *Package {
func loadPackage(arg string, stk *importStack) *Package { stk.push(path)
stk.push(arg)
defer stk.pop() defer stk.pop()
// Check package cache. // Determine canonical identifier for this package.
if p := packageCache[arg]; p != nil { // For a local path (./ or ../) the identifier is the full
return reusePackage(p, stk) // directory name. Otherwise it is the import path.
} pkgid := path
isLocal := build.IsLocalImport(path)
// Find basic information about package path. if isLocal {
isCmd := false pkgid = filepath.Join(srcDir, path)
t, importPath, err := build.FindTree(arg)
dir := ""
// Maybe it is a standard command.
if err != nil && strings.HasPrefix(arg, "cmd/") {
goroot := build.Path[0]
p := filepath.Join(goroot.Path, "src", arg)
if st, err1 := os.Stat(p); err1 == nil && st.IsDir() {
t = goroot
importPath = arg
dir = p
err = nil
isCmd = true
}
}
// Maybe it is a path to a standard command.
if err != nil && (filepath.IsAbs(arg) || isLocalPath(arg)) {
arg, _ := filepath.Abs(arg)
goroot := build.Path[0]
cmd := filepath.Join(goroot.Path, "src", "cmd") + string(filepath.Separator)
if st, err1 := os.Stat(arg); err1 == nil && st.IsDir() && strings.HasPrefix(arg, cmd) {
t = goroot
importPath = filepath.FromSlash(arg[len(cmd):])
dir = arg
err = nil
isCmd = true
}
} }
if err != nil { if p := packageCache[pkgid]; p != nil {
p := &Package{ return reusePackage(p, stk)
ImportPath: arg,
Error: &PackageError{
ImportStack: stk.copy(),
Err: err.Error(),
},
Incomplete: true,
}
packageCache[arg] = p
return p
} }
if dir == "" { p := new(Package)
dir = filepath.Join(t.SrcDir(), filepath.FromSlash(importPath)) packageCache[pkgid] = p
}
// Maybe we know the package by its directory. // Load package.
p := packageCache[dir] // Import always returns bp != nil, even if an error occurs,
if p != nil { // in order to return partial information.
packageCache[importPath] = p bp, err := buildContext.Import(path, srcDir, build.AllowBinary)
p = reusePackage(p, stk) p.load(stk, bp, err)
} else { if p.Error != nil && len(importPos) > 0 {
p = scanPackage(&buildContext, t, arg, importPath, dir, stk, false) pos := importPos[0]
pos.Filename = shortPath(pos.Filename)
p.Error.Pos = pos.String()
} }
// If we loaded the files from the Go root's cmd/ tree,
// it must be a command (package main).
if isCmd && p.Error == nil && p.Name != "main" {
p.Error = &PackageError{
ImportStack: stk.copy(),
Err: fmt.Sprintf("expected package main in %q; found package %s", dir, p.Name),
}
}
return p return p
} }
// reusePackage reuses package p to satisfy the import at the top
// of the import stack stk. If this use causes an import loop,
// reusePackage updates p's error information to record the loop.
func reusePackage(p *Package, stk *importStack) *Package { func reusePackage(p *Package, stk *importStack) *Package {
// We use p.imports==nil to detect a package that // We use p.imports==nil to detect a package that
// is in the midst of its own loadPackage call // is in the midst of its own loadPackage call
...@@ -212,6 +211,7 @@ func reusePackage(p *Package, stk *importStack) *Package { ...@@ -212,6 +211,7 @@ func reusePackage(p *Package, stk *importStack) *Package {
ImportStack: stk.copy(), ImportStack: stk.copy(),
Err: "import loop", Err: "import loop",
} }
panic("loop")
} }
p.Incomplete = true p.Incomplete = true
} }
...@@ -222,7 +222,7 @@ func reusePackage(p *Package, stk *importStack) *Package { ...@@ -222,7 +222,7 @@ func reusePackage(p *Package, stk *importStack) *Package {
} }
// isGoTool is the list of directories for Go programs that are installed in // isGoTool is the list of directories for Go programs that are installed in
// $GOROOT/bin/tool. // $GOROOT/pkg/tool.
var isGoTool = map[string]bool{ var isGoTool = map[string]bool{
"cmd/api": true, "cmd/api": true,
"cmd/cgo": true, "cmd/cgo": true,
...@@ -233,126 +233,75 @@ var isGoTool = map[string]bool{ ...@@ -233,126 +233,75 @@ var isGoTool = map[string]bool{
"exp/ebnflint": true, "exp/ebnflint": true,
} }
func scanPackage(ctxt *build.Context, t *build.Tree, arg, importPath, dir string, stk *importStack, useAllFiles bool) *Package { // expandScanner expands a scanner.List error into all the errors in the list.
// Read the files in the directory to learn the structure // The default Error method only shows the first error.
// of the package. func expandScanner(err error) error {
p := &Package{ // Look for parser errors.
ImportPath: importPath, if err, ok := err.(scanner.ErrorList); ok {
Dir: dir, // Prepare error with \n before each message.
Standard: t.Goroot && !strings.Contains(importPath, "."), // When printed in something like context: %v
t: t, // this will put the leading file positions each on
} // its own line. It will also show all the errors
packageCache[dir] = p // instead of just the first, as err.Error does.
packageCache[importPath] = p var buf bytes.Buffer
for _, e := range err {
ctxt.UseAllFiles = useAllFiles e.Pos.Filename = shortPath(e.Pos.Filename)
info, err := ctxt.ScanDir(dir) buf.WriteString("\n")
useAllFiles = false // flag does not apply to dependencies buf.WriteString(e.Error())
}
return errors.New(buf.String())
}
return err
}
// load populates p using information from bp, err, which should
// be the result of calling build.Context.Import.
func (p *Package) load(stk *importStack, bp *build.Package, err error) *Package {
p.copyBuild(bp)
p.local = build.IsLocalImport(p.ImportPath)
if p.local {
// The correct import for this package depends on which
// directory you are in. Instead, record the full directory path.
// That can't be used as an import path at all, but at least
// it uniquely identifies the package.
p.ImportPath = p.Dir
}
if err != nil { if err != nil {
p.Incomplete = true
err = expandScanner(err)
p.Error = &PackageError{ p.Error = &PackageError{
ImportStack: stk.copy(), ImportStack: stk.copy(),
Err: err.Error(), Err: err.Error(),
} }
// Look for parser errors.
if err, ok := err.(scanner.ErrorList); ok {
// Prepare error with \n before each message.
// When printed in something like context: %v
// this will put the leading file positions each on
// its own line. It will also show all the errors
// instead of just the first, as err.Error does.
var buf bytes.Buffer
for _, e := range err {
buf.WriteString("\n")
buf.WriteString(e.Error())
}
p.Error.Err = buf.String()
}
p.Incomplete = true
return p return p
} }
p.info = info if p.Name == "main" {
p.Name = info.Package _, elem := filepath.Split(p.Dir)
p.Doc = doc.Synopsis(info.PackageComment.Text()) full := buildContext.GOOS + "_" + buildContext.GOARCH + "/" + elem
p.Imports = info.Imports if buildContext.GOOS != toolGOOS || buildContext.GOARCH != toolGOARCH {
p.GoFiles = info.GoFiles // Install cross-compiled binaries to subdirectories of bin.
p.TestGoFiles = info.TestGoFiles elem = full
p.XTestGoFiles = info.XTestGoFiles }
p.CFiles = info.CFiles p.target = filepath.Join(p.build.BinDir, elem)
p.HFiles = info.HFiles if p.Goroot && isGoTool[p.ImportPath] {
p.SFiles = info.SFiles p.target = filepath.Join(gorootPkg, "tool", full)
p.CgoFiles = info.CgoFiles
p.CgoCFLAGS = info.CgoCFLAGS
p.CgoLDFLAGS = info.CgoLDFLAGS
if info.Package == "main" {
_, elem := filepath.Split(importPath)
full := ctxt.GOOS + "_" + ctxt.GOARCH + "/" + elem
if t.Goroot && isGoTool[p.ImportPath] {
p.target = filepath.Join(t.Path, "pkg/tool", full)
} else {
if ctxt.GOOS != toolGOOS || ctxt.GOARCH != toolGOARCH {
// Install cross-compiled binaries to subdirectories of bin.
elem = full
}
p.target = filepath.Join(t.BinDir(), elem)
} }
if ctxt.GOOS == "windows" { if buildContext.GOOS == "windows" {
p.target += ".exe" p.target += ".exe"
} }
} else if p.local {
// Local import turned into absolute path.
// No permanent install target.
p.target = ""
} else { } else {
dir := t.PkgDir() p.target = buildToolchain.pkgpath(p.build.PkgRoot, p, true)
// For gccgo, rewrite p.target with the expected library name.
if _, ok := buildToolchain.(gccgoToolchain); ok {
dir = filepath.Join(filepath.Dir(dir), "gccgo", filepath.Base(dir))
}
p.target = buildToolchain.pkgpath(dir, p)
}
var built time.Time
if fi, err := os.Stat(p.target); err == nil {
built = fi.ModTime()
}
// Build list of full paths to all Go files in the package,
// for use by commands like go fmt.
for _, f := range info.GoFiles {
p.gofiles = append(p.gofiles, filepath.Join(dir, f))
}
for _, f := range info.CgoFiles {
p.gofiles = append(p.gofiles, filepath.Join(dir, f))
}
for _, f := range info.TestGoFiles {
p.gofiles = append(p.gofiles, filepath.Join(dir, f))
}
for _, f := range info.XTestGoFiles {
p.gofiles = append(p.gofiles, filepath.Join(dir, f))
}
sort.Strings(p.gofiles)
srcss := [][]string{
p.GoFiles,
p.CFiles,
p.HFiles,
p.SFiles,
p.CgoFiles,
}
Stale:
for _, srcs := range srcss {
for _, src := range srcs {
if fi, err := os.Stat(filepath.Join(p.Dir, src)); err != nil || fi.ModTime().After(built) {
//println("STALE", p.ImportPath, "needs", src, err)
p.Stale = true
break Stale
}
}
} }
importPaths := p.Imports importPaths := p.Imports
// Packages that use cgo import runtime/cgo implicitly, // Packages that use cgo import runtime/cgo implicitly,
// except runtime/cgo itself. // except runtime/cgo itself.
if len(info.CgoFiles) > 0 && (!p.Standard || p.ImportPath != "runtime/cgo") { if len(p.CgoFiles) > 0 && (!p.Standard || p.ImportPath != "runtime/cgo") {
importPaths = append(importPaths, "runtime/cgo") importPaths = append(importPaths, "runtime/cgo")
} }
// Everything depends on runtime, except runtime and unsafe. // Everything depends on runtime, except runtime and unsafe.
...@@ -360,45 +309,34 @@ Stale: ...@@ -360,45 +309,34 @@ Stale:
importPaths = append(importPaths, "runtime") importPaths = append(importPaths, "runtime")
} }
// Record package under both import path and full directory name. // Build list of full paths to all Go files in the package,
packageCache[dir] = p // for use by commands like go fmt.
packageCache[importPath] = p p.gofiles = stringList(p.GoFiles, p.CgoFiles, p.TestGoFiles, p.XTestGoFiles)
for i := range p.gofiles {
p.gofiles[i] = filepath.Join(p.Dir, p.gofiles[i])
}
sort.Strings(p.gofiles)
// Build list of imported packages and full dependency list. // Build list of imported packages and full dependency list.
imports := make([]*Package, 0, len(p.Imports)) imports := make([]*Package, 0, len(p.Imports))
deps := make(map[string]bool) deps := make(map[string]bool)
for _, path := range importPaths { for i, path := range importPaths {
if path == "C" { if path == "C" {
continue continue
} }
deps[path] = true p1 := loadImport(path, p.Dir, stk, p.build.ImportPos[path])
p1 := loadPackage(path, stk) if p1.local {
if p1.Error != nil { path = p1.Dir
if info.ImportPos != nil && len(info.ImportPos[path]) > 0 { importPaths[i] = path
pos := info.ImportPos[path][0]
p1.Error.Pos = pos.String()
}
} }
deps[path] = true
imports = append(imports, p1) imports = append(imports, p1)
for _, dep := range p1.Deps { for _, dep := range p1.Deps {
deps[dep] = true deps[dep] = true
} }
if p1.Stale {
p.Stale = true
}
if p1.Incomplete { if p1.Incomplete {
p.Incomplete = true p.Incomplete = true
} }
// p1.target can be empty only if p1 is not a real package,
// such as package unsafe or the temporary packages
// created during go test.
if !p.Stale && p1.target != "" {
if fi, err := os.Stat(p1.target); err != nil || fi.ModTime().After(built) {
//println("STALE", p.ImportPath, "needs", p1.target, err)
//println("BUILT", built.String(), "VS", fi.ModTime().String())
p.Stale = true
}
}
} }
p.imports = imports p.imports = imports
...@@ -418,17 +356,193 @@ Stale: ...@@ -418,17 +356,193 @@ Stale:
} }
} }
// unsafe is a fake package and is never out-of-date. // unsafe is a fake package.
if p.Standard && p.ImportPath == "unsafe" { if p.Standard && p.ImportPath == "unsafe" {
p.Stale = false
p.target = "" p.target = ""
} }
p.Target = p.target p.Target = p.target
return p return p
} }
// packageList returns the list of packages in the dag rooted at roots
// as visited in a depth-first post-order traversal.
func packageList(roots []*Package) []*Package {
seen := map[*Package]bool{}
all := []*Package{}
var walk func(*Package)
walk = func(p *Package) {
if seen[p] {
return
}
seen[p] = true
for _, p1 := range p.deps {
walk(p1)
}
all = append(all, p)
}
for _, root := range roots {
walk(root)
}
return all
}
// computeStale computes the Stale flag in the package dag that starts
// at the named pkgs (command-line arguments).
func computeStale(pkgs []*Package) {
topRoot := map[string]bool{}
for _, p := range pkgs {
topRoot[p.Root] = true
}
for _, p := range packageList(pkgs) {
p.Stale = isStale(p, topRoot)
}
}
// isStale reports whether package p needs to be rebuilt.
func isStale(p *Package, topRoot map[string]bool) bool {
if p.Standard && p.ImportPath == "unsafe" {
// fake, builtin package
return false
}
if p.Error != nil {
return true
}
// A package without Go sources means we only found
// the installed .a file. Since we don't know how to rebuild
// it, it can't be stale, even if -a is set. This enables binary-only
// distributions of Go packages, although such binaries are
// only useful with the specific version of the toolchain that
// created them.
if len(p.gofiles) == 0 {
return false
}
if buildA || p.target == "" || p.Stale {
return true
}
// Package is stale if completely unbuilt.
var built time.Time
if fi, err := os.Stat(p.target); err == nil {
built = fi.ModTime()
}
if built.IsZero() {
return true
}
olderThan := func(file string) bool {
fi, err := os.Stat(file)
return err != nil || fi.ModTime().After(built)
}
// Package is stale if a dependency is, or if a dependency is newer.
for _, p1 := range p.deps {
if p1.Stale || p1.target != "" && olderThan(p1.target) {
return true
}
}
// As a courtesy to developers installing new versions of the compiler
// frequently, define that packages are stale if they are
// older than the compiler, and commands if they are older than
// the linker. This heuristic will not work if the binaries are back-dated,
// as some binary distributions may do, but it does handle a very
// common case. See issue 3036.
if olderThan(buildToolchain.compiler()) {
return true
}
if p.build.IsCommand() && olderThan(buildToolchain.linker()) {
return true
}
// Have installed copy, probably built using current compilers,
// and built after its imported packages. The only reason now
// that we'd have to rebuild it is if the sources were newer than
// the package. If a package p is not in the same tree as any
// package named on the command-line, assume it is up-to-date
// no matter what the modification times on the source files indicate.
// This avoids rebuilding $GOROOT packages when people are
// working outside the Go root, and it effectively makes each tree
// listed in $GOPATH a separate compilation world.
// See issue 3149.
if p.Root != "" && !topRoot[p.Root] {
return false
}
srcs := stringList(p.GoFiles, p.CFiles, p.HFiles, p.SFiles, p.CgoFiles)
for _, src := range srcs {
if olderThan(filepath.Join(p.Dir, src)) {
return true
}
}
return false
}
var cwd, _ = os.Getwd()
var cmdCache = map[string]*Package{}
// loadPackage is like loadImport but is used for command-line arguments,
// not for paths found in import statements. In addition to ordinary import paths,
// loadPackage accepts pseudo-paths beginning with cmd/ to denote commands
// in the Go command directory, as well as paths to those directories.
func loadPackage(arg string, stk *importStack) *Package {
if build.IsLocalImport(arg) {
dir := arg
if !filepath.IsAbs(dir) {
if abs, err := filepath.Abs(dir); err == nil {
// interpret relative to current directory
dir = abs
}
}
if sub, ok := hasSubdir(gorootSrc, dir); ok && strings.HasPrefix(sub, "cmd/") && !strings.Contains(sub[4:], "/") {
arg = sub
}
}
if strings.HasPrefix(arg, "cmd/") && !strings.Contains(arg[4:], "/") {
if p := cmdCache[arg]; p != nil {
return p
}
stk.push(arg)
defer stk.pop()
bp, err := build.ImportDir(filepath.Join(gorootSrc, arg), 0)
bp.ImportPath = arg
bp.Goroot = true
bp.BinDir = gobin
bp.Root = goroot
bp.SrcRoot = gorootSrc
p := new(Package)
cmdCache[arg] = p
p.load(stk, bp, err)
if p.Error == nil && p.Name != "main" {
p.Error = &PackageError{
ImportStack: stk.copy(),
Err: fmt.Sprintf("expected package main but found package %s in %s", p.Name, p.Dir),
}
}
return p
}
// Wasn't a command; must be a package.
// If it is a local import path but names a standard package,
// we treat it as if the user specified the standard package.
// This lets you run go test ./ioutil in package io and be
// referring to io/ioutil rather than a hypothetical import of
// "./ioutil".
if build.IsLocalImport(arg) {
bp, _ := build.ImportDir(filepath.Join(cwd, arg), build.FindOnly)
if bp.ImportPath != "" && bp.ImportPath != "." {
arg = bp.ImportPath
}
}
return loadImport(arg, cwd, stk, nil)
}
// packages returns the packages named by the // packages returns the packages named by the
// command line arguments 'args'. If a named package // command line arguments 'args'. If a named package
// cannot be loaded at all (for example, if the directory does not exist), // cannot be loaded at all (for example, if the directory does not exist),
...@@ -438,11 +552,8 @@ Stale: ...@@ -438,11 +552,8 @@ Stale:
// package is still returned, with p.Incomplete = true // package is still returned, with p.Incomplete = true
// and details in p.DepsErrors. // and details in p.DepsErrors.
func packages(args []string) []*Package { func packages(args []string) []*Package {
args = importPaths(args)
var pkgs []*Package var pkgs []*Package
var stk importStack for _, pkg := range packagesAndErrors(args) {
for _, arg := range args {
pkg := loadPackage(arg, &stk)
if pkg.Error != nil { if pkg.Error != nil {
errorf("can't load package: %s", pkg.Error) errorf("can't load package: %s", pkg.Error)
continue continue
...@@ -452,17 +563,24 @@ func packages(args []string) []*Package { ...@@ -452,17 +563,24 @@ func packages(args []string) []*Package {
return pkgs return pkgs
} }
// packagesAndErrors is like 'packages' but returns a // packagesAndErrors is like 'packages' but returns a
// *Package for every argument, even the ones that // *Package for every argument, even the ones that
// cannot be loaded at all. // cannot be loaded at all.
// The packages that fail to load will have p.Error != nil. // The packages that fail to load will have p.Error != nil.
func packagesAndErrors(args []string) []*Package { func packagesAndErrors(args []string) []*Package {
if len(args) > 0 && strings.HasSuffix(args[0], ".go") {
return []*Package{goFilesPackage(args)}
}
args = importPaths(args) args = importPaths(args)
var pkgs []*Package var pkgs []*Package
var stk importStack var stk importStack
for _, arg := range args { for _, arg := range args {
pkgs = append(pkgs, loadPackage(arg, &stk)) pkgs = append(pkgs, loadPackage(arg, &stk))
} }
computeStale(pkgs)
return pkgs return pkgs
} }
...@@ -490,3 +608,26 @@ func packagesForBuild(args []string) []*Package { ...@@ -490,3 +608,26 @@ func packagesForBuild(args []string) []*Package {
exitIfErrors() exitIfErrors()
return pkgs return pkgs
} }
// hasSubdir reports whether dir is a subdirectory of
// (possibly multiple levels below) root.
// If so, it sets rel to the path fragment that must be
// appended to root to reach dir.
func hasSubdir(root, dir string) (rel string, ok bool) {
if p, err := filepath.EvalSymlinks(root); err == nil {
root = p
}
if p, err := filepath.EvalSymlinks(dir); err == nil {
dir = p
}
const sep = string(filepath.Separator)
root = filepath.Clean(root)
if !strings.HasSuffix(root, sep) {
root += sep
}
dir = filepath.Clean(dir)
if !strings.HasPrefix(dir, root) {
return "", false
}
return filepath.ToSlash(dir[len(root):]), true
}
...@@ -12,14 +12,12 @@ import ( ...@@ -12,14 +12,12 @@ import (
) )
var cmdRun = &Command{ var cmdRun = &Command{
UsageLine: "run [-a] [-n] [-x] gofiles... [arguments...]", UsageLine: "run [build flags] gofiles... [arguments...]",
Short: "compile and run Go program", Short: "compile and run Go program",
Long: ` Long: `
Run compiles and runs the main package comprising the named Go source files. Run compiles and runs the main package comprising the named Go source files.
The -a flag forces reinstallation of packages that are already up-to-date. For more about build flags, see 'go help build'.
The -n flag prints the commands but does not run them.
The -x flag prints the commands.
See also: go build. See also: go build.
`, `,
...@@ -46,7 +44,7 @@ func runRun(cmd *Command, args []string) { ...@@ -46,7 +44,7 @@ func runRun(cmd *Command, args []string) {
i++ i++
} }
files, cmdArgs := args[:i], args[i:] files, cmdArgs := args[:i], args[i:]
p := goFilesPackage(files, "") p := goFilesPackage(files)
p.target = "" // must build - not up to date p.target = "" // must build - not up to date
a1 := b.action(modeBuild, modeBuild, p) a1 := b.action(modeBuild, modeBuild, p)
a := &action{f: (*builder).runProgram, args: cmdArgs, deps: []*action{a1}} a := &action{f: (*builder).runProgram, args: cmdArgs, deps: []*action{a1}}
......
#!/bin/bash
# Copyright 2012 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.
set -e
go build -o testgo
ok=true
# Test that error messages have file:line information
# at beginning of line.
for i in testdata/errmsg/*.go
do
# TODO: |cat should not be necessary here but is.
./testgo test $i 2>&1 | cat >err.out || true
if ! grep -q "^$i:" err.out; then
echo "$i: missing file:line in error message"
cat err.out
ok=false
fi
done
# Test local (./) imports.
./testgo build -o hello testdata/local/easy.go
./hello >hello.out
if ! grep -q '^easysub\.Hello' hello.out; then
echo "testdata/local/easy.go did not generate expected output"
cat hello.out
ok=false
fi
./testgo build -o hello testdata/local/hard.go
./hello >hello.out
if ! grep -q '^sub\.Hello' hello.out || ! grep -q '^subsub\.Hello' hello.out ; then
echo "testdata/local/hard.go did not generate expected output"
cat hello.out
ok=false
fi
rm -f err.out hello.out hello
# Test that go install x.go fails.
if ./testgo install testdata/local/easy.go >/dev/null 2>&1; then
echo "go install testdata/local/easy.go succeeded"
ok=false
fi
if $ok; then
echo PASS
else
echo FAIL
exit 1
fi
...@@ -11,7 +11,6 @@ import ( ...@@ -11,7 +11,6 @@ import (
"go/build" "go/build"
"go/doc" "go/doc"
"go/parser" "go/parser"
"go/scanner"
"go/token" "go/token"
"os" "os"
"os/exec" "os/exec"
...@@ -33,7 +32,7 @@ func init() { ...@@ -33,7 +32,7 @@ func init() {
var cmdTest = &Command{ var cmdTest = &Command{
CustomFlags: true, CustomFlags: true,
UsageLine: "test [-c] [-i] [-p n] [-x] [importpath...] [flags for test binary]", UsageLine: "test [-c] [-i] [build flags] [packages] [flags for test binary]",
Short: "test packages", Short: "test packages",
Long: ` Long: `
'Go test' automates testing the packages named by the import paths. 'Go test' automates testing the packages named by the import paths.
...@@ -56,7 +55,7 @@ with source in the current directory, including tests, and runs the tests. ...@@ -56,7 +55,7 @@ with source in the current directory, including tests, and runs the tests.
The package is built in a temporary directory so it does not interfere with the The package is built in a temporary directory so it does not interfere with the
non-test installation. non-test installation.
The flags handled by 'go test' itself are: In addition to the build flags, the flags handled by 'go test' itself are:
-c Compile the test binary to pkg.test but do not run it. -c Compile the test binary to pkg.test but do not run it.
...@@ -64,16 +63,11 @@ The flags handled by 'go test' itself are: ...@@ -64,16 +63,11 @@ The flags handled by 'go test' itself are:
Install packages that are dependencies of the test. Install packages that are dependencies of the test.
Do not run the test. Do not run the test.
-p n
Compile and test up to n packages in parallel.
The default value is the number of CPUs available.
-x Print each subcommand go test executes.
The test binary also accepts flags that control execution of the test; these The test binary also accepts flags that control execution of the test; these
flags are also accessible by 'go test'. See 'go help testflag' for details. flags are also accessible by 'go test'. See 'go help testflag' for details.
See 'go help importpath' for more about import paths. For more about build flags, see 'go help build'.
For more about specifying packages, see 'go help packages'.
See also: go build, go vet. See also: go build, go vet.
`, `,
...@@ -134,7 +128,7 @@ directory containing the package sources, has its own flags: ...@@ -134,7 +128,7 @@ directory containing the package sources, has its own flags:
The default is 1 second. The default is 1 second.
-test.cpu 1,2,4 -test.cpu 1,2,4
Specify a list of GOMAXPROCS values for which the tests or Specify a list of GOMAXPROCS values for which the tests or
benchmarks should be executed. The default is the current value benchmarks should be executed. The default is the current value
of GOMAXPROCS. of GOMAXPROCS.
...@@ -265,10 +259,10 @@ func runTest(cmd *Command, args []string) { ...@@ -265,10 +259,10 @@ func runTest(cmd *Command, args []string) {
} }
for _, p := range pkgs { for _, p := range pkgs {
// Dependencies for each test. // Dependencies for each test.
for _, path := range p.info.Imports { for _, path := range p.Imports {
deps[path] = true deps[path] = true
} }
for _, path := range p.info.TestImports { for _, path := range p.TestImports {
deps[path] = true deps[path] = true
} }
} }
...@@ -307,17 +301,15 @@ func runTest(cmd *Command, args []string) { ...@@ -307,17 +301,15 @@ func runTest(cmd *Command, args []string) {
for _, p := range pkgs { for _, p := range pkgs {
buildTest, runTest, printTest, err := b.test(p) buildTest, runTest, printTest, err := b.test(p)
if err != nil { if err != nil {
if list, ok := err.(scanner.ErrorList); ok { str := err.Error()
const n = 10 if strings.HasPrefix(str, "\n") {
if len(list) > n { str = str[1:]
list = list[:n] }
} if p.ImportPath != "" {
for _, err := range list { errorf("# %s\n%s", p.ImportPath, str)
errorf("%s", err) } else {
} errorf("%s", str)
continue
} }
errorf("%s", err)
continue continue
} }
builds = append(builds, buildTest) builds = append(builds, buildTest)
...@@ -380,7 +372,7 @@ func runTest(cmd *Command, args []string) { ...@@ -380,7 +372,7 @@ func runTest(cmd *Command, args []string) {
} }
func (b *builder) test(p *Package) (buildAction, runAction, printAction *action, err error) { func (b *builder) test(p *Package) (buildAction, runAction, printAction *action, err error) {
if len(p.info.TestGoFiles)+len(p.info.XTestGoFiles) == 0 { if len(p.TestGoFiles)+len(p.XTestGoFiles) == 0 {
build := &action{p: p} build := &action{p: p}
run := &action{p: p} run := &action{p: p}
print := &action{f: (*builder).notest, p: p, deps: []*action{build}} print := &action{f: (*builder).notest, p: p, deps: []*action{build}}
...@@ -393,20 +385,23 @@ func (b *builder) test(p *Package) (buildAction, runAction, printAction *action, ...@@ -393,20 +385,23 @@ func (b *builder) test(p *Package) (buildAction, runAction, printAction *action,
// pmain - pkg.test binary // pmain - pkg.test binary
var ptest, pxtest, pmain *Package var ptest, pxtest, pmain *Package
// go/build does not distinguish the dependencies used var imports, ximports []*Package
// by the TestGoFiles from the dependencies used by the
// XTestGoFiles, so we build one list and use it for both
// ptest and pxtest. No harm done.
var imports []*Package
var stk importStack var stk importStack
stk.push(p.ImportPath + "_test") stk.push(p.ImportPath + "_test")
for _, path := range p.info.TestImports { for _, path := range p.TestImports {
p1 := loadPackage(path, &stk) p1 := loadImport(path, p.Dir, &stk, p.build.TestImportPos[path])
if p1.Error != nil { if p1.Error != nil {
return nil, nil, nil, p1.Error return nil, nil, nil, p1.Error
} }
imports = append(imports, p1) imports = append(imports, p1)
} }
for _, path := range p.XTestImports {
p1 := loadImport(path, p.Dir, &stk, p.build.XTestImportPos[path])
if p1.Error != nil {
return nil, nil, nil, p1.Error
}
ximports = append(ximports, p1)
}
stk.pop() stk.pop()
// Use last element of import path, not package name. // Use last element of import path, not package name.
...@@ -429,7 +424,7 @@ func (b *builder) test(p *Package) (buildAction, runAction, printAction *action, ...@@ -429,7 +424,7 @@ func (b *builder) test(p *Package) (buildAction, runAction, printAction *action,
// 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.work, filepath.FromSlash(p.ImportPath+"/_test"))
ptestObj := buildToolchain.pkgpath(testDir, p) ptestObj := buildToolchain.pkgpath(testDir, p, false)
// Create the directory for the .a files. // Create the directory for the .a files.
ptestDir, _ := filepath.Split(ptestObj) ptestDir, _ := filepath.Split(ptestObj)
...@@ -441,17 +436,27 @@ func (b *builder) test(p *Package) (buildAction, runAction, printAction *action, ...@@ -441,17 +436,27 @@ func (b *builder) test(p *Package) (buildAction, runAction, printAction *action,
} }
// Test package. // Test package.
if len(p.info.TestGoFiles) > 0 { if len(p.TestGoFiles) > 0 {
ptest = new(Package) ptest = new(Package)
*ptest = *p *ptest = *p
ptest.GoFiles = nil ptest.GoFiles = nil
ptest.GoFiles = append(ptest.GoFiles, p.GoFiles...) ptest.GoFiles = append(ptest.GoFiles, p.GoFiles...)
ptest.GoFiles = append(ptest.GoFiles, p.info.TestGoFiles...) ptest.GoFiles = append(ptest.GoFiles, p.TestGoFiles...)
ptest.target = "" ptest.target = ""
ptest.Imports = stringList(p.info.Imports, p.info.TestImports) ptest.Imports = stringList(p.Imports, p.TestImports)
ptest.imports = append(append([]*Package{}, p.imports...), imports...) ptest.imports = append(append([]*Package{}, p.imports...), imports...)
ptest.pkgdir = testDir ptest.pkgdir = testDir
ptest.fake = true ptest.fake = true
ptest.build = new(build.Package)
*ptest.build = *p.build
m := map[string][]token.Position{}
for k, v := range p.build.ImportPos {
m[k] = append(m[k], v...)
}
for k, v := range p.build.TestImportPos {
m[k] = append(m[k], v...)
}
ptest.build.ImportPos = m
a := b.action(modeBuild, modeBuild, ptest) a := b.action(modeBuild, modeBuild, ptest)
a.objdir = testDir + string(filepath.Separator) a.objdir = testDir + string(filepath.Separator)
a.objpkg = ptestObj a.objpkg = ptestObj
...@@ -462,23 +467,23 @@ func (b *builder) test(p *Package) (buildAction, runAction, printAction *action, ...@@ -462,23 +467,23 @@ func (b *builder) test(p *Package) (buildAction, runAction, printAction *action,
} }
// External test package. // External test package.
if len(p.info.XTestGoFiles) > 0 { if len(p.XTestGoFiles) > 0 {
pxtest = &Package{ pxtest = &Package{
Name: p.Name + "_test", Name: p.Name + "_test",
ImportPath: p.ImportPath + "_test", ImportPath: p.ImportPath + "_test",
Dir: p.Dir, Dir: p.Dir,
GoFiles: p.info.XTestGoFiles, GoFiles: p.XTestGoFiles,
Imports: p.info.TestImports, Imports: p.XTestImports,
t: p.t, build: &build.Package{
info: &build.DirInfo{}, ImportPos: p.build.XTestImportPos,
imports: imports, },
pkgdir: testDir, imports: append(ximports, ptest),
fake: true, pkgdir: testDir,
fake: true,
} }
pxtest.imports = append(pxtest.imports, ptest)
a := b.action(modeBuild, modeBuild, pxtest) a := b.action(modeBuild, modeBuild, pxtest)
a.objdir = testDir + string(filepath.Separator) a.objdir = testDir + string(filepath.Separator)
a.objpkg = buildToolchain.pkgpath(testDir, pxtest) a.objpkg = buildToolchain.pkgpath(testDir, pxtest, false)
a.target = a.objpkg a.target = a.objpkg
} }
...@@ -487,9 +492,8 @@ func (b *builder) test(p *Package) (buildAction, runAction, printAction *action, ...@@ -487,9 +492,8 @@ func (b *builder) test(p *Package) (buildAction, runAction, printAction *action,
Name: "main", Name: "main",
Dir: testDir, Dir: testDir,
GoFiles: []string{"_testmain.go"}, GoFiles: []string{"_testmain.go"},
t: p.t,
info: &build.DirInfo{},
imports: []*Package{ptest}, imports: []*Package{ptest},
build: &build.Package{},
fake: true, fake: true,
} }
if pxtest != nil { if pxtest != nil {
...@@ -498,11 +502,11 @@ func (b *builder) test(p *Package) (buildAction, runAction, printAction *action, ...@@ -498,11 +502,11 @@ func (b *builder) test(p *Package) (buildAction, runAction, printAction *action,
// The generated main also imports testing and regexp. // The generated main also imports testing and regexp.
stk.push("testmain") stk.push("testmain")
ptesting := loadPackage("testing", &stk) ptesting := loadImport("testing", "", &stk, nil)
if ptesting.Error != nil { if ptesting.Error != nil {
return nil, nil, nil, ptesting.Error return nil, nil, nil, ptesting.Error
} }
pregexp := loadPackage("regexp", &stk) pregexp := loadImport("regexp", "", &stk, nil)
if pregexp.Error != nil { if pregexp.Error != nil {
return nil, nil, nil, pregexp.Error return nil, nil, nil, pregexp.Error
} }
...@@ -511,7 +515,7 @@ func (b *builder) test(p *Package) (buildAction, runAction, printAction *action, ...@@ -511,7 +515,7 @@ func (b *builder) test(p *Package) (buildAction, runAction, printAction *action,
a := b.action(modeBuild, modeBuild, pmain) a := b.action(modeBuild, 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) + b.exe a.target = filepath.Join(testDir, testBinary) + exeSuffix
pmainAction := a pmainAction := a
if testC { if testC {
...@@ -520,7 +524,7 @@ func (b *builder) test(p *Package) (buildAction, runAction, printAction *action, ...@@ -520,7 +524,7 @@ func (b *builder) test(p *Package) (buildAction, runAction, printAction *action,
f: (*builder).install, f: (*builder).install,
deps: []*action{pmainAction}, deps: []*action{pmainAction},
p: pmain, p: pmain,
target: testBinary + b.exe, target: testBinary + exeSuffix,
} }
printAction = &action{p: p, deps: []*action{runAction}} // nop printAction = &action{p: p, deps: []*action{runAction}} // nop
} else { } else {
...@@ -664,14 +668,13 @@ func isTest(name, prefix string) bool { ...@@ -664,14 +668,13 @@ func isTest(name, prefix string) bool {
func writeTestmain(out string, p *Package) error { func writeTestmain(out string, p *Package) error {
t := &testFuncs{ t := &testFuncs{
Package: p, Package: p,
Info: p.info,
} }
for _, file := range p.info.TestGoFiles { for _, file := range p.TestGoFiles {
if err := t.load(filepath.Join(p.Dir, file), "_test", &t.NeedTest); err != nil { if err := t.load(filepath.Join(p.Dir, file), "_test", &t.NeedTest); err != nil {
return err return err
} }
} }
for _, file := range p.info.XTestGoFiles { for _, file := range p.XTestGoFiles {
if err := t.load(filepath.Join(p.Dir, file), "_xtest", &t.NeedXtest); err != nil { if err := t.load(filepath.Join(p.Dir, file), "_xtest", &t.NeedXtest); err != nil {
return err return err
} }
...@@ -695,7 +698,6 @@ type testFuncs struct { ...@@ -695,7 +698,6 @@ type testFuncs struct {
Benchmarks []testFunc Benchmarks []testFunc
Examples []testFunc Examples []testFunc
Package *Package Package *Package
Info *build.DirInfo
NeedTest bool NeedTest bool
NeedXtest bool NeedXtest bool
} }
...@@ -711,7 +713,7 @@ var testFileSet = token.NewFileSet() ...@@ -711,7 +713,7 @@ var testFileSet = token.NewFileSet()
func (t *testFuncs) load(filename, pkg string, seen *bool) error { func (t *testFuncs) load(filename, pkg string, seen *bool) error {
f, err := parser.ParseFile(testFileSet, filename, nil, parser.ParseComments) f, err := parser.ParseFile(testFileSet, filename, nil, parser.ParseComments)
if err != nil { if err != nil {
return err return expandScanner(err)
} }
for _, d := range f.Decls { for _, d := range f.Decls {
n, ok := d.(*ast.FuncDecl) n, ok := d.(*ast.FuncDecl)
......
package foo
import "bar"
package foo_test
import "bar"
package main
import "./easysub"
func main() {
easysub.Hello()
}
package easysub
import "fmt"
func Hello() {
fmt.Println("easysub.Hello")
}
package main
import "./sub"
func main() {
sub.Hello()
}
package sub
import (
"fmt"
subsub "./sub"
)
func Hello() {
fmt.Println("sub.Hello")
subsub.Hello()
}
package subsub
import "fmt"
func Hello() {
fmt.Println("subsub.Hello")
}
...@@ -10,6 +10,7 @@ import ( ...@@ -10,6 +10,7 @@ import (
"fmt" "fmt"
"os" "os"
"os/exec" "os/exec"
"path/filepath"
"regexp" "regexp"
"strings" "strings"
) )
...@@ -269,6 +270,38 @@ type vcsPath struct { ...@@ -269,6 +270,38 @@ type vcsPath struct {
regexp *regexp.Regexp // cached compiled form of re regexp *regexp.Regexp // cached compiled form of re
} }
// vcsForDir inspects dir and its parents to determine the
// version control system and code repository to use.
// On return, root is the import path
// corresponding to the root of the repository
// (thus root is a prefix of importPath).
func vcsForDir(p *Package) (vcs *vcsCmd, root string, err error) {
// Clean and double-check that dir is in (a subdirectory of) srcRoot.
dir := filepath.Clean(p.Dir)
srcRoot := filepath.Clean(p.build.SrcRoot)
if len(dir) <= len(srcRoot) || dir[len(srcRoot)] != filepath.Separator {
return nil, "", fmt.Errorf("directory %q is outside source root %q", dir, srcRoot)
}
for len(dir) > len(srcRoot) {
for _, vcs := range vcsList {
if fi, err := os.Stat(filepath.Join(dir, "."+vcs.cmd)); err == nil && fi.IsDir() {
return vcs, dir[len(srcRoot)+1:], nil
}
}
// Move to parent.
ndir := filepath.Dir(dir)
if len(ndir) >= len(dir) {
// Shouldn't happen, but just in case, stop.
break
}
dir = ndir
}
return nil, "", fmt.Errorf("directory %q is not using a known version control system", dir)
}
// vcsForImportPath analyzes importPath to determine the // vcsForImportPath analyzes importPath to determine the
// version control system, and code repository to use. // version control system, and code repository to use.
// On return, repo is the repository URL and root is the // On return, repo is the repository URL and root is the
......
...@@ -6,13 +6,13 @@ package main ...@@ -6,13 +6,13 @@ package main
var cmdVet = &Command{ var cmdVet = &Command{
Run: runVet, Run: runVet,
UsageLine: "vet [importpath...]", UsageLine: "vet [packages]",
Short: "run go tool vet on packages", Short: "run go tool vet on packages",
Long: ` Long: `
Vet runs the Go vet command on the packages named by the import paths. Vet runs the Go vet command on the packages named by the import paths.
For more about vet, see 'godoc vet'. For more about vet, see 'godoc vet'.
For more about import paths, see 'go help importpath'. For more about specifying packages, see 'go help packages'.
To run the vet tool with specific options, run 'go tool vet'. To run the vet tool with specific options, run 'go tool vet'.
......
...@@ -3,6 +3,29 @@ ...@@ -3,6 +3,29 @@
# 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.
# Environment variables that control make.bash:
#
# GOROOT_FINAL: The expected final Go root, baked into binaries.
# The default is the location of the Go tree during the build.
#
# GOHOSTARCH: The architecture for host tools (compilers and
# binaries). Binaries of this type must be executable on the current
# system, so the only common reason to set this is to set
# GOHOSTARCH=386 on an amd64 machine.
#
# GOARCH: The target architecture for installed packages and tools.
#
# GOOS: The target operating system for installed packages and tools.
#
# GCFLAGS: Additional 5g/6g/8g arguments to use when
# building the packages and commands.
#
# LDFLAGS: Additional 5l/6l/8l arguments to use when
# building the packages and commands.
#
# CGO_ENABLED: Setting this to 0 disables the use of cgo
# in the built and installed packages and tools.
set -e set -e
if [ ! -f run.bash ]; then if [ ! -f run.bash ]; then
echo 'make.bash must be run from $GOROOT/src' 1>&2 echo 'make.bash must be run from $GOROOT/src' 1>&2
...@@ -88,12 +111,12 @@ echo ...@@ -88,12 +111,12 @@ echo
if [ "$GOHOSTARCH" != "$GOARCH" -o "$GOHOSTOS" != "$GOOS" ]; then if [ "$GOHOSTARCH" != "$GOARCH" -o "$GOHOSTOS" != "$GOOS" ]; then
echo "# Building packages and commands for host, $GOHOSTOS/$GOHOSTARCH." echo "# Building packages and commands for host, $GOHOSTOS/$GOHOSTARCH."
GOOS=$GOHOSTOS GOARCH=$GOHOSTARCH \ GOOS=$GOHOSTOS GOARCH=$GOHOSTARCH \
$GOTOOLDIR/go_bootstrap install -v std $GOTOOLDIR/go_bootstrap install -gcflags "$GCFLAGS" -ldflags "$LDFLAGS" -v std
echo echo
fi fi
echo "# Building packages and commands for $GOOS/$GOARCH." echo "# Building packages and commands for $GOOS/$GOARCH."
$GOTOOLDIR/go_bootstrap install -v std $GOTOOLDIR/go_bootstrap install -gcflags "$GCFLAGS" -ldflags "$LDFLAGS" -v std
echo echo
rm -f $GOTOOLDIR/go_bootstrap rm -f $GOTOOLDIR/go_bootstrap
......
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