)
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",
Long: `
Build compiles the packages named by the import paths,
of source files specifying a single 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,
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.
-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 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'.
+The -o flag specifies the output file name. If not specified, the
+name is packagename.a (for a non-main package) or the base
+name of the first source file (for a main package).
+
+The build flags are shared by the build, install, run, and test commands:
+
+ -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.
`,
var buildV bool // -v flag
var buildX bool // -x flag
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.
func addBuildFlags(cmd *Command) {
cmd.Flag.BoolVar(&buildV, "v", false, "")
cmd.Flag.BoolVar(&buildX, "x", false, "")
cmd.Flag.BoolVar(&buildWork, "work", false, "")
-
- // TODO(rsc): This -t flag is used by buildscript.sh but
- // not documented. Should be documented but the
- // usage lines are getting too long. Probably need to say
- // 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", "")
+ cmd.Flag.Var((*stringsFlag)(&buildGcflags), "gcflags", "")
+ cmd.Flag.Var((*stringsFlag)(&buildLdflags), "ldflags", "")
+ cmd.Flag.Var((*stringsFlag)(&buildGccgoflags), "gccgoflags", "")
+ cmd.Flag.Var((*stringsFlag)(&buildContext.BuildTags), "tags", "")
}
type stringsFlag []string
func (v *stringsFlag) Set(s string) error {
- *v = append(*v, s)
+ *v = strings.Fields(s)
return nil
}
var b builder
b.init()
- var pkgs []*Package
- if len(args) > 0 && strings.HasSuffix(args[0], ".go") {
- pkg := goFilesPackage(args, "")
- pkgs = append(pkgs, pkg)
- } else {
- pkgs = packagesForBuild(args)
- }
+ pkgs := packagesForBuild(args)
if len(pkgs) == 1 && pkgs[0].Name == "main" && *buildO == "" {
_, *buildO = path.Split(pkgs[0].ImportPath)
- if b.goos == "windows" {
+ if goos == "windows" {
*buildO += ".exe"
}
}
}
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",
Long: `
Install compiles and installs the packages named by the import paths,
along with their dependencies.
-The -a flag forces reinstallation 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 -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'.
+For more about the build flags, see 'go help build'.
+For more about specifying packages, see 'go help packages'.
See also: go build, go get, go clean.
`,
func runInstall(cmd *Command, args []string) {
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
b.init()
a := &action{}
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.
-// It does not hold per-package state, because eventually we will
-// build packages in parallel, and the builder will be shared.
+// It does not hold per-package state, because we
+// build packages in parallel, and the builder is shared.
type builder struct {
work string // the temporary work directory (ends in filepath.Separator)
- 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
mkdirCache map[string]bool // a cache of created directories
print func(args ...interface{}) (int, error)
)
var (
- gobin = build.Path[0].BinDir()
- goroot = build.Path[0].Path
+ goroot = filepath.Clean(runtime.GOROOT())
+ 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() {
var err error
b.print = fmt.Print
b.actionCache = make(map[cacheKey]*action)
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 {
b.work = "$WORK"
}
// goFilesPackage creates a package for building a collection of Go files
-// (typically named on the command line). If target is given, the package
-// target is target. Otherwise, the target is named p.a for
+// (typically named on the command line). The target is named p.a for
// 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.
for _, f := range gofiles {
- if !strings.HasSuffix(f, ".go") || strings.Contains(f, "/") || strings.Contains(f, string(filepath.Separator)) {
- fatalf("named files must be in current directory and .go files")
+ if !strings.HasSuffix(f, ".go") {
+ 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
- // command directory.
- var dir []os.FileInfo
+ // command directory. So that local imports resolve
+ // consistently, the files must all be in the same directory.
+ var dirent []os.FileInfo
+ var dir string
for _, file := range gofiles {
fi, err := os.Stat(file)
if err != nil {
if fi.IsDir() {
fatalf("%s is a directory, should be a Go file", file)
}
- dir = append(dir, fi)
- }
- ctxt := buildContext
- ctxt.ReadDir = func(string) ([]os.FileInfo, error) { return dir, nil }
- pwd, _ := os.Getwd()
- 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)
+ dir1, _ := filepath.Split(file)
+ if dir == "" {
+ dir = dir1
+ } else if dir != dir1 {
+ fatalf("named files must all be in one directory; have %s and %s", dir, dir1)
}
+ dirent = append(dirent, fi)
}
- if target != "" {
- pkg.target = target
- } else if pkg.Name == "main" {
- pkg.target = gofiles[0][:len(gofiles[0])-len(".go")]
- } else {
- pkg.target = pkg.Name + ".a"
+ ctxt.ReadDir = func(string) ([]os.FileInfo, error) { return dirent, nil }
+
+ if !filepath.IsAbs(dir) {
+ dir = filepath.Join(cwd, dir)
}
- 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 a
}
- a = &action{p: p, pkgdir: p.t.PkgDir()}
+ a = &action{p: p, pkgdir: p.build.PkgRoot}
if p.pkgdir != "" { // overrides p.t
a.pkgdir = p.pkgdir
}
// 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
// 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" {
var stk importStack
p1 := loadPackage("cmd/cgo", &stk)
}
}
- if !p.Stale && !buildA && p.target != "" {
+ if !p.Stale && p.target != "" {
// p.Stale==false implies that p.target is up-to-date.
// Record target name for use by actions depending on this one.
a.target = p.target
return a
}
- a.objdir = filepath.Join(b.work, filepath.FromSlash(a.p.ImportPath+"/_obj")) + string(filepath.Separator)
- a.objpkg = buildToolchain.pkgpath(b.work, a.p)
+ prefix := "obj"
+ 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"
switch mode {
if a.link {
// An executable file.
// (This is the name of a temporary file.)
- a.target = a.objdir + "a.out" + b.exe
+ a.target = a.objdir + "a.out" + exeSuffix
}
}
// Run cgo.
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
// cgo and non-cgo worlds, so it necessarily has files in both.
// In that case gcc only gets the gcc_* files.
// Prepare Go import path list.
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.
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
} else {
objects = append(objects, out)
// Copy .h files named for goos or goarch or goos_goarch
// to names using GOOS and GOARCH.
// For example, defs_linux_amd64.h becomes defs_GOOS_GOARCH.h.
- _goos_goarch := "_" + b.goos + "_" + b.goarch + ".h"
- _goos := "_" + b.goos + ".h"
- _goarch := "_" + b.goarch + ".h"
+ _goos_goarch := "_" + goos + "_" + goarch + ".h"
+ _goos := "_" + goos + ".h"
+ _goarch := "_" + goarch + ".h"
for _, file := range a.p.HFiles {
switch {
case strings.HasSuffix(file, _goos_goarch):
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
}
case strings.HasSuffix(file, _goarch):
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
}
case strings.HasSuffix(file, _goos):
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
}
}
}
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 {
return err
}
// Assemble .s files.
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 {
return err
}
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
func (b *builder) includeArgs(flag string, all []*action) []string {
inc := []string{}
incMap := map[string]bool{
- b.work: true, // handled later
- build.Path[0].PkgDir(): true, // goroot
- "": true, // ignore empty strings
+ b.work + "/obj": true, // handled later
+ gorootPkg: true,
+ "": true, // ignore empty strings
}
// Look in the temporary space for results of test-specific actions.
// This is the $WORK/my/package/_test directory for the
// package being built, so there are few of these.
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
inc = append(inc, flag, dir)
}
// Also look in $WORK for any non-test packages that have
// been built but not installed.
- inc = append(inc, flag, b.work)
+ inc = append(inc, flag, b.work+"/obj")
// Finally, look in the installed package directories for each action.
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 {
dir = filepath.Join(filepath.Dir(dir), "gccgo", filepath.Base(dir))
}
}
// 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 {
b.showcmd("", "cp %s %s", src, dst)
if buildN {
func (b *builder) showOutput(dir, desc, out string) {
prefix := "# " + desc
suffix := "\n" + out
- pwd, _ := os.Getwd()
- if reldir, err := filepath.Rel(pwd, dir); err == nil && len(reldir) < len(dir) {
+ if reldir := shortPath(dir); reldir != dir {
suffix = strings.Replace(suffix, " "+dir, " "+reldir, -1)
suffix = strings.Replace(suffix, "\n"+dir, "\n"+reldir, -1)
}
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
// made relative to the current directory if they would be shorter.
func relPaths(paths []string) []string {
// run runs the command given by cmdline in the directory dir.
// If the commnd fails, run prints information about the failure
// 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...)
if len(out) > 0 {
if out[len(out)-1] != '\n' {
if desc == "" {
desc = b.fmtcmd(dir, "%s", strings.Join(stringList(cmdargs...), " "))
}
- b.showOutput(dir, desc, string(out))
+ b.showOutput(shortenDir, desc, string(out))
if err != nil {
err = errPrintedOutput
}
type toolchain interface {
// gc runs the compiler in a specific directory on a set of files
- // and returns the name of the generated output file.
- gc(b *builder, p *Package, obj string, importArgs []string, gofiles []string) (ofile string, err error)
+ // and returns the name of the generated output file.
+ // 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
// to produce an output file.
cc(b *builder, p *Package, objdir, ofile, cfile string) error
// 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
// 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
// an archive from a set of object files.
// typically it is run in the object directory.
pack(b *builder, p *Package, objDir, afile string, ofiles []string) error
// 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
+
+ compiler() string
+ linker() string
}
type goToolchain struct{}
var buildToolchain toolchain
func init() {
+ // TODO(rsc): Decide how to trigger gccgo. Issue 3157.
if os.Getenv("GC") == "gccgo" {
buildToolchain = gccgoToolchain{}
} else {
// The Go toolchain.
-func (goToolchain) gc(b *builder, p *Package, obj string, importArgs []string, gofiles []string) (ofile string, err error) {
- out := "_go_." + b.arch
+func (goToolchain) compiler() string {
+ 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
gcargs := []string{"-p", p.ImportPath}
if p.Standard && p.ImportPath == "runtime" {
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 {
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 {
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 {
- return filepath.Join(basedir, filepath.FromSlash(p.ImportPath+".a"))
+func (goToolchain) pkgpath(basedir string, p *Package, install bool) string {
+ 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 {
for _, f := range ofiles {
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 {
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 {
- 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)
- 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,
- "-DGOOS_"+b.goos, "-DGOARCH_"+b.goarch, cfile)
+ "-DGOOS_"+goos, "-DGOARCH_"+goarch, cfile)
}
// 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"
ofile = obj + out
gcargs := []string{"-g"}
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 {
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 {
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 {
- afile := filepath.Join(basedir, filepath.FromSlash(p.ImportPath+".a"))
- // prepend "lib" to the basename
+func (gccgoToolchain) pkgpath(basedir string, p *Package, install bool) string {
+ // NOTE: Apparently gccgo does not distinguish different trees
+ // 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))
}
for _, f := range ofiles {
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 {
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 {
- 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)
- 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,
- "-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.
func (b *builder) gcc(p *Package, out string, flags []string, cfile string) error {
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
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
// Definitely want -fPIC but on Windows gcc complains
// "-fPIC ignored for target (all code is position independent)"
- if b.goos != "windows" {
+ if goos != "windows" {
a = append(a, "-fPIC")
}
- switch b.arch {
+ switch archChar {
case "8":
a = append(a, "-m32")
case "6":
// gcc-4.5 and beyond require explicit "-pthread" flag
// for multithreading with pthread library.
if buildContext.CgoEnabled {
- switch b.goos {
+ switch goos {
case "windows":
a = append(a, "-mthreads")
default:
var cgoRe = regexp.MustCompile(`[/\\:]`)
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")
}
- cgoCFLAGS := stringList(envList("CGO_CFLAGS"), p.info.CgoCFLAGS)
- cgoLDFLAGS := stringList(envList("CGO_LDFLAGS"), p.info.CgoLDFLAGS)
+ cgoCFLAGS := stringList(envList("CGO_CFLAGS"), p.CgoCFLAGS)
+ 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)
if err != nil {
b.showOutput(p.Dir, "pkg-config --cflags "+strings.Join(pkgs, " "), string(out))
if _, ok := buildToolchain.(gccgoToolchain); ok {
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
}
outGo = append(outGo, gofiles...)
// 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 {
return nil, nil, err
}
// cgo -dynimport
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
}
// 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 {
return nil, nil, err
}
)
var cmdClean = &Command{
- UsageLine: "clean [-i] [-r] [-n] [-x] [importpath...]",
+ UsageLine: "clean [-i] [-r] [-n] [-x] [packages]",
Short: "remove object files",
Long: `
Clean removes object files from package source directories.
dependencies of the packages named by the import paths.
The -x flag causes clean to print remove commands as it executes them.
+
+For more about specifying packages, see 'go help packages'.
`,
}
Additional help topics:
gopath GOPATH environment variable
- importpath description of import paths
+ packages description of package lists
remote remote import path syntax
testflag description of testing flags
testfunc description of testing functions
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,
along with their dependencies, but it does not install the results.
Otherwise build compiles the packages but discards the results,
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.
-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 default is the number of CPUs available.
+The build flags are shared by the build, install, run, and test commands:
-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.
Usage:
- go clean [-i] [-r] [-n] [-x] [importpath...]
+ go clean [-i] [-r] [-n] [-x] [packages]
Clean removes object files from package source directories.
The go command builds most objects in a temporary directory,
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
Usage:
- go doc [importpath...]
+ go doc [packages]
Doc runs the godoc command on the packages named by the
import paths.
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.
Usage:
- go fix [importpath...]
+ go fix [packages]
Fix runs the Go fix command on the packages named by the import paths.
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'.
Usage:
- go fmt [importpath...]
+ go fmt [packages]
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.
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.
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,
along with their dependencies.
before resolving dependencies or building the code.
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.
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
download, see 'go help remote'.
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,
along with their dependencies.
-The -a flag forces reinstallation 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 -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'.
+For more about the build flags, see 'go help build'.
+For more about specifying packages, see 'go help packages'.
See also: go build, go get, go clean.
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.
a non-nil Error field; other information may or may not be missing
(zeroed).
-For more about import paths, see 'go help importpath'.
+For more about specifying packages, see 'go help packages'.
Compile and run Go program
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.
-The -a flag forces reinstallation of packages that are already up-to-date.
-The -n flag prints the commands but does not run them.
-The -x flag prints the commands.
+For more about build flags, see 'go help build'.
See also: go build.
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.
It prints a summary of the test results in the format:
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.
-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
non-test installation.
-See 'go help testflag' for details about flags handled by 'go test'
-and the test binary.
+In addition to the build flags, the flags handled by 'go test' itself are:
-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.
Usage:
- go tool command [args...]
+ go tool [-n] command [args...]
Tool runs the go tool command identified by the arguments.
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'.
Usage:
- go vet [importpath...]
+ go vet [packages]
Vet runs the Go vet command on the packages named by the import paths.
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'.
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
a . or .. element is interpreted as a file system path and
each of which can match any string, including the empty string and
strings containing slashes. Such a pattern expands to all package
directories found in the GOPATH trees with names matching the
-patterns. For example, encoding/... expands to all packages
-in the encoding tree.
+patterns. For example, encoding/... expands to all package
+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
a remote repository. Run 'go help remote' for details.
denoting remote repositories begin with the path to the code,
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
The 'go test' command takes both flags that apply to 'go test' itself
and flags that apply to the resulting test binary.
-The flags handled by 'go test' are:
-
- -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
+The test binary, called pkg.test, where pkg is the name of the
directory containing the package sources, has its own flags:
-test.v
The default is 1 second.
-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
of GOMAXPROCS.
also available as the flag -X in 'go test' itself. Flags not listed
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
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.
-That output is compared against the function's doc comment.
-An example without a doc comment is compiled but not executed.
+That output is compared against the function's "Output:" comment, which
+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
of the function, constant, or variable XXX. An example of a method M with
Here is an example of an example:
- // The output of this example function.
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.
var cmdFix = &Command{
Run: runFix,
- UsageLine: "fix [importpath...]",
+ UsageLine: "fix [packages]",
Short: "run go tool fix on packages",
Long: `
Fix runs the Go fix command on the packages named by the import paths.
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'.
var cmdFmt = &Command{
Run: runFmt,
- UsageLine: "fmt [importpath...]",
+ UsageLine: "fmt [packages]",
Short: "run gofmt on package sources",
Long: `
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.
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.
var cmdDoc = &Command{
Run: runDoc,
- UsageLine: "doc [importpath...]",
+ UsageLine: "doc [packages]",
Short: "run godoc on package sources",
Long: `
Doc runs the godoc command on the packages named by the
import paths.
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.
func runDoc(cmd *Command, args []string) {
for _, pkg := range packages(args) {
+ if pkg.ImportPath == "command-line arguments" {
+ errorf("go doc: cannot use package file list")
+ continue
+ }
run("godoc", pkg.Dir)
}
}
import (
"fmt"
- "go/build"
"os"
"path/filepath"
"runtime"
)
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",
Long: `
Get downloads and installs the packages named by the import paths,
before resolving dependencies or building the code.
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.
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
download, see 'go help remote'.
// downloadPackage runs the create or download command
// to make the first copy of or update a copy of the given package.
func downloadPackage(p *Package) error {
- // 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)
+ var (
+ vcs *vcsCmd
+ 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 {
return err
}
- if p.t == nil {
+
+ if p.build.SrcRoot == "" {
// Package not found. Put in first directory of $GOPATH or else $GOROOT.
- p.t = build.Path[0] // $GOROOT
- if len(build.Path) > 1 {
- p.t = build.Path[1] // first in $GOPATH
+ if list := filepath.SplitList(buildContext.GOPATH); len(list) > 0 {
+ p.build.SrcRoot = filepath.Join(list[0], "src")
+ 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 downloadRootCache[root] {
return nil
}
}
+ 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.
tags, err := vcs.tags(root)
if err != nil {
package main
-var helpImportpath = &Command{
- UsageLine: "importpath",
- Short: "description of import paths",
+var helpPackages = &Command{
+ UsageLine: "packages",
+ Short: "description of package lists",
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
a . or .. element is interpreted as a file system path and
each of which can match any string, including the empty string and
strings containing slashes. Such a pattern expands to all package
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
net and all its subdirectories.
internally at Google all begin with 'google', and paths
denoting remote repositories begin with the path to the code,
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.
`,
}
)
var cmdList = &Command{
- UsageLine: "list [-e] [-f format] [-json] [importpath...]",
+ UsageLine: "list [-e] [-f format] [-json] [packages]",
Short: "list packages",
Long: `
List lists the packages named by the import paths, one per line.
a non-nil Error field; other information may or may not be missing
(zeroed).
-For more about import paths, see 'go help importpath'.
+For more about specifying packages, see 'go help packages'.
`,
}
cmdVet,
helpGopath,
- helpImportpath,
+ helpPackages,
helpRemote,
helpTestflag,
helpTestfunc,
}
var out []string
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)...)
continue
}
var pkgs []string
// Commands
- goroot := build.Path[0].Path
cmd := filepath.Join(goroot, "src/cmd") + string(filepath.Separator)
filepath.Walk(cmd, func(path string, fi os.FileInfo, err error) error {
if err != nil || !fi.IsDir() || path == cmd {
return filepath.SkipDir
}
- _, err = build.ScanDir(path)
+ _, err = build.ImportDir(path, 0)
if err != nil {
return nil
}
return nil
})
- for _, t := range build.Path {
- if pattern == "std" && !t.Goroot {
+ for _, src := range buildContext.SrcDirs() {
+ if pattern == "std" && src != gorootSrcPkg {
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 {
if err != nil || !fi.IsDir() || path == src {
return nil
}
have[name] = true
- _, err = build.ScanDir(path)
+ _, err = build.ImportDir(path, 0)
if err != nil && strings.Contains(err.Error(), "no Go source files") {
return nil
}
-
if match(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
})
}
if !match(name) {
return nil
}
- if _, err = build.ScanDir(path); err != nil {
+ if _, err = build.ImportDir(path, 0); err != nil {
return nil
}
pkgs = append(pkgs, name)
}
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, "../")
-}
import (
"bytes"
+ "errors"
"fmt"
"go/build"
- "go/doc"
"go/scanner"
+ "go/token"
"os"
"path/filepath"
"sort"
// 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
// 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
Doc string `json:",omitempty"` // package documentation string
- Dir string `json:",omitempty"` // directory containing package sources
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?
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?
Error *PackageError `json:",omitempty"` // error loading this package (not dependencies)
+ Root string `json:",omitempty"` // root dir of tree this package belongs to
+
// Source files
- GoFiles []string `json:",omitempty"` // .go source files (excluding CgoFiles, TestGoFiles and XTestGoFiles)
- TestGoFiles []string `json:",omitempty"` // _test.go source files internal to the package they are testing
- XTestGoFiles []string `json:",omitempty"` //_test.go source files external to the package they are testing
- CFiles []string `json:",omitempty"` // .c source files
- HFiles []string `json:",omitempty"` // .h source files
- SFiles []string `json:",omitempty"` // .s source files
- CgoFiles []string `json:",omitempty"` // .go sources files that import "C"
+ GoFiles []string `json:",omitempty"` // .go source files (excluding CgoFiles, TestGoFiles XTestGoFiles)
+ CgoFiles []string `json:",omitempty"` // .go sources files that import "C"
+ CFiles []string `json:",omitempty"` // .c source files
+ HFiles []string `json:",omitempty"` // .h source files
+ SFiles []string `json:",omitempty"` // .s source files
+
+ // Cgo directives
CgoCFLAGS []string `json:",omitempty"` // cgo: flags for C compiler
CgoLDFLAGS []string `json:",omitempty"` // cgo: flags for linker
+ CgoPkgConfig []string `json:",omitempty"` // cgo: pkg-config names
// Dependency information
Imports []string `json:",omitempty"` // import paths used by this package
Deps []string `json:",omitempty"` // all (recursively) imported 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.
- t *build.Tree
- pkgdir string
- info *build.DirInfo
- imports []*Package
- deps []*Package
- gofiles []string // GoFiles+CgoFiles+TestGoFiles+XTestGoFiles files, absolute paths
- target string // installed file for this package (may be executable)
- fake bool // synthesized package
+ build *build.Package
+ pkgdir string // overrides build.PkgDir
+ imports []*Package
+ deps []*Package
+ gofiles []string // GoFiles+CgoFiles+TestGoFiles+XTestGoFiles files, absolute paths
+ target string // installed file for this package (may be executable)
+ 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.
func (p *PackageError) Error() string {
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.
return loadPackage(arg, stk)
}
-// loadPackage scans directory named by arg,
-// which is either an import path or a file system path
-// (if the latter, must be rooted or begin with . or ..),
-// and returns a *Package describing the package
-// found in that directory.
-func loadPackage(arg string, stk *importStack) *Package {
- stk.push(arg)
+// loadImport scans the directory named by path, which must be an import path,
+// but possibly a local import path (an absolute file system path or one beginning
+// with ./ or ../). A local relative path is interpreted relative to srcDir.
+// It returns a *Package describing the package found in that directory.
+func loadImport(path string, srcDir string, stk *importStack, importPos []token.Position) *Package {
+ stk.push(path)
defer stk.pop()
- // Check package cache.
- if p := packageCache[arg]; p != nil {
- return reusePackage(p, stk)
- }
-
- // Find basic information about package path.
- isCmd := false
- 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
- }
+ // Determine canonical identifier for this package.
+ // For a local path (./ or ../) the identifier is the full
+ // directory name. Otherwise it is the import path.
+ pkgid := path
+ isLocal := build.IsLocalImport(path)
+ if isLocal {
+ pkgid = filepath.Join(srcDir, path)
}
- if err != nil {
- p := &Package{
- ImportPath: arg,
- Error: &PackageError{
- ImportStack: stk.copy(),
- Err: err.Error(),
- },
- Incomplete: true,
- }
- packageCache[arg] = p
- return p
+ if p := packageCache[pkgid]; p != nil {
+ return reusePackage(p, stk)
}
- if dir == "" {
- dir = filepath.Join(t.SrcDir(), filepath.FromSlash(importPath))
- }
+ p := new(Package)
+ packageCache[pkgid] = p
- // Maybe we know the package by its directory.
- p := packageCache[dir]
- if p != nil {
- packageCache[importPath] = p
- p = reusePackage(p, stk)
- } else {
- p = scanPackage(&buildContext, t, arg, importPath, dir, stk, false)
+ // Load package.
+ // Import always returns bp != nil, even if an error occurs,
+ // in order to return partial information.
+ bp, err := buildContext.Import(path, srcDir, build.AllowBinary)
+ p.load(stk, bp, err)
+ if p.Error != nil && len(importPos) > 0 {
+ 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
}
+// 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 {
// We use p.imports==nil to detect a package that
// is in the midst of its own loadPackage call
ImportStack: stk.copy(),
Err: "import loop",
}
+ panic("loop")
}
p.Incomplete = true
}
}
// isGoTool is the list of directories for Go programs that are installed in
-// $GOROOT/bin/tool.
+// $GOROOT/pkg/tool.
var isGoTool = map[string]bool{
"cmd/api": true,
"cmd/cgo": true,
"exp/ebnflint": true,
}
-func scanPackage(ctxt *build.Context, t *build.Tree, arg, importPath, dir string, stk *importStack, useAllFiles bool) *Package {
- // Read the files in the directory to learn the structure
- // of the package.
- p := &Package{
- ImportPath: importPath,
- Dir: dir,
- Standard: t.Goroot && !strings.Contains(importPath, "."),
- t: t,
- }
- packageCache[dir] = p
- packageCache[importPath] = p
-
- ctxt.UseAllFiles = useAllFiles
- info, err := ctxt.ScanDir(dir)
- useAllFiles = false // flag does not apply to dependencies
+// expandScanner expands a scanner.List error into all the errors in the list.
+// The default Error method only shows the first error.
+func expandScanner(err error) 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 {
+ e.Pos.Filename = shortPath(e.Pos.Filename)
+ buf.WriteString("\n")
+ 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 {
+ p.Incomplete = true
+ err = expandScanner(err)
p.Error = &PackageError{
ImportStack: stk.copy(),
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
}
- p.info = info
- p.Name = info.Package
- p.Doc = doc.Synopsis(info.PackageComment.Text())
- p.Imports = info.Imports
- p.GoFiles = info.GoFiles
- p.TestGoFiles = info.TestGoFiles
- p.XTestGoFiles = info.XTestGoFiles
- p.CFiles = info.CFiles
- p.HFiles = info.HFiles
- p.SFiles = info.SFiles
- 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 p.Name == "main" {
+ _, elem := filepath.Split(p.Dir)
+ full := buildContext.GOOS + "_" + buildContext.GOARCH + "/" + elem
+ if buildContext.GOOS != toolGOOS || buildContext.GOARCH != toolGOARCH {
+ // Install cross-compiled binaries to subdirectories of bin.
+ elem = full
+ }
+ p.target = filepath.Join(p.build.BinDir, elem)
+ if p.Goroot && isGoTool[p.ImportPath] {
+ p.target = filepath.Join(gorootPkg, "tool", full)
}
- if ctxt.GOOS == "windows" {
+ if buildContext.GOOS == "windows" {
p.target += ".exe"
}
+ } else if p.local {
+ // Local import turned into absolute path.
+ // No permanent install target.
+ p.target = ""
} else {
- dir := t.PkgDir()
- // 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
- }
- }
+ p.target = buildToolchain.pkgpath(p.build.PkgRoot, p, true)
}
importPaths := p.Imports
// Packages that use cgo import runtime/cgo implicitly,
// 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")
}
// Everything depends on runtime, except runtime and unsafe.
importPaths = append(importPaths, "runtime")
}
- // Record package under both import path and full directory name.
- packageCache[dir] = p
- packageCache[importPath] = p
+ // Build list of full paths to all Go files in the package,
+ // for use by commands like go fmt.
+ 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.
imports := make([]*Package, 0, len(p.Imports))
deps := make(map[string]bool)
- for _, path := range importPaths {
+ for i, path := range importPaths {
if path == "C" {
continue
}
- deps[path] = true
- p1 := loadPackage(path, stk)
- if p1.Error != nil {
- if info.ImportPos != nil && len(info.ImportPos[path]) > 0 {
- pos := info.ImportPos[path][0]
- p1.Error.Pos = pos.String()
- }
+ p1 := loadImport(path, p.Dir, stk, p.build.ImportPos[path])
+ if p1.local {
+ path = p1.Dir
+ importPaths[i] = path
}
+ deps[path] = true
imports = append(imports, p1)
for _, dep := range p1.Deps {
deps[dep] = true
}
- if p1.Stale {
- p.Stale = true
- }
if p1.Incomplete {
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
}
}
- // unsafe is a fake package and is never out-of-date.
+ // unsafe is a fake package.
if p.Standard && p.ImportPath == "unsafe" {
- p.Stale = false
p.target = ""
}
p.Target = p.target
-
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
// command line arguments 'args'. If a named package
// cannot be loaded at all (for example, if the directory does not exist),
// package is still returned, with p.Incomplete = true
// and details in p.DepsErrors.
func packages(args []string) []*Package {
- args = importPaths(args)
var pkgs []*Package
- var stk importStack
- for _, arg := range args {
- pkg := loadPackage(arg, &stk)
+ for _, pkg := range packagesAndErrors(args) {
if pkg.Error != nil {
errorf("can't load package: %s", pkg.Error)
continue
return pkgs
}
-// packagesAndErrors is like 'packages' but returns a
+// packagesAndErrors is like 'packages' but returns a
// *Package for every argument, even the ones that
// cannot be loaded at all.
// The packages that fail to load will have p.Error != nil.
func packagesAndErrors(args []string) []*Package {
+ if len(args) > 0 && strings.HasSuffix(args[0], ".go") {
+ return []*Package{goFilesPackage(args)}
+ }
+
args = importPaths(args)
var pkgs []*Package
var stk importStack
for _, arg := range args {
pkgs = append(pkgs, loadPackage(arg, &stk))
}
+
+ computeStale(pkgs)
+
return pkgs
}
exitIfErrors()
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
+}
)
var cmdRun = &Command{
- UsageLine: "run [-a] [-n] [-x] gofiles... [arguments...]",
+ UsageLine: "run [build flags] gofiles... [arguments...]",
Short: "compile and run Go program",
Long: `
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.
-The -n flag prints the commands but does not run them.
-The -x flag prints the commands.
+For more about build flags, see 'go help build'.
See also: go build.
`,
i++
}
files, cmdArgs := args[:i], args[i:]
- p := goFilesPackage(files, "")
+ p := goFilesPackage(files)
p.target = "" // must build - not up to date
a1 := b.action(modeBuild, modeBuild, p)
a := &action{f: (*builder).runProgram, args: cmdArgs, deps: []*action{a1}}
--- /dev/null
+#!/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
"go/build"
"go/doc"
"go/parser"
- "go/scanner"
"go/token"
"os"
"os/exec"
var cmdTest = &Command{
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",
Long: `
'Go test' automates testing the packages named by the import paths.
The package is built in a temporary directory so it does not interfere with the
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.
Install packages that are dependencies of 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
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.
`,
The default is 1 second.
-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
of GOMAXPROCS.
}
for _, p := range pkgs {
// Dependencies for each test.
- for _, path := range p.info.Imports {
+ for _, path := range p.Imports {
deps[path] = true
}
- for _, path := range p.info.TestImports {
+ for _, path := range p.TestImports {
deps[path] = true
}
}
for _, p := range pkgs {
buildTest, runTest, printTest, err := b.test(p)
if err != nil {
- if list, ok := err.(scanner.ErrorList); ok {
- const n = 10
- if len(list) > n {
- list = list[:n]
- }
- for _, err := range list {
- errorf("%s", err)
- }
- continue
+ str := err.Error()
+ if strings.HasPrefix(str, "\n") {
+ str = str[1:]
+ }
+ if p.ImportPath != "" {
+ errorf("# %s\n%s", p.ImportPath, str)
+ } else {
+ errorf("%s", str)
}
- errorf("%s", err)
continue
}
builds = append(builds, buildTest)
}
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}
run := &action{p: p}
print := &action{f: (*builder).notest, p: p, deps: []*action{build}}
// pmain - pkg.test binary
var ptest, pxtest, pmain *Package
- // go/build does not distinguish the dependencies used
- // 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 imports, ximports []*Package
var stk importStack
stk.push(p.ImportPath + "_test")
- for _, path := range p.info.TestImports {
- p1 := loadPackage(path, &stk)
+ for _, path := range p.TestImports {
+ p1 := loadImport(path, p.Dir, &stk, p.build.TestImportPos[path])
if p1.Error != nil {
return nil, nil, nil, p1.Error
}
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()
// Use last element of import path, not package name.
// We write the external test package archive to
// $WORK/unicode/utf8/_test/unicode/utf8_test.a.
testDir := filepath.Join(b.work, filepath.FromSlash(p.ImportPath+"/_test"))
- ptestObj := buildToolchain.pkgpath(testDir, p)
+ ptestObj := buildToolchain.pkgpath(testDir, p, false)
// Create the directory for the .a files.
ptestDir, _ := filepath.Split(ptestObj)
}
// Test package.
- if len(p.info.TestGoFiles) > 0 {
+ if len(p.TestGoFiles) > 0 {
ptest = new(Package)
*ptest = *p
ptest.GoFiles = nil
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.Imports = stringList(p.info.Imports, p.info.TestImports)
+ ptest.Imports = stringList(p.Imports, p.TestImports)
ptest.imports = append(append([]*Package{}, p.imports...), imports...)
ptest.pkgdir = testDir
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.objdir = testDir + string(filepath.Separator)
a.objpkg = ptestObj
}
// External test package.
- if len(p.info.XTestGoFiles) > 0 {
+ if len(p.XTestGoFiles) > 0 {
pxtest = &Package{
Name: p.Name + "_test",
ImportPath: p.ImportPath + "_test",
Dir: p.Dir,
- GoFiles: p.info.XTestGoFiles,
- Imports: p.info.TestImports,
- t: p.t,
- info: &build.DirInfo{},
- imports: imports,
- pkgdir: testDir,
- fake: true,
+ GoFiles: p.XTestGoFiles,
+ Imports: p.XTestImports,
+ build: &build.Package{
+ ImportPos: p.build.XTestImportPos,
+ },
+ imports: append(ximports, ptest),
+ pkgdir: testDir,
+ fake: true,
}
- pxtest.imports = append(pxtest.imports, ptest)
a := b.action(modeBuild, modeBuild, pxtest)
a.objdir = testDir + string(filepath.Separator)
- a.objpkg = buildToolchain.pkgpath(testDir, pxtest)
+ a.objpkg = buildToolchain.pkgpath(testDir, pxtest, false)
a.target = a.objpkg
}
Name: "main",
Dir: testDir,
GoFiles: []string{"_testmain.go"},
- t: p.t,
- info: &build.DirInfo{},
imports: []*Package{ptest},
+ build: &build.Package{},
fake: true,
}
if pxtest != nil {
// The generated main also imports testing and regexp.
stk.push("testmain")
- ptesting := loadPackage("testing", &stk)
+ ptesting := loadImport("testing", "", &stk, nil)
if ptesting.Error != nil {
return nil, nil, nil, ptesting.Error
}
- pregexp := loadPackage("regexp", &stk)
+ pregexp := loadImport("regexp", "", &stk, nil)
if pregexp.Error != nil {
return nil, nil, nil, pregexp.Error
}
a := b.action(modeBuild, modeBuild, pmain)
a.objdir = testDir + string(filepath.Separator)
a.objpkg = filepath.Join(testDir, "main.a")
- a.target = filepath.Join(testDir, testBinary) + b.exe
+ a.target = filepath.Join(testDir, testBinary) + exeSuffix
pmainAction := a
if testC {
f: (*builder).install,
deps: []*action{pmainAction},
p: pmain,
- target: testBinary + b.exe,
+ target: testBinary + exeSuffix,
}
printAction = &action{p: p, deps: []*action{runAction}} // nop
} else {
func writeTestmain(out string, p *Package) error {
t := &testFuncs{
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 {
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 {
return err
}
Benchmarks []testFunc
Examples []testFunc
Package *Package
- Info *build.DirInfo
NeedTest bool
NeedXtest bool
}
func (t *testFuncs) load(filename, pkg string, seen *bool) error {
f, err := parser.ParseFile(testFileSet, filename, nil, parser.ParseComments)
if err != nil {
- return err
+ return expandScanner(err)
}
for _, d := range f.Decls {
n, ok := d.(*ast.FuncDecl)
--- /dev/null
+package foo
+
+import "bar"
--- /dev/null
+package foo_test
+
+import "bar"
--- /dev/null
+package foo
+
+import "bar"
--- /dev/null
+package main
+
+import "./easysub"
+
+func main() {
+ easysub.Hello()
+}
--- /dev/null
+package easysub
+
+import "fmt"
+
+func Hello() {
+ fmt.Println("easysub.Hello")
+}
--- /dev/null
+package main
+
+import "./sub"
+
+func main() {
+ sub.Hello()
+}
--- /dev/null
+package sub
+
+import (
+ "fmt"
+
+ subsub "./sub"
+)
+
+func Hello() {
+ fmt.Println("sub.Hello")
+ subsub.Hello()
+}
--- /dev/null
+package subsub
+
+import "fmt"
+
+func Hello() {
+ fmt.Println("subsub.Hello")
+}
"fmt"
"os"
"os/exec"
+ "path/filepath"
"regexp"
"strings"
)
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
// version control system, and code repository to use.
// On return, repo is the repository URL and root is the
var cmdVet = &Command{
Run: runVet,
- UsageLine: "vet [importpath...]",
+ UsageLine: "vet [packages]",
Short: "run go tool vet on packages",
Long: `
Vet runs the Go vet command on the packages named by the import paths.
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'.
# Use of this source code is governed by a BSD-style
# 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
if [ ! -f run.bash ]; then
echo 'make.bash must be run from $GOROOT/src' 1>&2
if [ "$GOHOSTARCH" != "$GOARCH" -o "$GOHOSTOS" != "$GOOS" ]; then
echo "# Building packages and commands for host, $GOHOSTOS/$GOHOSTARCH."
GOOS=$GOHOSTOS GOARCH=$GOHOSTARCH \
- $GOTOOLDIR/go_bootstrap install -v std
+ $GOTOOLDIR/go_bootstrap install -gcflags "$GCFLAGS" -ldflags "$LDFLAGS" -v std
echo
fi
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
rm -f $GOTOOLDIR/go_bootstrap