mirror of
https://github.com/golang/go
synced 2024-11-11 23:20:24 -07:00
cmd/go: work toward build script
The commands in the standard tree are now named by the pseudo-import paths cmd/gofmt etc. This avoids ambiguity between cmd/go's directory and go/token's parent directory. R=golang-dev, r CC=golang-dev https://golang.org/cl/5503050
This commit is contained in:
parent
8720105776
commit
fd1c1b9679
@ -6,6 +6,8 @@
|
||||
// to update builtin.c.boot. This is not done automatically
|
||||
// to avoid depending on having a working compiler binary.
|
||||
|
||||
// +build ignore
|
||||
|
||||
package PACKAGE
|
||||
|
||||
// emitted by compiler, not referred to by go programs
|
||||
|
@ -6,6 +6,8 @@
|
||||
// to update builtin.c.boot. This is not done automatically
|
||||
// to avoid depending on having a working compiler binary.
|
||||
|
||||
// +build ignore
|
||||
|
||||
package PACKAGE
|
||||
|
||||
type Pointer uintptr // not really; filled in by compiler
|
||||
|
@ -6,6 +6,7 @@ package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"go/build"
|
||||
"io"
|
||||
@ -14,8 +15,8 @@ import (
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"runtime"
|
||||
"strings"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// Break init cycles
|
||||
@ -108,7 +109,11 @@ type builder struct {
|
||||
goroot string // the $GOROOT
|
||||
goarch string // the $GOARCH
|
||||
goos string // the $GOOS
|
||||
gobin string // the $GOBIN
|
||||
actionCache map[cacheKey]*action // a cache of already-constructed actions
|
||||
|
||||
output sync.Mutex
|
||||
scriptDir string // current directory in printed script
|
||||
}
|
||||
|
||||
// An action represents a single action in the action graph.
|
||||
@ -148,9 +153,10 @@ func (b *builder) init(aflag, nflag, xflag bool) {
|
||||
b.nflag = nflag
|
||||
b.xflag = xflag
|
||||
b.actionCache = make(map[cacheKey]*action)
|
||||
b.goroot = runtime.GOROOT()
|
||||
b.goarch = build.DefaultContext.GOARCH
|
||||
b.goos = build.DefaultContext.GOOS
|
||||
b.goroot = build.Path[0].Path
|
||||
b.gobin = build.Path[0].BinDir()
|
||||
|
||||
b.arch, err = build.ArchChar(b.goarch)
|
||||
if err != nil {
|
||||
@ -312,7 +318,11 @@ func (b *builder) do(a *action) {
|
||||
}
|
||||
if a.f != nil {
|
||||
if err := a.f(b, a); err != nil {
|
||||
errorf("%s", err)
|
||||
if err == errPrintedOutput {
|
||||
exitStatus = 2
|
||||
} else {
|
||||
errorf("%s", err)
|
||||
}
|
||||
a.failed = true
|
||||
}
|
||||
}
|
||||
@ -321,6 +331,14 @@ func (b *builder) do(a *action) {
|
||||
|
||||
// build is the action for building a single package or command.
|
||||
func (b *builder) build(a *action) error {
|
||||
if b.nflag {
|
||||
// In -n mode, print a banner between packages.
|
||||
// The banner is five lines so that when changes to
|
||||
// different sections of the bootstrap script have to
|
||||
// be merged, the banners give patch something
|
||||
// to use to find its context.
|
||||
fmt.Printf("\n#\n# %s\n#\n\n", a.p.ImportPath)
|
||||
}
|
||||
obj := filepath.Join(b.work, filepath.FromSlash(a.p.ImportPath+"/_obj")) + string(filepath.Separator)
|
||||
if a.pkgobj == "" {
|
||||
a.pkgobj = filepath.Join(b.work, filepath.FromSlash(a.p.ImportPath+".a"))
|
||||
@ -362,7 +380,7 @@ func (b *builder) build(a *action) error {
|
||||
sfiles = nil
|
||||
}
|
||||
|
||||
outGo, outObj, err := b.cgo(a.p.Dir, obj, gccfiles, a.p)
|
||||
outGo, outObj, err := b.cgo(a.p, obj, gccfiles)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -405,7 +423,7 @@ func (b *builder) build(a *action) error {
|
||||
// additional reflect type data.
|
||||
gcargs = append(gcargs, "-+")
|
||||
}
|
||||
if err := b.gc(a.p.Dir, obj+out, gcargs, inc, gofiles); err != nil {
|
||||
if err := b.gc(a.p, obj+out, gcargs, inc, gofiles); err != nil {
|
||||
return err
|
||||
}
|
||||
objects = append(objects, out)
|
||||
@ -439,7 +457,7 @@ func (b *builder) build(a *action) error {
|
||||
|
||||
for _, file := range cfiles {
|
||||
out := file[:len(file)-len(".c")] + "." + b.arch
|
||||
if err := b.cc(a.p.Dir, obj, obj+out, file); err != nil {
|
||||
if err := b.cc(a.p, obj, obj+out, file); err != nil {
|
||||
return err
|
||||
}
|
||||
objects = append(objects, out)
|
||||
@ -448,14 +466,14 @@ func (b *builder) build(a *action) error {
|
||||
// assemble .s files
|
||||
for _, file := range sfiles {
|
||||
out := file[:len(file)-len(".s")] + "." + b.arch
|
||||
if err := b.asm(a.p.Dir, obj, obj+out, file); err != nil {
|
||||
if err := b.asm(a.p, obj, obj+out, file); err != nil {
|
||||
return err
|
||||
}
|
||||
objects = append(objects, out)
|
||||
}
|
||||
|
||||
// pack into archive
|
||||
if err := b.gopack(obj, a.pkgobj, objects); err != nil {
|
||||
if err := b.gopack(a.p, obj, a.pkgobj, objects); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@ -467,7 +485,7 @@ func (b *builder) build(a *action) error {
|
||||
inc[i] = "-L"
|
||||
}
|
||||
a.pkgbin = obj + "a.out"
|
||||
if err := b.ld(a.p.Dir, a.pkgbin, inc, a.pkgobj); err != nil {
|
||||
if err := b.ld(a.p, a.pkgbin, inc, a.pkgobj); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
@ -503,7 +521,7 @@ func (b *builder) install(a *action) error {
|
||||
// copyFile is like 'cp src dst'.
|
||||
func (b *builder) copyFile(dst, src string, perm uint32) error {
|
||||
if b.nflag || b.xflag {
|
||||
b.showcmd("cp %s %s", src, dst)
|
||||
b.showcmd("", "cp %s %s", src, dst)
|
||||
if b.nflag {
|
||||
return nil
|
||||
}
|
||||
@ -528,27 +546,91 @@ func (b *builder) copyFile(dst, src string, perm uint32) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// fmtcmd is like fmt.Sprintf but replaces references to the
|
||||
// work directory (a temporary directory with a clumsy name)
|
||||
// with $WORK.
|
||||
func (b *builder) fmtcmd(format string, args ...interface{}) string {
|
||||
s := fmt.Sprintf(format, args...)
|
||||
s = strings.Replace(s, b.work, "$WORK", -1)
|
||||
return s
|
||||
// fmtcmd formats a command in the manner of fmt.Sprintf but also:
|
||||
//
|
||||
// If dir is non-empty and the script is not in dir right now,
|
||||
// fmtcmd inserts "cd dir\n" before the command.
|
||||
//
|
||||
// fmtcmd replaces the value of b.work with $WORK.
|
||||
// fmtcmd replaces the value of b.goroot with $GOROOT.
|
||||
// fmtcmd replaces the value of b.gobin with $GOBIN.
|
||||
//
|
||||
// fmtcmd replaces the name of the current directory with dot (.)
|
||||
// but only when it is at the beginning of a space-separated token.
|
||||
//
|
||||
func (b *builder) fmtcmd(dir string, format string, args ...interface{}) string {
|
||||
cmd := fmt.Sprintf(format, args...)
|
||||
if dir != "" {
|
||||
cmd = strings.Replace(" "+cmd, " "+dir, " .", -1)[1:]
|
||||
if b.scriptDir != dir {
|
||||
b.scriptDir = dir
|
||||
cmd = " cd " + dir + "\n" + cmd
|
||||
}
|
||||
}
|
||||
cmd = strings.Replace(cmd, b.work, "$WORK", -1)
|
||||
cmd = strings.Replace(cmd, b.gobin, "$GOBIN", -1)
|
||||
cmd = strings.Replace(cmd, b.goroot, "$GOROOT", -1)
|
||||
return cmd
|
||||
}
|
||||
|
||||
// showcmd prints the given command to standard output
|
||||
// for the implementation of -n or -x.
|
||||
func (b *builder) showcmd(format string, args ...interface{}) {
|
||||
fmt.Println(b.fmtcmd(format, args...))
|
||||
func (b *builder) showcmd(dir string, format string, args ...interface{}) {
|
||||
b.output.Lock()
|
||||
defer b.output.Unlock()
|
||||
fmt.Println(b.fmtcmd(dir, format, args...))
|
||||
}
|
||||
|
||||
// showOutput prints "# desc" followed by the given output.
|
||||
// The output is expected to contain references to 'dir', usually
|
||||
// the source directory for the package that has failed to build.
|
||||
// showOutput rewrites mentions of dir with a relative path to dir.
|
||||
// This is usually shorter and more pleasant than the absolute path.
|
||||
// For example, if fmt doesn't compile and we are in src/pkg/html,
|
||||
// the output is
|
||||
//
|
||||
// $ go build
|
||||
// # fmt
|
||||
// ../fmt/print.go:1090: undefined: asdf
|
||||
// $
|
||||
//
|
||||
// instead of
|
||||
//
|
||||
// $ go build
|
||||
// # fmt
|
||||
// /usr/gopher/go/src/pkg/fmt/print.go:1090: undefined: asdf
|
||||
// $
|
||||
//
|
||||
// showOutput also replaces references to the work directory with $WORK.
|
||||
//
|
||||
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 {
|
||||
suffix = strings.Replace(suffix, " "+dir, " "+reldir, -1)
|
||||
suffix = strings.Replace(suffix, "\n"+dir, "\n"+reldir, -1)
|
||||
}
|
||||
suffix = strings.Replace(suffix, " "+b.work, " $WORK", -1)
|
||||
|
||||
b.output.Lock()
|
||||
defer b.output.Unlock()
|
||||
fmt.Print(prefix, suffix)
|
||||
}
|
||||
|
||||
// errPrintedOutput is a special error indicating that a command failed
|
||||
// but that it generated output as well, and that output has already
|
||||
// been printed, so there's no point showing 'exit status 1' or whatever
|
||||
// the wait status was. The main executor, builder.do, knows not to
|
||||
// print this error.
|
||||
var errPrintedOutput = errors.New("already printed output - no need to show error")
|
||||
|
||||
// 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, cmdline ...string) error {
|
||||
func (b *builder) run(dir string, desc string, cmdline ...string) error {
|
||||
if b.nflag || b.xflag {
|
||||
b.showcmd("cd %s; %s", dir, strings.Join(cmdline, " "))
|
||||
b.showcmd(dir, "%s", strings.Join(cmdline, " "))
|
||||
if b.nflag {
|
||||
return nil
|
||||
}
|
||||
@ -562,8 +644,17 @@ func (b *builder) run(dir string, cmdline ...string) error {
|
||||
// TODO: cmd.Env
|
||||
err := cmd.Run()
|
||||
if buf.Len() > 0 {
|
||||
fmt.Fprintf(os.Stderr, "# cd %s; %s\n", dir, strings.Join(cmdline, " "))
|
||||
fmt.Fprintf(os.Stderr, "%s\n", buf.Bytes())
|
||||
out := buf.Bytes()
|
||||
if out[len(out)-1] != '\n' {
|
||||
out = append(out, '\n')
|
||||
}
|
||||
if desc == "" {
|
||||
desc = b.fmtcmd(dir, "%s", strings.Join(cmdline, " "))
|
||||
}
|
||||
b.showOutput(dir, desc, string(out))
|
||||
if err != nil {
|
||||
err = errPrintedOutput
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
@ -571,7 +662,7 @@ func (b *builder) run(dir string, cmdline ...string) error {
|
||||
// mkdir makes the named directory.
|
||||
func (b *builder) mkdir(dir string) error {
|
||||
if b.nflag || b.xflag {
|
||||
b.showcmd("mkdir -p %s", dir)
|
||||
b.showcmd("", "mkdir -p %s", dir)
|
||||
if b.nflag {
|
||||
return nil
|
||||
}
|
||||
@ -583,50 +674,75 @@ func (b *builder) mkdir(dir string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// mkAbs returns an absolute path corresponding to
|
||||
// evaluating f in the directory dir.
|
||||
// We always pass absolute paths of source files so that
|
||||
// the error messages will include the full path to a file
|
||||
// in need of attention.
|
||||
func mkAbs(dir, f string) string {
|
||||
// Leave absolute paths alone.
|
||||
// Also, during -n mode we use the pseudo-directory $WORK
|
||||
// instead of creating an actual work directory that won't be used.
|
||||
// Leave paths beginning with $WORK alone too.
|
||||
if filepath.IsAbs(f) || strings.HasPrefix(f, "$WORK") {
|
||||
return f
|
||||
}
|
||||
return filepath.Join(dir, f)
|
||||
}
|
||||
|
||||
// gc runs the Go compiler in a specific directory on a set of files
|
||||
// to generate the named output file.
|
||||
func (b *builder) gc(dir, ofile string, gcargs, importArgs []string, gofiles []string) error {
|
||||
func (b *builder) gc(p *Package, ofile string, gcargs, importArgs []string, gofiles []string) error {
|
||||
args := []string{b.arch + "g", "-o", ofile}
|
||||
args = append(args, gcargs...)
|
||||
args = append(args, importArgs...)
|
||||
args = append(args, gofiles...)
|
||||
return b.run(dir, args...)
|
||||
for _, f := range gofiles {
|
||||
args = append(args, mkAbs(p.Dir, f))
|
||||
}
|
||||
return b.run(p.Dir, p.ImportPath, args...)
|
||||
}
|
||||
|
||||
// asm runs the assembler in a specific directory on a specific file
|
||||
// to generate the named output file.
|
||||
func (b *builder) asm(dir, obj, ofile, sfile string) error {
|
||||
return b.run(dir, b.arch+"a", "-I", obj, "-o", ofile, "-DGOOS_"+b.goos, "-DGOARCH_"+b.goarch, sfile)
|
||||
func (b *builder) asm(p *Package, obj, ofile, sfile string) error {
|
||||
sfile = mkAbs(p.Dir, sfile)
|
||||
return b.run(p.Dir, p.ImportPath, b.arch+"a", "-I", obj, "-o", ofile, "-DGOOS_"+b.goos, "-DGOARCH_"+b.goarch, sfile)
|
||||
}
|
||||
|
||||
// gopack runs the assembler in a specific directory to create
|
||||
// an archive from a set of object files.
|
||||
// typically it is run in the object directory.
|
||||
func (b *builder) gopack(objDir, afile string, ofiles []string) error {
|
||||
return b.run(objDir, append([]string{"gopack", "grc", afile}, ofiles...)...)
|
||||
func (b *builder) gopack(p *Package, objDir, afile string, ofiles []string) error {
|
||||
cmd := []string{"gopack", "grc"}
|
||||
cmd = append(cmd, mkAbs(objDir, afile))
|
||||
for _, f := range ofiles {
|
||||
cmd = append(cmd, mkAbs(objDir, f))
|
||||
}
|
||||
return b.run(p.Dir, p.ImportPath, cmd...)
|
||||
}
|
||||
|
||||
// ld runs the linker to create a package starting at mainpkg.
|
||||
func (b *builder) ld(dir, out string, importArgs []string, mainpkg string) error {
|
||||
return b.run(dir, append(append([]string{b.arch + "l", "-o", out}, importArgs...), mainpkg)...)
|
||||
func (b *builder) ld(p *Package, out string, importArgs []string, mainpkg string) error {
|
||||
return b.run(p.Dir, p.ImportPath, append(append([]string{b.arch + "l", "-o", out}, importArgs...), mainpkg)...)
|
||||
}
|
||||
|
||||
// cc runs the gc-toolchain C compiler in a directory on a C file
|
||||
// to produce an output file.
|
||||
func (b *builder) cc(dir, objdir, ofile, cfile string) error {
|
||||
inc := filepath.Join(runtime.GOROOT(), "pkg",
|
||||
fmt.Sprintf("%s_%s", b.goos, b.goarch))
|
||||
return b.run(dir, b.arch+"c", "-FVw", "-I", objdir, "-I", inc, "-o", ofile, "-DGOOS_"+b.goos, "-DGOARCH_"+b.goarch, cfile)
|
||||
func (b *builder) cc(p *Package, objdir, ofile, cfile string) error {
|
||||
inc := filepath.Join(b.goroot, "pkg", fmt.Sprintf("%s_%s", b.goos, b.goarch))
|
||||
cfile = mkAbs(p.Dir, cfile)
|
||||
return b.run(p.Dir, p.ImportPath, b.arch+"c", "-FVw", "-I", objdir, "-I", inc, "-o", ofile, "-DGOOS_"+b.goos, "-DGOARCH_"+b.goarch, cfile)
|
||||
}
|
||||
|
||||
// gcc runs the gcc C compiler to create an object from a single C file.
|
||||
func (b *builder) gcc(dir, out string, flags []string, cfile string) error {
|
||||
return b.run(dir, b.gccCmd(dir, flags, "-o", out, "-c", cfile)...)
|
||||
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)...)
|
||||
}
|
||||
|
||||
// gccld runs the gcc linker to create an executable from a set of object files
|
||||
func (b *builder) gccld(dir, out string, flags []string, obj []string) error {
|
||||
return b.run(dir, append(b.gccCmd(dir, flags, "-o", out), obj...)...)
|
||||
func (b *builder) gccld(p *Package, out string, flags []string, obj []string) error {
|
||||
return b.run(p.Dir, p.ImportPath, append(b.gccCmd(p.Dir, flags, "-o", out), obj...)...)
|
||||
}
|
||||
|
||||
// gccCmd returns a gcc command line ending with args
|
||||
@ -645,7 +761,7 @@ func (b *builder) gccCmd(objdir string, flags []string, args ...string) []string
|
||||
|
||||
var cgoRe = regexp.MustCompile(`[/\\:]`)
|
||||
|
||||
func (b *builder) cgo(dir, obj string, csfiles []string, p *Package) (outGo, outObj []string, err error) {
|
||||
func (b *builder) cgo(p *Package, obj string, gccfiles []string) (outGo, outObj []string, err error) {
|
||||
// cgo
|
||||
// TODO: CGOPKGPATH, CGO_FLAGS?
|
||||
gofiles := []string{obj + "_cgo_gotypes.go"}
|
||||
@ -664,14 +780,14 @@ func (b *builder) cgo(dir, obj string, csfiles []string, p *Package) (outGo, out
|
||||
}
|
||||
cgoArgs = append(cgoArgs, "--")
|
||||
cgoArgs = append(cgoArgs, p.CgoFiles...)
|
||||
if err := b.run(dir, cgoArgs...); err != nil {
|
||||
if err := b.run(p.Dir, p.ImportPath, cgoArgs...); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
outGo = append(outGo, gofiles...)
|
||||
|
||||
// cc _cgo_defun.c
|
||||
defunObj := obj + "_cgo_defun." + b.arch
|
||||
if err := b.cc(dir, obj, defunObj, defunC); err != nil {
|
||||
if err := b.cc(p, obj, defunObj, defunC); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
outObj = append(outObj, defunObj)
|
||||
@ -680,7 +796,7 @@ func (b *builder) cgo(dir, obj string, csfiles []string, p *Package) (outGo, out
|
||||
var linkobj []string
|
||||
for _, cfile := range cfiles {
|
||||
ofile := obj + cfile[:len(cfile)-1] + "o"
|
||||
if err := b.gcc(dir, ofile, p.info.CgoCFLAGS, obj+cfile); err != nil {
|
||||
if err := b.gcc(p, ofile, p.info.CgoCFLAGS, obj+cfile); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
linkobj = append(linkobj, ofile)
|
||||
@ -688,28 +804,28 @@ func (b *builder) cgo(dir, obj string, csfiles []string, p *Package) (outGo, out
|
||||
outObj = append(outObj, ofile)
|
||||
}
|
||||
}
|
||||
for _, file := range csfiles {
|
||||
for _, file := range gccfiles {
|
||||
ofile := obj + cgoRe.ReplaceAllString(file[:len(file)-1], "_") + "o"
|
||||
if err := b.gcc(dir, ofile, p.info.CgoCFLAGS, file); err != nil {
|
||||
if err := b.gcc(p, ofile, p.info.CgoCFLAGS, file); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
linkobj = append(linkobj, ofile)
|
||||
outObj = append(outObj, ofile)
|
||||
}
|
||||
dynobj := obj + "_cgo_.o"
|
||||
if err := b.gccld(dir, dynobj, p.info.CgoLDFLAGS, linkobj); err != nil {
|
||||
if err := b.gccld(p, dynobj, p.info.CgoLDFLAGS, linkobj); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
// cgo -dynimport
|
||||
importC := obj + "_cgo_import.c"
|
||||
if err := b.run(dir, "cgo", "-objdir", obj, "-dynimport", dynobj, "-dynout", importC); err != nil {
|
||||
if err := b.run(p.Dir, p.ImportPath, "cgo", "-objdir", obj, "-dynimport", dynobj, "-dynout", importC); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
// cc _cgo_import.ARCH
|
||||
importObj := obj + "_cgo_import." + b.arch
|
||||
if err := b.cc(dir, obj, importObj, importC); err != nil {
|
||||
if err := b.cc(p, obj, importObj, importC); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
outObj = append(outObj, importObj)
|
||||
|
@ -14,7 +14,7 @@ var cmdList = &Command{
|
||||
UsageLine: "list [-f format] [-json] [importpath...]",
|
||||
Short: "list packages",
|
||||
Long: `
|
||||
List lists the packages named by the import paths.
|
||||
List lists the packages named by the import paths, one per line.
|
||||
|
||||
The default output shows the package name and file system location:
|
||||
|
||||
@ -24,7 +24,7 @@ The default output shows the package name and file system location:
|
||||
|
||||
The -f flag specifies an alternate format for the list,
|
||||
using the syntax of package template. The default output
|
||||
is equivalent to -f '{{.Name}} {{.Dir}}'. The struct
|
||||
is equivalent to -f '{{.ImportPath}}'. The struct
|
||||
being passed to the template is:
|
||||
|
||||
type Package struct {
|
||||
@ -57,7 +57,7 @@ func init() {
|
||||
cmdList.Run = runList // break init cycle
|
||||
}
|
||||
|
||||
var listFmt = cmdList.Flag.String("f", "{{.Name}} {{.Dir}}", "")
|
||||
var listFmt = cmdList.Flag.String("f", "{{.ImportPath}}", "")
|
||||
var listJson = cmdList.Flag.Bool("json", false, "")
|
||||
var nl = []byte{'\n'}
|
||||
|
||||
|
@ -237,8 +237,38 @@ func run(cmdline ...string) {
|
||||
// allPackages returns all the packages that can be found
|
||||
// under the $GOPATH directories and $GOROOT.
|
||||
func allPackages() []string {
|
||||
have := make(map[string]bool)
|
||||
have := map[string]bool{
|
||||
"builtin": true, // ignore pseudo-package that exists only for documentation
|
||||
}
|
||||
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() {
|
||||
return nil
|
||||
}
|
||||
name := path[len(cmd):]
|
||||
// Commands are all in cmd/, not in subdirectories.
|
||||
if strings.Contains(name, string(filepath.Separator)) {
|
||||
return filepath.SkipDir
|
||||
}
|
||||
|
||||
_, err = build.ScanDir(path)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
// We use, e.g., cmd/gofmt as the pseudo import path for gofmt.
|
||||
name = "cmd/" + name
|
||||
if !have[name] {
|
||||
have[name] = true
|
||||
pkgs = append(pkgs, name)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
for _, t := range build.Path {
|
||||
src := t.SrcDir() + string(filepath.Separator)
|
||||
filepath.Walk(src, func(path string, fi os.FileInfo, err error) error {
|
||||
@ -256,21 +286,19 @@ func allPackages() []string {
|
||||
return nil
|
||||
}
|
||||
name := path[len(src):]
|
||||
if have[name] {
|
||||
return nil
|
||||
if !have[name] {
|
||||
pkgs = append(pkgs, name)
|
||||
have[name] = true
|
||||
}
|
||||
pkgs = append(pkgs, name)
|
||||
have[name] = true
|
||||
|
||||
// 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
|
||||
})
|
||||
|
||||
// TODO: Commands.
|
||||
}
|
||||
return pkgs
|
||||
}
|
||||
|
@ -70,13 +70,15 @@ func loadPackage(arg string) (*Package, error) {
|
||||
|
||||
// Find basic information about package path.
|
||||
t, importPath, err := build.FindTree(arg)
|
||||
dir := ""
|
||||
// Maybe it is a standard command.
|
||||
if err != nil && !filepath.IsAbs(arg) && !strings.HasPrefix(arg, ".") {
|
||||
if err != nil && !filepath.IsAbs(arg) && strings.HasPrefix(arg, "cmd/") {
|
||||
goroot := build.Path[0]
|
||||
p := filepath.Join(goroot.Path, "src/cmd", arg)
|
||||
p := filepath.Join(goroot.Path, "src", arg)
|
||||
if st, err1 := os.Stat(p); err1 == nil && st.IsDir() {
|
||||
t = goroot
|
||||
importPath = "../cmd/" + arg
|
||||
importPath = arg
|
||||
dir = p
|
||||
err = nil
|
||||
}
|
||||
}
|
||||
@ -84,7 +86,9 @@ func loadPackage(arg string) (*Package, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
dir := filepath.Join(t.SrcDir(), filepath.FromSlash(importPath))
|
||||
if dir == "" {
|
||||
dir = filepath.Join(t.SrcDir(), filepath.FromSlash(importPath))
|
||||
}
|
||||
|
||||
// Maybe we know the package by its directory.
|
||||
if p := packageCache[dir]; p != nil {
|
||||
@ -140,6 +144,13 @@ func scanPackage(ctxt *build.Context, t *build.Tree, arg, importPath, dir string
|
||||
}
|
||||
sort.Strings(p.gofiles)
|
||||
|
||||
// Packages that use cgo import runtime/cgo implicitly,
|
||||
// except runtime/cgo itself.
|
||||
if len(info.CgoFiles) > 0 && (!p.Standard || p.ImportPath != "runtime/cgo") {
|
||||
p.Imports = append(p.Imports, "runtime/cgo")
|
||||
sort.Strings(p.Imports)
|
||||
}
|
||||
|
||||
// Record package under both import path and full directory name.
|
||||
packageCache[dir] = p
|
||||
packageCache[importPath] = p
|
||||
|
Loading…
Reference in New Issue
Block a user