mirror of
https://github.com/golang/go
synced 2024-11-25 11:07:59 -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 update builtin.c.boot. This is not done automatically
|
||||||
// to avoid depending on having a working compiler binary.
|
// to avoid depending on having a working compiler binary.
|
||||||
|
|
||||||
|
// +build ignore
|
||||||
|
|
||||||
package PACKAGE
|
package PACKAGE
|
||||||
|
|
||||||
// emitted by compiler, not referred to by go programs
|
// emitted by compiler, not referred to by go programs
|
||||||
|
@ -6,6 +6,8 @@
|
|||||||
// to update builtin.c.boot. This is not done automatically
|
// to update builtin.c.boot. This is not done automatically
|
||||||
// to avoid depending on having a working compiler binary.
|
// to avoid depending on having a working compiler binary.
|
||||||
|
|
||||||
|
// +build ignore
|
||||||
|
|
||||||
package PACKAGE
|
package PACKAGE
|
||||||
|
|
||||||
type Pointer uintptr // not really; filled in by compiler
|
type Pointer uintptr // not really; filled in by compiler
|
||||||
|
@ -6,6 +6,7 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"go/build"
|
"go/build"
|
||||||
"io"
|
"io"
|
||||||
@ -14,8 +15,8 @@ import (
|
|||||||
"os/exec"
|
"os/exec"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"regexp"
|
"regexp"
|
||||||
"runtime"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
"sync"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Break init cycles
|
// Break init cycles
|
||||||
@ -108,7 +109,11 @@ type builder struct {
|
|||||||
goroot string // the $GOROOT
|
goroot string // the $GOROOT
|
||||||
goarch string // the $GOARCH
|
goarch string // the $GOARCH
|
||||||
goos string // the $GOOS
|
goos string // the $GOOS
|
||||||
|
gobin string // the $GOBIN
|
||||||
actionCache map[cacheKey]*action // a cache of already-constructed actions
|
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.
|
// 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.nflag = nflag
|
||||||
b.xflag = xflag
|
b.xflag = xflag
|
||||||
b.actionCache = make(map[cacheKey]*action)
|
b.actionCache = make(map[cacheKey]*action)
|
||||||
b.goroot = runtime.GOROOT()
|
|
||||||
b.goarch = build.DefaultContext.GOARCH
|
b.goarch = build.DefaultContext.GOARCH
|
||||||
b.goos = build.DefaultContext.GOOS
|
b.goos = build.DefaultContext.GOOS
|
||||||
|
b.goroot = build.Path[0].Path
|
||||||
|
b.gobin = build.Path[0].BinDir()
|
||||||
|
|
||||||
b.arch, err = build.ArchChar(b.goarch)
|
b.arch, err = build.ArchChar(b.goarch)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -312,7 +318,11 @@ func (b *builder) do(a *action) {
|
|||||||
}
|
}
|
||||||
if a.f != nil {
|
if a.f != nil {
|
||||||
if err := a.f(b, a); err != nil {
|
if err := a.f(b, a); err != nil {
|
||||||
errorf("%s", err)
|
if err == errPrintedOutput {
|
||||||
|
exitStatus = 2
|
||||||
|
} else {
|
||||||
|
errorf("%s", err)
|
||||||
|
}
|
||||||
a.failed = true
|
a.failed = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -321,6 +331,14 @@ func (b *builder) do(a *action) {
|
|||||||
|
|
||||||
// build is the action for building a single package or command.
|
// build is the action for building a single package or command.
|
||||||
func (b *builder) build(a *action) error {
|
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)
|
obj := filepath.Join(b.work, filepath.FromSlash(a.p.ImportPath+"/_obj")) + string(filepath.Separator)
|
||||||
if a.pkgobj == "" {
|
if a.pkgobj == "" {
|
||||||
a.pkgobj = filepath.Join(b.work, filepath.FromSlash(a.p.ImportPath+".a"))
|
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
|
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 {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -405,7 +423,7 @@ func (b *builder) build(a *action) error {
|
|||||||
// additional reflect type data.
|
// additional reflect type data.
|
||||||
gcargs = append(gcargs, "-+")
|
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
|
return err
|
||||||
}
|
}
|
||||||
objects = append(objects, out)
|
objects = append(objects, out)
|
||||||
@ -439,7 +457,7 @@ func (b *builder) build(a *action) error {
|
|||||||
|
|
||||||
for _, file := range cfiles {
|
for _, file := range cfiles {
|
||||||
out := file[:len(file)-len(".c")] + "." + b.arch
|
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
|
return err
|
||||||
}
|
}
|
||||||
objects = append(objects, out)
|
objects = append(objects, out)
|
||||||
@ -448,14 +466,14 @@ func (b *builder) build(a *action) error {
|
|||||||
// assemble .s files
|
// assemble .s files
|
||||||
for _, file := range sfiles {
|
for _, file := range sfiles {
|
||||||
out := file[:len(file)-len(".s")] + "." + b.arch
|
out := file[:len(file)-len(".s")] + "." + 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
|
return err
|
||||||
}
|
}
|
||||||
objects = append(objects, out)
|
objects = append(objects, out)
|
||||||
}
|
}
|
||||||
|
|
||||||
// pack into archive
|
// 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
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -467,7 +485,7 @@ func (b *builder) build(a *action) error {
|
|||||||
inc[i] = "-L"
|
inc[i] = "-L"
|
||||||
}
|
}
|
||||||
a.pkgbin = obj + "a.out"
|
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
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -503,7 +521,7 @@ func (b *builder) install(a *action) error {
|
|||||||
// copyFile is like 'cp src dst'.
|
// copyFile is like 'cp src dst'.
|
||||||
func (b *builder) copyFile(dst, src string, perm uint32) error {
|
func (b *builder) copyFile(dst, src string, perm uint32) error {
|
||||||
if b.nflag || b.xflag {
|
if b.nflag || b.xflag {
|
||||||
b.showcmd("cp %s %s", src, dst)
|
b.showcmd("", "cp %s %s", src, dst)
|
||||||
if b.nflag {
|
if b.nflag {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -528,27 +546,91 @@ func (b *builder) copyFile(dst, src string, perm uint32) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// fmtcmd is like fmt.Sprintf but replaces references to the
|
// fmtcmd formats a command in the manner of fmt.Sprintf but also:
|
||||||
// work directory (a temporary directory with a clumsy name)
|
//
|
||||||
// with $WORK.
|
// If dir is non-empty and the script is not in dir right now,
|
||||||
func (b *builder) fmtcmd(format string, args ...interface{}) string {
|
// fmtcmd inserts "cd dir\n" before the command.
|
||||||
s := fmt.Sprintf(format, args...)
|
//
|
||||||
s = strings.Replace(s, b.work, "$WORK", -1)
|
// fmtcmd replaces the value of b.work with $WORK.
|
||||||
return s
|
// 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
|
// showcmd prints the given command to standard output
|
||||||
// for the implementation of -n or -x.
|
// for the implementation of -n or -x.
|
||||||
func (b *builder) showcmd(format string, args ...interface{}) {
|
func (b *builder) showcmd(dir string, format string, args ...interface{}) {
|
||||||
fmt.Println(b.fmtcmd(format, args...))
|
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.
|
// run runs the command given by cmdline in the directory dir.
|
||||||
// If the commnd fails, run prints information about the failure
|
// If the commnd fails, run prints information about the failure
|
||||||
// and returns a non-nil error.
|
// and returns a non-nil error.
|
||||||
func (b *builder) run(dir string, cmdline ...string) error {
|
func (b *builder) run(dir string, desc string, cmdline ...string) error {
|
||||||
if b.nflag || b.xflag {
|
if b.nflag || b.xflag {
|
||||||
b.showcmd("cd %s; %s", dir, strings.Join(cmdline, " "))
|
b.showcmd(dir, "%s", strings.Join(cmdline, " "))
|
||||||
if b.nflag {
|
if b.nflag {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -562,8 +644,17 @@ func (b *builder) run(dir string, cmdline ...string) error {
|
|||||||
// TODO: cmd.Env
|
// TODO: cmd.Env
|
||||||
err := cmd.Run()
|
err := cmd.Run()
|
||||||
if buf.Len() > 0 {
|
if buf.Len() > 0 {
|
||||||
fmt.Fprintf(os.Stderr, "# cd %s; %s\n", dir, strings.Join(cmdline, " "))
|
out := buf.Bytes()
|
||||||
fmt.Fprintf(os.Stderr, "%s\n", 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
|
return err
|
||||||
}
|
}
|
||||||
@ -571,7 +662,7 @@ func (b *builder) run(dir string, cmdline ...string) error {
|
|||||||
// mkdir makes the named directory.
|
// mkdir makes the named directory.
|
||||||
func (b *builder) mkdir(dir string) error {
|
func (b *builder) mkdir(dir string) error {
|
||||||
if b.nflag || b.xflag {
|
if b.nflag || b.xflag {
|
||||||
b.showcmd("mkdir -p %s", dir)
|
b.showcmd("", "mkdir -p %s", dir)
|
||||||
if b.nflag {
|
if b.nflag {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -583,50 +674,75 @@ func (b *builder) mkdir(dir string) error {
|
|||||||
return nil
|
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
|
// gc runs the Go compiler in a specific directory on a set of files
|
||||||
// to generate the named output file.
|
// 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 := []string{b.arch + "g", "-o", ofile}
|
||||||
args = append(args, gcargs...)
|
args = append(args, gcargs...)
|
||||||
args = append(args, importArgs...)
|
args = append(args, importArgs...)
|
||||||
args = append(args, gofiles...)
|
for _, f := range gofiles {
|
||||||
return b.run(dir, args...)
|
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
|
// asm runs the assembler in a specific directory on a specific file
|
||||||
// to generate the named output file.
|
// to generate the named output file.
|
||||||
func (b *builder) asm(dir, obj, ofile, sfile string) error {
|
func (b *builder) asm(p *Package, obj, ofile, sfile string) error {
|
||||||
return b.run(dir, b.arch+"a", "-I", obj, "-o", ofile, "-DGOOS_"+b.goos, "-DGOARCH_"+b.goarch, sfile)
|
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
|
// gopack runs the assembler in a specific directory to create
|
||||||
// an archive from a set of object files.
|
// an archive from a set of object files.
|
||||||
// typically it is run in the object directory.
|
// typically it is run in the object directory.
|
||||||
func (b *builder) gopack(objDir, afile string, ofiles []string) error {
|
func (b *builder) gopack(p *Package, objDir, afile string, ofiles []string) error {
|
||||||
return b.run(objDir, append([]string{"gopack", "grc", afile}, ofiles...)...)
|
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.
|
// ld runs the linker to create a package starting at mainpkg.
|
||||||
func (b *builder) ld(dir, out string, importArgs []string, mainpkg string) error {
|
func (b *builder) ld(p *Package, out string, importArgs []string, mainpkg string) error {
|
||||||
return b.run(dir, append(append([]string{b.arch + "l", "-o", out}, importArgs...), mainpkg)...)
|
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
|
// cc runs the gc-toolchain C compiler in a directory on a C file
|
||||||
// to produce an output file.
|
// to produce an output file.
|
||||||
func (b *builder) cc(dir, objdir, ofile, cfile string) error {
|
func (b *builder) cc(p *Package, objdir, ofile, cfile string) error {
|
||||||
inc := filepath.Join(runtime.GOROOT(), "pkg",
|
inc := filepath.Join(b.goroot, "pkg", fmt.Sprintf("%s_%s", b.goos, b.goarch))
|
||||||
fmt.Sprintf("%s_%s", b.goos, b.goarch))
|
cfile = mkAbs(p.Dir, cfile)
|
||||||
return b.run(dir, b.arch+"c", "-FVw", "-I", objdir, "-I", inc, "-o", ofile, "-DGOOS_"+b.goos, "-DGOARCH_"+b.goarch, 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.
|
// 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 {
|
func (b *builder) gcc(p *Package, out string, flags []string, cfile string) error {
|
||||||
return b.run(dir, b.gccCmd(dir, flags, "-o", out, "-c", cfile)...)
|
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
|
// 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 {
|
func (b *builder) gccld(p *Package, out string, flags []string, obj []string) error {
|
||||||
return b.run(dir, append(b.gccCmd(dir, flags, "-o", out), obj...)...)
|
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
|
// 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(`[/\\:]`)
|
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
|
// cgo
|
||||||
// TODO: CGOPKGPATH, CGO_FLAGS?
|
// TODO: CGOPKGPATH, CGO_FLAGS?
|
||||||
gofiles := []string{obj + "_cgo_gotypes.go"}
|
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, "--")
|
||||||
cgoArgs = append(cgoArgs, p.CgoFiles...)
|
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
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
outGo = append(outGo, gofiles...)
|
outGo = append(outGo, gofiles...)
|
||||||
|
|
||||||
// cc _cgo_defun.c
|
// cc _cgo_defun.c
|
||||||
defunObj := obj + "_cgo_defun." + b.arch
|
defunObj := obj + "_cgo_defun." + 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
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
outObj = append(outObj, defunObj)
|
outObj = append(outObj, defunObj)
|
||||||
@ -680,7 +796,7 @@ func (b *builder) cgo(dir, obj string, csfiles []string, p *Package) (outGo, out
|
|||||||
var linkobj []string
|
var linkobj []string
|
||||||
for _, cfile := range cfiles {
|
for _, cfile := range cfiles {
|
||||||
ofile := obj + cfile[:len(cfile)-1] + "o"
|
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
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
linkobj = append(linkobj, ofile)
|
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)
|
outObj = append(outObj, ofile)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for _, file := range csfiles {
|
for _, file := range gccfiles {
|
||||||
ofile := obj + cgoRe.ReplaceAllString(file[:len(file)-1], "_") + "o"
|
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
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
linkobj = append(linkobj, ofile)
|
linkobj = append(linkobj, ofile)
|
||||||
outObj = append(outObj, ofile)
|
outObj = append(outObj, ofile)
|
||||||
}
|
}
|
||||||
dynobj := obj + "_cgo_.o"
|
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
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// cgo -dynimport
|
// cgo -dynimport
|
||||||
importC := obj + "_cgo_import.c"
|
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
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// cc _cgo_import.ARCH
|
// cc _cgo_import.ARCH
|
||||||
importObj := obj + "_cgo_import." + b.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
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
outObj = append(outObj, importObj)
|
outObj = append(outObj, importObj)
|
||||||
|
@ -14,7 +14,7 @@ var cmdList = &Command{
|
|||||||
UsageLine: "list [-f format] [-json] [importpath...]",
|
UsageLine: "list [-f format] [-json] [importpath...]",
|
||||||
Short: "list packages",
|
Short: "list packages",
|
||||||
Long: `
|
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:
|
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,
|
The -f flag specifies an alternate format for the list,
|
||||||
using the syntax of package template. The default output
|
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:
|
being passed to the template is:
|
||||||
|
|
||||||
type Package struct {
|
type Package struct {
|
||||||
@ -57,7 +57,7 @@ func init() {
|
|||||||
cmdList.Run = runList // break init cycle
|
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 listJson = cmdList.Flag.Bool("json", false, "")
|
||||||
var nl = []byte{'\n'}
|
var nl = []byte{'\n'}
|
||||||
|
|
||||||
|
@ -237,8 +237,38 @@ func run(cmdline ...string) {
|
|||||||
// allPackages returns all the packages that can be found
|
// allPackages returns all the packages that can be found
|
||||||
// under the $GOPATH directories and $GOROOT.
|
// under the $GOPATH directories and $GOROOT.
|
||||||
func allPackages() []string {
|
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
|
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 {
|
for _, t := range build.Path {
|
||||||
src := t.SrcDir() + string(filepath.Separator)
|
src := t.SrcDir() + string(filepath.Separator)
|
||||||
filepath.Walk(src, func(path string, fi os.FileInfo, err error) error {
|
filepath.Walk(src, func(path string, fi os.FileInfo, err error) error {
|
||||||
@ -256,21 +286,19 @@ func allPackages() []string {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
name := path[len(src):]
|
name := path[len(src):]
|
||||||
if have[name] {
|
if !have[name] {
|
||||||
return nil
|
pkgs = append(pkgs, name)
|
||||||
|
have[name] = true
|
||||||
}
|
}
|
||||||
pkgs = append(pkgs, name)
|
|
||||||
have[name] = true
|
|
||||||
|
|
||||||
// Avoid go/build test data.
|
// Avoid go/build test data.
|
||||||
|
// TODO: Move it into a testdata directory.
|
||||||
if path == filepath.Join(build.Path[0].SrcDir(), "go/build") {
|
if path == filepath.Join(build.Path[0].SrcDir(), "go/build") {
|
||||||
return filepath.SkipDir
|
return filepath.SkipDir
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
|
|
||||||
// TODO: Commands.
|
|
||||||
}
|
}
|
||||||
return pkgs
|
return pkgs
|
||||||
}
|
}
|
||||||
|
@ -70,13 +70,15 @@ func loadPackage(arg string) (*Package, error) {
|
|||||||
|
|
||||||
// Find basic information about package path.
|
// Find basic information about package path.
|
||||||
t, importPath, err := build.FindTree(arg)
|
t, importPath, err := build.FindTree(arg)
|
||||||
|
dir := ""
|
||||||
// Maybe it is a standard command.
|
// 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]
|
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() {
|
if st, err1 := os.Stat(p); err1 == nil && st.IsDir() {
|
||||||
t = goroot
|
t = goroot
|
||||||
importPath = "../cmd/" + arg
|
importPath = arg
|
||||||
|
dir = p
|
||||||
err = nil
|
err = nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -84,7 +86,9 @@ func loadPackage(arg string) (*Package, error) {
|
|||||||
return nil, err
|
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.
|
// Maybe we know the package by its directory.
|
||||||
if p := packageCache[dir]; p != nil {
|
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)
|
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.
|
// Record package under both import path and full directory name.
|
||||||
packageCache[dir] = p
|
packageCache[dir] = p
|
||||||
packageCache[importPath] = p
|
packageCache[importPath] = p
|
||||||
|
Loading…
Reference in New Issue
Block a user