aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorRuss Cox <rsc@golang.org>2011-12-20 16:42:44 -0500
committerRuss Cox <rsc@golang.org>2011-12-20 16:42:44 -0500
commitfd1c1b9679a2ed9c96bc3ccd74336ba5b23a5049 (patch)
tree16b149ffbb8833cfa150261d96dbaa1ff05a0a6f /src
parent8720105776d9c1f2f7ff8bde070b70853afecb6d (diff)
downloadgo-fd1c1b9679a2ed9c96bc3ccd74336ba5b23a5049.tar.xz
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
Diffstat (limited to 'src')
-rw-r--r--src/cmd/gc/runtime.go2
-rw-r--r--src/cmd/gc/unsafe.go2
-rw-r--r--src/cmd/go/build.go216
-rw-r--r--src/cmd/go/list.go6
-rw-r--r--src/cmd/go/main.go42
-rw-r--r--src/cmd/go/pkg.go19
6 files changed, 223 insertions, 64 deletions
diff --git a/src/cmd/gc/runtime.go b/src/cmd/gc/runtime.go
index 2d9e423214..000b2328ff 100644
--- a/src/cmd/gc/runtime.go
+++ b/src/cmd/gc/runtime.go
@@ -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
diff --git a/src/cmd/gc/unsafe.go b/src/cmd/gc/unsafe.go
index db27d7425f..c7b48a8b06 100644
--- a/src/cmd/gc/unsafe.go
+++ b/src/cmd/gc/unsafe.go
@@ -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
diff --git a/src/cmd/go/build.go b/src/cmd/go/build.go
index c434dc0db5..f53efc8c1f 100644
--- a/src/cmd/go/build.go
+++ b/src/cmd/go/build.go
@@ -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)
diff --git a/src/cmd/go/list.go b/src/cmd/go/list.go
index bd75fd6cc4..df18df17a7 100644
--- a/src/cmd/go/list.go
+++ b/src/cmd/go/list.go
@@ -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'}
diff --git a/src/cmd/go/main.go b/src/cmd/go/main.go
index 79bcd66746..6d70da824f 100644
--- a/src/cmd/go/main.go
+++ b/src/cmd/go/main.go
@@ -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
}
diff --git a/src/cmd/go/pkg.go b/src/cmd/go/pkg.go
index 503b098ce8..599c4e0779 100644
--- a/src/cmd/go/pkg.go
+++ b/src/cmd/go/pkg.go
@@ -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