summaryrefslogtreecommitdiff
path: root/src/cmd/go
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd/go')
-rw-r--r--src/cmd/go/build.go626
-rw-r--r--src/cmd/go/clean.go41
-rw-r--r--src/cmd/go/context.go36
-rw-r--r--src/cmd/go/discovery.go3
-rw-r--r--src/cmd/go/doc.go116
-rw-r--r--src/cmd/go/env.go34
-rw-r--r--src/cmd/go/get.go11
-rw-r--r--src/cmd/go/help.go46
-rw-r--r--src/cmd/go/list.go55
-rw-r--r--src/cmd/go/main.go6
-rw-r--r--src/cmd/go/pkg.go33
-rw-r--r--src/cmd/go/pkg_test.go73
-rw-r--r--src/cmd/go/run.go39
-rw-r--r--src/cmd/go/signal_unix.go2
-rwxr-xr-xsrc/cmd/go/test.bash211
-rw-r--r--src/cmd/go/test.go142
-rw-r--r--src/cmd/go/testdata/cgocover/p.go19
-rw-r--r--src/cmd/go/testdata/cgocover/p_test.go7
-rw-r--r--src/cmd/go/testdata/dep_test.go7
-rw-r--r--src/cmd/go/testdata/src/notest/hello.go6
-rw-r--r--src/cmd/go/testdata/src/testcycle/p1/p1.go7
-rw-r--r--src/cmd/go/testdata/src/testcycle/p1/p1_test.go6
-rw-r--r--src/cmd/go/testdata/src/testcycle/p2/p2.go7
-rw-r--r--src/cmd/go/testdata/src/testcycle/p3/p3.go5
-rw-r--r--src/cmd/go/testdata/src/testcycle/p3/p3_test.go10
-rw-r--r--src/cmd/go/testdata/src/xtestonly/f.go3
-rw-r--r--src/cmd/go/testdata/src/xtestonly/f_test.go12
-rw-r--r--src/cmd/go/testdata/standalone_test.go6
-rw-r--r--src/cmd/go/testdata/testonly/p_test.go1
-rw-r--r--src/cmd/go/testflag.go23
-rw-r--r--src/cmd/go/vcs.go10
31 files changed, 1237 insertions, 366 deletions
diff --git a/src/cmd/go/build.go b/src/cmd/go/build.go
index f70f778d9..3645f1c2d 100644
--- a/src/cmd/go/build.go
+++ b/src/cmd/go/build.go
@@ -5,6 +5,7 @@
package main
import (
+ "bufio"
"bytes"
"container/heap"
"errors"
@@ -27,7 +28,7 @@ import (
)
var cmdBuild = &Command{
- UsageLine: "build [-o output] [build flags] [packages]",
+ UsageLine: "build [-o output] [-i] [build flags] [packages]",
Short: "compile packages and dependencies",
Long: `
Build compiles the packages named by the import paths,
@@ -49,7 +50,10 @@ derives from the first file name mentioned, such as f1 for 'go build
f1.go f2.go'; with no files provided ('go build'), the output file
name is the base name of the containing directory.
-The build flags are shared by the build, install, run, and test commands:
+The -i flag installs the packages that are dependencies of the target.
+
+The build flags are shared by the build, clean, get, install, list, run,
+and test commands:
-a
force rebuilding of packages that are already up-to-date.
@@ -86,8 +90,8 @@ The build flags are shared by the build, install, run, and test commands:
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 information about build tags, see the description of
+ build constraints in the documentation for the go/build package.
The list flags accept a space-separated list of strings. To embed spaces
in an element in the list, surround it with either single or double quotes.
@@ -106,6 +110,8 @@ func init() {
cmdBuild.Run = runBuild
cmdInstall.Run = runInstall
+ cmdBuild.Flag.BoolVar(&buildI, "i", false, "")
+
addBuildFlags(cmdBuild)
addBuildFlags(cmdInstall)
}
@@ -116,6 +122,7 @@ var buildN bool // -n flag
var buildP = runtime.NumCPU() // -p flag
var buildV bool // -v flag
var buildX bool // -x flag
+var buildI bool // -i flag
var buildO = cmdBuild.Flag.String("o", "", "output file")
var buildWork bool // -work flag
var buildGcflags []string // -gcflags flag
@@ -158,7 +165,8 @@ func init() {
}
}
-// addBuildFlags adds the flags common to the build and install commands.
+// addBuildFlags adds the flags common to the build, clean, get,
+// install, list, run, and test commands.
func addBuildFlags(cmd *Command) {
// NOTE: If you add flags here, also add them to testflag.go.
cmd.Flag.BoolVar(&buildA, "a", false, "")
@@ -203,6 +211,9 @@ type stringsFlag []string
func (v *stringsFlag) Set(s string) error {
var err error
*v, err = splitQuotedFields(s)
+ if *v == nil {
+ *v = []string{}
+ }
return err
}
@@ -286,8 +297,12 @@ func runBuild(cmd *Command, args []string) {
}
a := &action{}
+ depMode := modeBuild
+ if buildI {
+ depMode = modeInstall
+ }
for _, p := range packages(args) {
- a.deps = append(a.deps, b.action(modeBuild, modeBuild, p))
+ a.deps = append(a.deps, b.action(modeBuild, depMode, p))
}
b.do(a)
}
@@ -349,7 +364,12 @@ func init() {
var err error
archChar, err = build.ArchChar(goarch)
if err != nil {
- fatalf("%s", err)
+ if _, isgc := buildToolchain.(gcToolchain); isgc {
+ fatalf("%s", err)
+ }
+ // archChar is only required for gcToolchain, if we're using
+ // another toolchain leave it blank.
+ archChar = ""
}
}
@@ -438,7 +458,8 @@ func (b *builder) init() {
fmt.Fprintf(os.Stderr, "WORK=%s\n", b.work)
}
if !buildWork {
- atexit(func() { os.RemoveAll(b.work) })
+ workdir := b.work
+ atexit(func() { os.RemoveAll(workdir) })
}
}
}
@@ -760,6 +781,11 @@ func (b *builder) build(a *action) (err error) {
return fmt.Errorf("can't build package %s because it contains C++ files (%s) but it's not using cgo nor SWIG",
a.p.ImportPath, strings.Join(a.p.CXXFiles, ","))
}
+ // Same as above for Objective-C files
+ if len(a.p.MFiles) > 0 && !a.p.usesCgo() && !a.p.usesSwig() {
+ return fmt.Errorf("can't build package %s because it contains Objective-C files (%s) but it's not using cgo nor SWIG",
+ a.p.ImportPath, strings.Join(a.p.MFiles, ","))
+ }
defer func() {
if err != nil && err != errPrintedOutput {
err = fmt.Errorf("go build %s: %v", a.p.ImportPath, err)
@@ -799,25 +825,7 @@ func (b *builder) build(a *action) (err error) {
var gofiles, cfiles, sfiles, objects, cgoObjects []string
- // If we're doing coverage, preprocess the .go files and put them in the work directory
- if a.p.coverMode != "" {
- for _, file := range a.p.GoFiles {
- sourceFile := filepath.Join(a.p.Dir, file)
- cover := a.p.coverVars[file]
- if cover == nil || isTestFile(file) {
- // Not covering this file.
- gofiles = append(gofiles, file)
- continue
- }
- coverFile := filepath.Join(obj, file)
- if err := b.cover(a, coverFile, sourceFile, 0666, cover.Var); err != nil {
- return err
- }
- gofiles = append(gofiles, coverFile)
- }
- } else {
- gofiles = append(gofiles, a.p.GoFiles...)
- }
+ gofiles = append(gofiles, a.p.GoFiles...)
cfiles = append(cfiles, a.p.CFiles...)
sfiles = append(sfiles, a.p.SFiles...)
@@ -851,7 +859,7 @@ func (b *builder) build(a *action) (err error) {
if a.cgo != nil && a.cgo.target != "" {
cgoExe = a.cgo.target
}
- outGo, outObj, err := b.cgo(a.p, cgoExe, obj, gccfiles, a.p.CXXFiles)
+ outGo, outObj, err := b.cgo(a.p, cgoExe, obj, gccfiles, a.p.CXXFiles, a.p.MFiles)
if err != nil {
return err
}
@@ -866,7 +874,7 @@ func (b *builder) build(a *action) (err error) {
gccfiles := append(cfiles, sfiles...)
cfiles = nil
sfiles = nil
- outGo, outObj, err := b.swig(a.p, obj, gccfiles, a.p.CXXFiles)
+ outGo, outObj, err := b.swig(a.p, obj, gccfiles, a.p.CXXFiles, a.p.MFiles)
if err != nil {
return err
}
@@ -874,21 +882,54 @@ func (b *builder) build(a *action) (err error) {
gofiles = append(gofiles, outGo...)
}
+ if len(gofiles) == 0 {
+ return &build.NoGoError{a.p.Dir}
+ }
+
+ // If we're doing coverage, preprocess the .go files and put them in the work directory
+ if a.p.coverMode != "" {
+ for i, file := range gofiles {
+ var sourceFile string
+ var coverFile string
+ var key string
+ if strings.HasSuffix(file, ".cgo1.go") {
+ // cgo files have absolute paths
+ base := filepath.Base(file)
+ sourceFile = file
+ coverFile = filepath.Join(obj, base)
+ key = strings.TrimSuffix(base, ".cgo1.go") + ".go"
+ } else {
+ sourceFile = filepath.Join(a.p.Dir, file)
+ coverFile = filepath.Join(obj, file)
+ key = file
+ }
+ cover := a.p.coverVars[key]
+ if cover == nil || isTestFile(file) {
+ // Not covering this file.
+ continue
+ }
+ if err := b.cover(a, coverFile, sourceFile, 0666, cover.Var); err != nil {
+ return err
+ }
+ gofiles[i] = coverFile
+ }
+ }
+
// Prepare Go import path list.
inc := b.includeArgs("-I", a.deps)
// Compile Go.
- if len(gofiles) > 0 {
- ofile, out, err := buildToolchain.gc(b, a.p, obj, inc, gofiles)
- if len(out) > 0 {
- b.showOutput(a.p.Dir, a.p.ImportPath, b.processOutput(out))
- if err != nil {
- return errPrintedOutput
- }
- }
+ ofile, out, err := buildToolchain.gc(b, a.p, a.objpkg, obj, inc, gofiles)
+ if len(out) > 0 {
+ b.showOutput(a.p.Dir, a.p.ImportPath, b.processOutput(out))
if err != nil {
- return err
+ return errPrintedOutput
}
+ }
+ if err != nil {
+ return err
+ }
+ if ofile != a.objpkg {
objects = append(objects, ofile)
}
@@ -903,17 +944,17 @@ func (b *builder) build(a *action) (err error) {
switch {
case strings.HasSuffix(name, _goos_goarch):
targ := file[:len(name)-len(_goos_goarch)] + "_GOOS_GOARCH." + ext
- if err := b.copyFile(a, obj+targ, filepath.Join(a.p.Dir, file), 0666); err != nil {
+ if err := b.copyFile(a, obj+targ, filepath.Join(a.p.Dir, file), 0644); err != nil {
return err
}
case strings.HasSuffix(name, _goarch):
targ := file[:len(name)-len(_goarch)] + "_GOARCH." + ext
- if err := b.copyFile(a, obj+targ, filepath.Join(a.p.Dir, file), 0666); err != nil {
+ if err := b.copyFile(a, obj+targ, filepath.Join(a.p.Dir, file), 0644); err != nil {
return err
}
case strings.HasSuffix(name, _goos):
targ := file[:len(name)-len(_goos)] + "_GOOS." + ext
- if err := b.copyFile(a, obj+targ, filepath.Join(a.p.Dir, file), 0666); err != nil {
+ if err := b.copyFile(a, obj+targ, filepath.Join(a.p.Dir, file), 0644); err != nil {
return err
}
}
@@ -952,9 +993,15 @@ func (b *builder) build(a *action) (err error) {
objects = append(objects, filepath.Join(a.p.Dir, syso))
}
- // Pack into archive in obj directory
- if err := buildToolchain.pack(b, a.p, obj, a.objpkg, objects); err != nil {
- return err
+ // Pack into archive in obj directory.
+ // If the Go compiler wrote an archive, we only need to add the
+ // object files for non-Go sources to the archive.
+ // If the Go compiler wrote an archive and the package is entirely
+ // Go sources, there is no pack to execute at all.
+ if len(objects) > 0 {
+ if err := buildToolchain.pack(b, a.p, obj, a.objpkg, objects); err != nil {
+ return err
+ }
}
// Link if needed.
@@ -979,9 +1026,9 @@ func (b *builder) install(a *action) (err error) {
}
}()
a1 := a.deps[0]
- perm := os.FileMode(0666)
+ perm := os.FileMode(0644)
if a1.link {
- perm = 0777
+ perm = 0755
}
// make target directory
@@ -1001,22 +1048,7 @@ func (b *builder) install(a *action) (err error) {
defer os.Remove(a1.target)
}
- if a.p.usesSwig() {
- for _, f := range stringList(a.p.SwigFiles, a.p.SwigCXXFiles) {
- dir = a.p.swigDir(&buildContext)
- if err := b.mkdir(dir); err != nil {
- return err
- }
- soname := a.p.swigSoname(f)
- source := filepath.Join(a.objdir, soname)
- target := filepath.Join(dir, soname)
- if err = b.copyFile(a, target, source, perm); err != nil {
- return err
- }
- }
- }
-
- return b.copyFile(a, a.target, a1.target, perm)
+ return b.moveOrCopyFile(a, a.target, a1.target, perm)
}
// includeArgs returns the -I or -L directory list for access
@@ -1062,6 +1094,27 @@ func (b *builder) includeArgs(flag string, all []*action) []string {
return inc
}
+// moveOrCopyFile is like 'mv src dst' or 'cp src dst'.
+func (b *builder) moveOrCopyFile(a *action, dst, src string, perm os.FileMode) error {
+ if buildN {
+ b.showcmd("", "mv %s %s", src, dst)
+ return nil
+ }
+
+ // If we can update the mode and rename to the dst, do it.
+ // Otherwise fall back to standard copy.
+ if err := os.Chmod(src, perm); err == nil {
+ if err := os.Rename(src, dst); err == nil {
+ if buildX {
+ b.showcmd("", "mv %s %s", src, dst)
+ }
+ return nil
+ }
+ }
+
+ return b.copyFile(a, dst, src, perm)
+}
+
// copyFile is like 'cp src dst'.
func (b *builder) copyFile(a *action, dst, src string, perm os.FileMode) error {
if buildN || buildX {
@@ -1262,6 +1315,7 @@ func relPaths(paths []string) []string {
var errPrintedOutput = errors.New("already printed output - no need to show error")
var cgoLine = regexp.MustCompile(`\[[^\[\]]+\.cgo1\.go:[0-9]+\]`)
+var cgoTypeSigRe = regexp.MustCompile(`\b_Ctype_\B`)
// run runs the command given by cmdline in the directory dir.
// If the command fails, run prints information about the failure
@@ -1288,11 +1342,11 @@ func (b *builder) processOutput(out []byte) string {
messages := string(out)
// Fix up output referring to cgo-generated code to be more readable.
// Replace x.go:19[/tmp/.../x.cgo1.go:18] with x.go:19.
- // Replace _Ctype_foo with C.foo.
+ // Replace *[100]_Ctype_foo with *[100]C.foo.
// If we're using -x, assume we're debugging and want the full dump, so disable the rewrite.
if !buildX && cgoLine.MatchString(messages) {
messages = cgoLine.ReplaceAllString(messages, "")
- messages = strings.Replace(messages, "type _Ctype_", "type C.", -1)
+ messages = cgoTypeSigRe.ReplaceAllString(messages, "C.")
}
return messages
}
@@ -1302,7 +1356,13 @@ func (b *builder) processOutput(out []byte) string {
func (b *builder) runOut(dir string, desc string, env []string, cmdargs ...interface{}) ([]byte, error) {
cmdline := stringList(cmdargs...)
if buildN || buildX {
- b.showcmd(dir, "%s", joinUnambiguously(cmdline))
+ var envcmdline string
+ for i := range env {
+ envcmdline += env[i]
+ envcmdline += " "
+ }
+ envcmdline += joinUnambiguously(cmdline)
+ b.showcmd(dir, "%s", envcmdline)
if buildN {
return nil, nil
}
@@ -1432,7 +1492,7 @@ 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.
// The compiler runs in the directory dir.
- gc(b *builder, p *Package, obj string, importArgs []string, gofiles []string) (ofile string, out []byte, err error)
+ gc(b *builder, p *Package, archive, obj string, importArgs []string, gofiles []string) (ofile string, out []byte, 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
@@ -1469,7 +1529,7 @@ func (noToolchain) linker() string {
return ""
}
-func (noToolchain) gc(b *builder, p *Package, obj string, importArgs []string, gofiles []string) (ofile string, out []byte, err error) {
+func (noToolchain) gc(b *builder, p *Package, archive, obj string, importArgs []string, gofiles []string) (ofile string, out []byte, err error) {
return "", nil, noCompiler()
}
@@ -1505,9 +1565,14 @@ func (gcToolchain) linker() string {
return tool(archChar + "l")
}
-func (gcToolchain) gc(b *builder, p *Package, obj string, importArgs []string, gofiles []string) (ofile string, output []byte, err error) {
- out := "_go_." + archChar
- ofile = obj + out
+func (gcToolchain) gc(b *builder, p *Package, archive, obj string, importArgs []string, gofiles []string) (ofile string, output []byte, err error) {
+ if archive != "" {
+ ofile = archive
+ } else {
+ out := "_go_." + archChar
+ ofile = obj + out
+ }
+
gcargs := []string{"-p", p.ImportPath}
if p.Standard && p.ImportPath == "runtime" {
// runtime compiles with a special 6g flag to emit
@@ -1519,7 +1584,7 @@ func (gcToolchain) gc(b *builder, p *Package, obj string, importArgs []string, g
// so that it can give good error messages about forward declarations.
// Exceptions: a few standard packages have forward declarations for
// pieces supplied behind-the-scenes by package runtime.
- extFiles := len(p.CgoFiles) + len(p.CFiles) + len(p.CXXFiles) + len(p.SFiles) + len(p.SysoFiles) + len(p.SwigFiles) + len(p.SwigCXXFiles)
+ extFiles := len(p.CgoFiles) + len(p.CFiles) + len(p.CXXFiles) + len(p.MFiles) + len(p.SFiles) + len(p.SysoFiles) + len(p.SwigFiles) + len(p.SwigCXXFiles)
if p.Standard {
switch p.ImportPath {
case "os", "runtime/pprof", "sync", "time":
@@ -1533,7 +1598,10 @@ func (gcToolchain) gc(b *builder, p *Package, obj string, importArgs []string, g
gcargs = append(gcargs, "-installsuffix", buildContext.InstallSuffix)
}
- args := stringList(tool(archChar+"g"), "-o", ofile, buildGcflags, gcargs, "-D", p.localPrefix, importArgs)
+ args := stringList(tool(archChar+"g"), "-o", ofile, "-trimpath", b.work, buildGcflags, gcargs, "-D", p.localPrefix, importArgs)
+ if ofile == archive {
+ args = append(args, "-pack")
+ }
for _, f := range gofiles {
args = append(args, mkAbs(p.Dir, f))
}
@@ -1544,7 +1612,7 @@ func (gcToolchain) gc(b *builder, p *Package, obj string, importArgs []string, g
func (gcToolchain) asm(b *builder, p *Package, obj, ofile, sfile string) error {
sfile = mkAbs(p.Dir, sfile)
- return b.run(p.Dir, p.ImportPath, nil, tool(archChar+"a"), "-I", obj, "-o", ofile, "-D", "GOOS_"+goos, "-D", "GOARCH_"+goarch, sfile)
+ return b.run(p.Dir, p.ImportPath, nil, tool(archChar+"a"), "-trimpath", b.work, "-I", obj, "-o", ofile, "-D", "GOOS_"+goos, "-D", "GOARCH_"+goarch, sfile)
}
func (gcToolchain) pkgpath(basedir string, p *Package) string {
@@ -1557,83 +1625,148 @@ func (gcToolchain) pack(b *builder, p *Package, objDir, afile string, ofiles []s
for _, f := range ofiles {
absOfiles = append(absOfiles, mkAbs(objDir, f))
}
- return b.run(p.Dir, p.ImportPath, nil, tool("pack"), "grcP", b.work, mkAbs(objDir, afile), absOfiles)
+ cmd := "c"
+ absAfile := mkAbs(objDir, afile)
+ appending := false
+ if _, err := os.Stat(absAfile); err == nil {
+ appending = true
+ cmd = "r"
+ }
+
+ cmdline := stringList("pack", cmd, absAfile, absOfiles)
+
+ if appending {
+ if buildN || buildX {
+ b.showcmd(p.Dir, "%s # internal", joinUnambiguously(cmdline))
+ }
+ if buildN {
+ return nil
+ }
+ if err := packInternal(b, absAfile, absOfiles); err != nil {
+ b.showOutput(p.Dir, p.ImportPath, err.Error()+"\n")
+ return errPrintedOutput
+ }
+ return nil
+ }
+
+ // Need actual pack.
+ cmdline[0] = tool("pack")
+ return b.run(p.Dir, p.ImportPath, nil, cmdline)
+}
+
+func packInternal(b *builder, afile string, ofiles []string) error {
+ dst, err := os.OpenFile(afile, os.O_WRONLY|os.O_APPEND, 0)
+ if err != nil {
+ return err
+ }
+ defer dst.Close() // only for error returns or panics
+ w := bufio.NewWriter(dst)
+
+ for _, ofile := range ofiles {
+ src, err := os.Open(ofile)
+ if err != nil {
+ return err
+ }
+ fi, err := src.Stat()
+ if err != nil {
+ src.Close()
+ return err
+ }
+ // Note: Not using %-16.16s format because we care
+ // about bytes, not runes.
+ name := fi.Name()
+ if len(name) > 16 {
+ name = name[:16]
+ } else {
+ name += strings.Repeat(" ", 16-len(name))
+ }
+ size := fi.Size()
+ fmt.Fprintf(w, "%s%-12d%-6d%-6d%-8o%-10d`\n",
+ name, 0, 0, 0, 0644, size)
+ n, err := io.Copy(w, src)
+ src.Close()
+ if err == nil && n < size {
+ err = io.ErrUnexpectedEOF
+ } else if err == nil && n > size {
+ err = fmt.Errorf("file larger than size reported by stat")
+ }
+ if err != nil {
+ return fmt.Errorf("copying %s to %s: %v", ofile, afile, err)
+ }
+ if size&1 != 0 {
+ w.WriteByte(0)
+ }
+ }
+
+ if err := w.Flush(); err != nil {
+ return err
+ }
+ return dst.Close()
}
func (gcToolchain) ld(b *builder, p *Package, out string, allactions []*action, mainpkg string, ofiles []string) error {
importArgs := b.includeArgs("-L", allactions)
- swigDirs := make(map[string]bool)
- swigArg := []string{}
cxx := false
for _, a := range allactions {
- if a.p != nil && a.p.usesSwig() {
- sd := a.p.swigDir(&buildContext)
- if len(swigArg) == 0 {
- swigArg = []string{"-r", sd}
- } else if !swigDirs[sd] {
- swigArg[1] += ":"
- swigArg[1] += sd
- }
- swigDirs[sd] = true
- if a.objdir != "" && !swigDirs[a.objdir] {
- swigArg[1] += ":"
- swigArg[1] += a.objdir
- swigDirs[a.objdir] = true
- }
- }
if a.p != nil && len(a.p.CXXFiles) > 0 {
cxx = true
}
}
ldflags := buildLdflags
+ // Limit slice capacity so that concurrent appends do not race on the shared array.
+ ldflags = ldflags[:len(ldflags):len(ldflags)]
if buildContext.InstallSuffix != "" {
ldflags = append(ldflags, "-installsuffix", buildContext.InstallSuffix)
}
- if cxx {
- // The program includes C++ code. If the user has not
- // specified the -extld option, then default to
- // linking with the compiler named by the CXX
- // environment variable, or g++ if CXX is not set.
- extld := false
- for _, f := range ldflags {
- if f == "-extld" || strings.HasPrefix(f, "-extld=") {
- extld = true
- break
- }
+ if p.omitDWARF {
+ ldflags = append(ldflags, "-w")
+ }
+
+ // If the user has not specified the -extld option, then specify the
+ // appropriate linker. In case of C++ code, use the compiler named
+ // by the CXX environment variable or defaultCXX if CXX is not set.
+ // Else, use the CC environment variable and defaultCC as fallback.
+ extld := false
+ for _, f := range ldflags {
+ if f == "-extld" || strings.HasPrefix(f, "-extld=") {
+ extld = true
+ break
}
- if !extld {
- compiler := strings.Fields(os.Getenv("CXX"))
- if len(compiler) == 0 {
- compiler = []string{"g++"}
- }
- ldflags = append(ldflags, "-extld="+compiler[0])
- if len(compiler) > 1 {
- extldflags := false
- add := strings.Join(compiler[1:], " ")
- for i, f := range ldflags {
- if f == "-extldflags" && i+1 < len(ldflags) {
- ldflags[i+1] = add + " " + ldflags[i+1]
- extldflags = true
- break
- } else if strings.HasPrefix(f, "-extldflags=") {
- ldflags[i] = "-extldflags=" + add + " " + ldflags[i][len("-extldflags="):]
- extldflags = true
- break
- }
- }
- if !extldflags {
- ldflags = append(ldflags, "-extldflags="+add)
+ }
+ if !extld {
+ var compiler []string
+ if cxx {
+ compiler = envList("CXX", defaultCXX)
+ } else {
+ compiler = envList("CC", defaultCC)
+ }
+ ldflags = append(ldflags, "-extld="+compiler[0])
+ if len(compiler) > 1 {
+ extldflags := false
+ add := strings.Join(compiler[1:], " ")
+ for i, f := range ldflags {
+ if f == "-extldflags" && i+1 < len(ldflags) {
+ ldflags[i+1] = add + " " + ldflags[i+1]
+ extldflags = true
+ break
+ } else if strings.HasPrefix(f, "-extldflags=") {
+ ldflags[i] = "-extldflags=" + add + " " + ldflags[i][len("-extldflags="):]
+ extldflags = true
+ break
}
}
+ if !extldflags {
+ ldflags = append(ldflags, "-extldflags="+add)
+ }
}
}
- return b.run(".", p.ImportPath, nil, tool(archChar+"l"), "-o", out, importArgs, swigArg, ldflags, mainpkg)
+ return b.run(".", p.ImportPath, nil, tool(archChar+"l"), "-o", out, importArgs, ldflags, mainpkg)
}
func (gcToolchain) cc(b *builder, p *Package, objdir, ofile, cfile string) error {
inc := filepath.Join(goroot, "pkg", fmt.Sprintf("%s_%s", goos, goarch))
cfile = mkAbs(p.Dir, cfile)
- args := stringList(tool(archChar+"c"), "-F", "-V", "-w", "-I", objdir, "-I", inc, "-o", ofile, buildCcflags, "-D", "GOOS_"+goos, "-D", "GOARCH_"+goarch, cfile)
+ args := stringList(tool(archChar+"c"), "-F", "-V", "-w", "-trimpath", b.work, "-I", objdir, "-I", inc, "-o", ofile, buildCcflags, "-D", "GOOS_"+goos, "-D", "GOARCH_"+goarch, cfile)
return b.run(p.Dir, p.ImportPath, nil, args)
}
@@ -1650,7 +1783,7 @@ func (gccgoToolchain) linker() string {
return gccgoBin
}
-func (gccgoToolchain) gc(b *builder, p *Package, obj string, importArgs []string, gofiles []string) (ofile string, output []byte, err error) {
+func (gccgoToolchain) gc(b *builder, p *Package, archive, obj string, importArgs []string, gofiles []string) (ofile string, output []byte, err error) {
out := p.Name + ".o"
ofile = obj + out
gcargs := []string{"-g"}
@@ -1698,52 +1831,62 @@ func (gccgoToolchain) pack(b *builder, p *Package, objDir, afile string, ofiles
func (tools gccgoToolchain) ld(b *builder, p *Package, out string, allactions []*action, mainpkg string, ofiles []string) error {
// gccgo needs explicit linking with all package dependencies,
// and all LDFLAGS from cgo dependencies.
- afiles := make(map[*Package]string)
- sfiles := make(map[*Package][]string)
+ apackagesSeen := make(map[*Package]bool)
+ afiles := []string{}
ldflags := b.gccArchArgs()
cgoldflags := []string{}
usesCgo := false
cxx := false
- for _, a := range allactions {
- if a.p != nil {
- if !a.p.Standard {
- if afiles[a.p] == "" || a.objpkg != a.target {
- afiles[a.p] = a.target
+ objc := false
+
+ // Prefer the output of an install action to the output of a build action,
+ // because the install action will delete the output of the build action.
+ // Iterate over the list backward (reverse dependency order) so that we
+ // always see the install before the build.
+ for i := len(allactions) - 1; i >= 0; i-- {
+ a := allactions[i]
+ if !a.p.Standard {
+ if a.p != nil && !apackagesSeen[a.p] {
+ apackagesSeen[a.p] = true
+ if a.p.fake {
+ // move _test files to the top of the link order
+ afiles = append([]string{a.target}, afiles...)
+ } else {
+ afiles = append(afiles, a.target)
}
}
+ }
+ }
+
+ for _, a := range allactions {
+ if a.p != nil {
cgoldflags = append(cgoldflags, a.p.CgoLDFLAGS...)
if len(a.p.CgoFiles) > 0 {
usesCgo = true
}
if a.p.usesSwig() {
- sd := a.p.swigDir(&buildContext)
- if a.objdir != "" {
- sd = a.objdir
- }
- for _, f := range stringList(a.p.SwigFiles, a.p.SwigCXXFiles) {
- soname := a.p.swigSoname(f)
- sfiles[a.p] = append(sfiles[a.p], filepath.Join(sd, soname))
- }
usesCgo = true
}
if len(a.p.CXXFiles) > 0 {
cxx = true
}
+ if len(a.p.MFiles) > 0 {
+ objc = true
+ }
}
}
- for _, afile := range afiles {
- ldflags = append(ldflags, afile)
- }
- for _, sfiles := range sfiles {
- ldflags = append(ldflags, sfiles...)
- }
+ ldflags = append(ldflags, afiles...)
ldflags = append(ldflags, cgoldflags...)
+ ldflags = append(ldflags, p.CgoLDFLAGS...)
if usesCgo && goos == "linux" {
ldflags = append(ldflags, "-Wl,-E")
}
if cxx {
ldflags = append(ldflags, "-lstdc++")
}
+ if objc {
+ ldflags = append(ldflags, "-lobjc")
+ }
return b.run(".", p.ImportPath, nil, "gccgo", "-o", out, ofiles, "-Wl,-(", ldflags, "-Wl,-)", buildGccgoflags)
}
@@ -1856,16 +1999,13 @@ func (b *builder) gxxCmd(objdir string) []string {
}
// ccompilerCmd returns a command line prefix for the given environment
-// variable and using the default command when the variable is empty
+// variable and using the default command when the variable is empty.
func (b *builder) ccompilerCmd(envvar, defcmd, objdir string) []string {
// NOTE: env.go's mkEnv knows that the first three
// strings returned are "gcc", "-I", objdir (and cuts them off).
- compiler := strings.Fields(os.Getenv(envvar))
- if len(compiler) == 0 {
- compiler = strings.Fields(defcmd)
- }
- a := []string{compiler[0], "-I", objdir, "-g", "-O2"}
+ compiler := envList(envvar, defcmd)
+ a := []string{compiler[0], "-I", objdir}
a = append(a, compiler[1:]...)
// Definitely want -fPIC but on Windows gcc complains
@@ -1892,6 +2032,9 @@ func (b *builder) ccompilerCmd(envvar, defcmd, objdir string) []string {
a = append(a, "-Qunused-arguments")
}
+ // disable word wrapping in error messages
+ a = append(a, "-fmessage-length=0")
+
// On OS X, some of the compilers behave as if -fno-common
// is always set, and the Mach-O linker in 6l/8l assumes this.
// See http://golang.org/issue/3253.
@@ -1915,8 +2058,28 @@ func (b *builder) gccArchArgs() []string {
return nil
}
-func envList(key string) []string {
- return strings.Fields(os.Getenv(key))
+// envList returns the value of the given environment variable broken
+// into fields, using the default value when the variable is empty.
+func envList(key, def string) []string {
+ v := os.Getenv(key)
+ if v == "" {
+ v = def
+ }
+ return strings.Fields(v)
+}
+
+// Return the flags to use when invoking the C or C++ compilers, or cgo.
+func (b *builder) cflags(p *Package, def bool) (cppflags, cflags, cxxflags, ldflags []string) {
+ var defaults string
+ if def {
+ defaults = "-g -O2"
+ }
+
+ cppflags = stringList(envList("CGO_CPPFLAGS", ""), p.CgoCPPFLAGS)
+ cflags = stringList(envList("CGO_CFLAGS", defaults), p.CgoCFLAGS)
+ cxxflags = stringList(envList("CGO_CXXFLAGS", defaults), p.CgoCXXFLAGS)
+ ldflags = stringList(envList("CGO_LDFLAGS", defaults), p.CgoLDFLAGS)
+ return
}
var cgoRe = regexp.MustCompile(`[/\\:]`)
@@ -1927,15 +2090,14 @@ var (
cgoLibGccFileOnce sync.Once
)
-func (b *builder) cgo(p *Package, cgoExe, obj string, gccfiles []string, gxxfiles []string) (outGo, outObj []string, err error) {
- if goos != toolGOOS {
- return nil, nil, errors.New("cannot use cgo when compiling for a different operating system")
- }
+func (b *builder) cgo(p *Package, cgoExe, obj string, gccfiles, gxxfiles, mfiles []string) (outGo, outObj []string, err error) {
+ cgoCPPFLAGS, cgoCFLAGS, cgoCXXFLAGS, cgoLDFLAGS := b.cflags(p, true)
+ _, cgoexeCFLAGS, _, _ := b.cflags(p, false)
- cgoCPPFLAGS := stringList(envList("CGO_CPPFLAGS"), p.CgoCPPFLAGS)
- cgoCFLAGS := stringList(envList("CGO_CFLAGS"), p.CgoCFLAGS)
- cgoCXXFLAGS := stringList(envList("CGO_CXXFLAGS"), p.CgoCXXFLAGS)
- cgoLDFLAGS := stringList(envList("CGO_LDFLAGS"), p.CgoLDFLAGS)
+ // If we are compiling Objective-C code, then we need to link against libobjc
+ if len(mfiles) > 0 {
+ cgoLDFLAGS = append(cgoLDFLAGS, "-lobjc")
+ }
if pkgs := p.CgoPkgConfig; len(pkgs) > 0 {
out, err := b.runOut(p.Dir, p.ImportPath, nil, "pkg-config", "--cflags", pkgs)
@@ -2001,7 +2163,7 @@ func (b *builder) cgo(p *Package, cgoExe, obj string, gccfiles []string, gxxfile
}
objExt = "o"
}
- if err := b.run(p.Dir, p.ImportPath, cgoenv, cgoExe, "-objdir", obj, cgoflags, "--", cgoCPPFLAGS, cgoCFLAGS, p.CgoFiles); err != nil {
+ if err := b.run(p.Dir, p.ImportPath, cgoenv, cgoExe, "-objdir", obj, cgoflags, "--", cgoCPPFLAGS, cgoexeCFLAGS, p.CgoFiles); err != nil {
return nil, nil, err
}
outGo = append(outGo, gofiles...)
@@ -2088,6 +2250,16 @@ func (b *builder) cgo(p *Package, cgoExe, obj string, gccfiles []string, gxxfile
outObj = append(outObj, ofile)
}
+ for _, file := range mfiles {
+ // Append .o to the file, just in case the pkg has file.c and file.m
+ ofile := obj + cgoRe.ReplaceAllString(file, "_") + ".o"
+ if err := b.gcc(p, ofile, cflags, file); err != nil {
+ return nil, nil, err
+ }
+ linkobj = append(linkobj, ofile)
+ outObj = append(outObj, ofile)
+ }
+
linkobj = append(linkobj, p.SysoFiles...)
dynobj := obj + "_cgo_.o"
if goarch == "arm" && goos == "linux" { // we need to use -pie for Linux/ARM to get accurate imported sym
@@ -2145,24 +2317,39 @@ func (b *builder) cgo(p *Package, cgoExe, obj string, gccfiles []string, gxxfile
// Run SWIG on all SWIG input files.
// TODO: Don't build a shared library, once SWIG emits the necessary
// pragmas for external linking.
-func (b *builder) swig(p *Package, obj string, gccfiles, gxxfiles []string) (outGo, outObj []string, err error) {
+func (b *builder) swig(p *Package, obj string, gccfiles, gxxfiles, mfiles []string) (outGo, outObj []string, err error) {
+ cgoCPPFLAGS, cgoCFLAGS, cgoCXXFLAGS, _ := b.cflags(p, true)
+ cflags := stringList(cgoCPPFLAGS, cgoCFLAGS)
+ cxxflags := stringList(cgoCPPFLAGS, cgoCXXFLAGS)
- var extraObj []string
for _, file := range gccfiles {
ofile := obj + cgoRe.ReplaceAllString(file[:len(file)-1], "_") + "o"
- if err := b.gcc(p, ofile, nil, file); err != nil {
+ if err := b.gcc(p, ofile, cflags, file); err != nil {
return nil, nil, err
}
- extraObj = append(extraObj, ofile)
+ outObj = append(outObj, ofile)
}
for _, file := range gxxfiles {
// Append .o to the file, just in case the pkg has file.c and file.cpp
ofile := obj + cgoRe.ReplaceAllString(file, "_") + ".o"
- if err := b.gxx(p, ofile, nil, file); err != nil {
+ if err := b.gxx(p, ofile, cxxflags, file); err != nil {
return nil, nil, err
}
- extraObj = append(extraObj, ofile)
+ outObj = append(outObj, ofile)
+ }
+
+ for _, file := range mfiles {
+ // Append .o to the file, just in case the pkg has file.c and file.cpp
+ ofile := obj + cgoRe.ReplaceAllString(file, "_") + ".o"
+ if err := b.gcc(p, ofile, cflags, file); err != nil {
+ return nil, nil, err
+ }
+ outObj = append(outObj, ofile)
+ }
+
+ if err := b.swigVersionCheck(); err != nil {
+ return nil, nil, err
}
intgosize, err := b.swigIntSize(obj)
@@ -2171,7 +2358,7 @@ func (b *builder) swig(p *Package, obj string, gccfiles, gxxfiles []string) (out
}
for _, f := range p.SwigFiles {
- goFile, objFile, err := b.swigOne(p, f, obj, false, intgosize, extraObj)
+ goFile, objFile, gccObjFile, err := b.swigOne(p, f, obj, false, intgosize)
if err != nil {
return nil, nil, err
}
@@ -2181,9 +2368,12 @@ func (b *builder) swig(p *Package, obj string, gccfiles, gxxfiles []string) (out
if objFile != "" {
outObj = append(outObj, objFile)
}
+ if gccObjFile != "" {
+ outObj = append(outObj, gccObjFile)
+ }
}
for _, f := range p.SwigCXXFiles {
- goFile, objFile, err := b.swigOne(p, f, obj, true, intgosize, extraObj)
+ goFile, objFile, gccObjFile, err := b.swigOne(p, f, obj, true, intgosize)
if err != nil {
return nil, nil, err
}
@@ -2193,10 +2383,48 @@ func (b *builder) swig(p *Package, obj string, gccfiles, gxxfiles []string) (out
if objFile != "" {
outObj = append(outObj, objFile)
}
+ if gccObjFile != "" {
+ outObj = append(outObj, gccObjFile)
+ }
}
return outGo, outObj, nil
}
+// Make sure SWIG is new enough.
+var (
+ swigCheckOnce sync.Once
+ swigCheck error
+)
+
+func (b *builder) swigDoVersionCheck() error {
+ out, err := b.runOut("", "", nil, "swig", "-version")
+ if err != nil {
+ return err
+ }
+ re := regexp.MustCompile(`[vV]ersion +([\d])`)
+ matches := re.FindSubmatch(out)
+ if matches == nil {
+ // Can't find version number; hope for the best.
+ return nil
+ }
+ major, err := strconv.Atoi(string(matches[1]))
+ if err != nil {
+ // Can't find version number; hope for the best.
+ return nil
+ }
+ if major < 3 {
+ return errors.New("must have SWIG version >= 3.0")
+ }
+ return nil
+}
+
+func (b *builder) swigVersionCheck() error {
+ swigCheckOnce.Do(func() {
+ swigCheck = b.swigDoVersionCheck()
+ })
+ return swigCheck
+}
+
// This code fails to build if sizeof(int) <= 32
const swigIntSizeCode = `
package main
@@ -2217,14 +2445,22 @@ func (b *builder) swigIntSize(obj string) (intsize string, err error) {
p := goFilesPackage(srcs)
- if _, _, e := buildToolchain.gc(b, p, obj, nil, srcs); e != nil {
+ if _, _, e := buildToolchain.gc(b, p, "", obj, nil, srcs); e != nil {
return "32", nil
}
return "64", nil
}
// Run SWIG on one SWIG input file.
-func (b *builder) swigOne(p *Package, file, obj string, cxx bool, intgosize string, extraObj []string) (outGo, outObj string, err error) {
+func (b *builder) swigOne(p *Package, file, obj string, cxx bool, intgosize string) (outGo, outObj, objGccObj string, err error) {
+ cgoCPPFLAGS, cgoCFLAGS, cgoCXXFLAGS, _ := b.cflags(p, true)
+ var cflags []string
+ if cxx {
+ cflags = stringList(cgoCPPFLAGS, cgoCXXFLAGS)
+ } else {
+ cflags = stringList(cgoCPPFLAGS, cgoCFLAGS)
+ }
+
n := 5 // length of ".swig"
if cxx {
n = 8 // length of ".swigcxx"
@@ -2237,7 +2473,6 @@ func (b *builder) swigOne(p *Package, file, obj string, cxx bool, intgosize stri
if cxx {
gccExt = "cxx"
}
- soname := p.swigSoname(file)
_, gccgo := buildToolchain.(gccgoToolchain)
@@ -2246,12 +2481,14 @@ func (b *builder) swigOne(p *Package, file, obj string, cxx bool, intgosize stri
"-go",
"-intgosize", intgosize,
"-module", base,
- "-soname", soname,
"-o", obj + gccBase + gccExt,
"-outdir", obj,
}
if gccgo {
args = append(args, "-gccgo")
+ if pkgpath := gccgoPkgpath(p); pkgpath != "" {
+ args = append(args, "-go-pkgpath", pkgpath)
+ }
}
if cxx {
args = append(args, "-c++")
@@ -2260,12 +2497,12 @@ func (b *builder) swigOne(p *Package, file, obj string, cxx bool, intgosize stri
if out, err := b.runOut(p.Dir, p.ImportPath, nil, "swig", args, file); err != nil {
if len(out) > 0 {
if bytes.Contains(out, []byte("Unrecognized option -intgosize")) {
- return "", "", errors.New("must have SWIG version >= 2.0.9\n")
+ return "", "", "", errors.New("must have SWIG version >= 3.0")
}
b.showOutput(p.Dir, p.ImportPath, b.processOutput(out))
- return "", "", errPrintedOutput
+ return "", "", "", errPrintedOutput
}
- return "", "", err
+ return "", "", "", err
}
var cObj string
@@ -2273,32 +2510,23 @@ func (b *builder) swigOne(p *Package, file, obj string, cxx bool, intgosize stri
// cc
cObj = obj + cBase + archChar
if err := buildToolchain.cc(b, p, obj, cObj, obj+cBase+"c"); err != nil {
- return "", "", err
+ return "", "", "", err
}
}
// gcc
gccObj := obj + gccBase + "o"
- if err := b.gcc(p, gccObj, []string{"-g", "-fPIC", "-O2"}, obj+gccBase+gccExt); err != nil {
- return "", "", err
- }
-
- // create shared library
- osldflags := map[string][]string{
- "darwin": {"-dynamiclib", "-Wl,-undefined,dynamic_lookup"},
- "freebsd": {"-shared", "-lpthread", "-lm"},
- "linux": {"-shared", "-lpthread", "-lm"},
- "windows": {"-shared", "-lm", "-mthreads"},
- }
- var cxxlib []string
- if cxx {
- cxxlib = []string{"-lstdc++"}
+ if !cxx {
+ if err := b.gcc(p, gccObj, cflags, obj+gccBase+gccExt); err != nil {
+ return "", "", "", err
+ }
+ } else {
+ if err := b.gxx(p, gccObj, cflags, obj+gccBase+gccExt); err != nil {
+ return "", "", "", err
+ }
}
- ldflags := stringList(osldflags[goos], cxxlib)
- target := filepath.Join(obj, soname)
- b.run(p.Dir, p.ImportPath, nil, b.gccCmd(p.Dir), "-o", target, gccObj, extraObj, ldflags)
- return obj + goFile, cObj, nil
+ return obj + goFile, cObj, gccObj, nil
}
// An actionQueue is a priority queue of actions.
diff --git a/src/cmd/go/clean.go b/src/cmd/go/clean.go
index 16687f72f..16054a5b5 100644
--- a/src/cmd/go/clean.go
+++ b/src/cmd/go/clean.go
@@ -13,7 +13,7 @@ import (
)
var cmdClean = &Command{
- UsageLine: "clean [-i] [-r] [-n] [-x] [packages]",
+ UsageLine: "clean [-i] [-r] [-n] [-x] [build flags] [packages]",
Short: "remove object files",
Long: `
Clean removes object files from package source directories.
@@ -52,23 +52,26 @@ 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 build flags, see 'go help build'.
+
For more about specifying packages, see 'go help packages'.
`,
}
var cleanI bool // clean -i flag
-var cleanN bool // clean -n flag
var cleanR bool // clean -r flag
-var cleanX bool // clean -x flag
func init() {
// break init cycle
cmdClean.Run = runClean
cmdClean.Flag.BoolVar(&cleanI, "i", false, "")
- cmdClean.Flag.BoolVar(&cleanN, "n", false, "")
cmdClean.Flag.BoolVar(&cleanR, "r", false, "")
- cmdClean.Flag.BoolVar(&cleanX, "x", false, "")
+ // -n and -x are important enough to be
+ // mentioned explicitly in the docs but they
+ // are part of the build flags.
+
+ addBuildFlags(cmdClean)
}
func runClean(cmd *Command, args []string) {
@@ -153,7 +156,7 @@ func clean(p *Package) {
elem+".test.exe",
)
- // Remove a potental executable for each .go file in the directory that
+ // Remove a potential executable for each .go file in the directory that
// is not part of the directory's package.
for _, dir := range dirs {
name := dir.Name()
@@ -169,7 +172,7 @@ func clean(p *Package) {
}
}
- if cleanN || cleanX {
+ if buildN || buildX {
b.showcmd(p.Dir, "rm -f %s", strings.Join(allRemove, " "))
}
@@ -182,9 +185,9 @@ func clean(p *Package) {
if dir.IsDir() {
// TODO: Remove once Makefiles are forgotten.
if cleanDir[name] {
- if cleanN || cleanX {
+ if buildN || buildX {
b.showcmd(p.Dir, "rm -r %s", name)
- if cleanN {
+ if buildN {
continue
}
}
@@ -195,7 +198,7 @@ func clean(p *Package) {
continue
}
- if cleanN {
+ if buildN {
continue
}
@@ -205,28 +208,14 @@ func clean(p *Package) {
}
if cleanI && p.target != "" {
- if cleanN || cleanX {
+ if buildN || buildX {
b.showcmd("", "rm -f %s", p.target)
}
- if !cleanN {
+ if !buildN {
removeFile(p.target)
}
}
- if cleanI && p.usesSwig() {
- for _, f := range stringList(p.SwigFiles, p.SwigCXXFiles) {
- dir := p.swigDir(&buildContext)
- soname := p.swigSoname(f)
- target := filepath.Join(dir, soname)
- if cleanN || cleanX {
- b.showcmd("", "rm -f %s", target)
- }
- if !cleanN {
- removeFile(target)
- }
- }
- }
-
if cleanR {
for _, p1 := range p.imports {
clean(p1)
diff --git a/src/cmd/go/context.go b/src/cmd/go/context.go
new file mode 100644
index 000000000..68e518259
--- /dev/null
+++ b/src/cmd/go/context.go
@@ -0,0 +1,36 @@
+// Copyright 2014 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.
+
+package main
+
+import (
+ "go/build"
+)
+
+type Context struct {
+ GOARCH string `json:",omitempty"` // target architecture
+ GOOS string `json:",omitempty"` // target operating system
+ GOROOT string `json:",omitempty"` // Go root
+ GOPATH string `json:",omitempty"` // Go path
+ CgoEnabled bool `json:",omitempty"` // whether cgo can be used
+ UseAllFiles bool `json:",omitempty"` // use files regardless of +build lines, file names
+ Compiler string `json:",omitempty"` // compiler to assume when computing target paths
+ BuildTags []string `json:",omitempty"` // build constraints to match in +build lines
+ ReleaseTags []string `json:",omitempty"` // releases the current release is compatible with
+ InstallSuffix string `json:",omitempty"` // suffix to use in the name of the install dir
+}
+
+func newContext(c *build.Context) *Context {
+ return &Context{
+ GOARCH: c.GOARCH,
+ GOOS: c.GOOS,
+ GOROOT: c.GOROOT,
+ CgoEnabled: c.CgoEnabled,
+ UseAllFiles: c.UseAllFiles,
+ Compiler: c.Compiler,
+ BuildTags: c.BuildTags,
+ ReleaseTags: c.ReleaseTags,
+ InstallSuffix: c.InstallSuffix,
+ }
+}
diff --git a/src/cmd/go/discovery.go b/src/cmd/go/discovery.go
index 75228b52a..b9f427995 100644
--- a/src/cmd/go/discovery.go
+++ b/src/cmd/go/discovery.go
@@ -43,6 +43,9 @@ func parseMetaGoImports(r io.Reader) (imports []metaImport, err error) {
for {
t, err = d.Token()
if err != nil {
+ if err == io.EOF {
+ err = nil
+ }
return
}
if e, ok := t.(xml.StartElement); ok && strings.EqualFold(e.Name.Local, "body") {
diff --git a/src/cmd/go/doc.go b/src/cmd/go/doc.go
index ebb2f37fd..9840804ce 100644
--- a/src/cmd/go/doc.go
+++ b/src/cmd/go/doc.go
@@ -33,6 +33,7 @@ Use "go help [command]" for more information about a command.
Additional help topics:
c calling between Go and C
+ filetype file types
gopath GOPATH environment variable
importpath import path syntax
packages description of package lists
@@ -46,7 +47,7 @@ Compile packages and dependencies
Usage:
- go build [-o output] [build flags] [packages]
+ go build [-o output] [-i] [build flags] [packages]
Build compiles the packages named by the import paths,
along with their dependencies, but it does not install the results.
@@ -67,7 +68,10 @@ derives from the first file name mentioned, such as f1 for 'go build
f1.go f2.go'; with no files provided ('go build'), the output file
name is the base name of the containing directory.
-The build flags are shared by the build, install, run, and test commands:
+The -i flag installs the packages that are dependencies of the target.
+
+The build flags are shared by the build, clean, get, install, list, run,
+and test commands:
-a
force rebuilding of packages that are already up-to-date.
@@ -104,8 +108,8 @@ The build flags are shared by the build, install, run, and test commands:
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 information about build tags, see the description of
+ build constraints in the documentation for the go/build package.
The list flags accept a space-separated list of strings. To embed spaces
in an element in the list, surround it with either single or double quotes.
@@ -122,7 +126,7 @@ Remove object files
Usage:
- go clean [-i] [-r] [-n] [-x] [packages]
+ go clean [-i] [-r] [-n] [-x] [build flags] [packages]
Clean removes object files from package source directories.
The go command builds most objects in a temporary directory,
@@ -160,6 +164,8 @@ 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 build flags, see 'go help build'.
+
For more about specifying packages, see 'go help packages'.
@@ -235,8 +241,7 @@ 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
missing packages but does not use it to look for updates to existing packages.
-Get also accepts all the flags in the 'go build' and 'go install' commands,
-to control the installation. See 'go help build'.
+Get also accepts build flags to control the installation. See 'go help build'.
When checking out or updating a package, get looks for a branch or tag
that matches the locally installed version of Go. The most important
@@ -271,7 +276,7 @@ List packages
Usage:
- go list [-e] [-race] [-f format] [-json] [-tags 'tag list'] [packages]
+ go list [-e] [-f format] [-json] [build flags] [packages]
List lists the packages named by the import paths, one per line.
@@ -283,8 +288,7 @@ The default output shows the package import path:
The -f flag specifies an alternate format for the list, using the
syntax of package template. The default output is equivalent to -f
-'{{.ImportPath}}'. One extra template function is available, "join",
-which calls strings.Join. The struct being passed to the template is:
+'{{.ImportPath}}'. The struct being passed to the template is:
type Package struct {
Dir string // directory containing package sources
@@ -303,6 +307,7 @@ which calls strings.Join. The struct being passed to the template is:
IgnoredGoFiles []string // .go sources ignored due to build constraints
CFiles []string // .c source files
CXXFiles []string // .cc, .cxx and .cpp source files
+ MFiles []string // .m source files
HFiles []string // .h, .hh, .hpp and .hxx source files
SFiles []string // .s source files
SwigFiles []string // .swig files
@@ -331,6 +336,26 @@ which calls strings.Join. The struct being passed to the template is:
XTestImports []string // imports from XTestGoFiles
}
+The template function "join" calls strings.Join.
+
+The template function "context" returns the build context, defined as:
+
+ type Context struct {
+ GOARCH string // target architecture
+ GOOS string // target operating system
+ GOROOT string // Go root
+ GOPATH string // Go path
+ CgoEnabled bool // whether cgo can be used
+ UseAllFiles bool // use files regardless of +build lines, file names
+ Compiler string // compiler to assume when computing target paths
+ BuildTags []string // build constraints to match in +build lines
+ ReleaseTags []string // releases the current release is compatible with
+ InstallSuffix string // suffix to use in the name of the install dir
+ }
+
+For more information about the meaning of these fields see the documentation
+for the go/build package's Context type.
+
The -json flag causes the package data to be printed in JSON format
instead of using the template format.
@@ -344,11 +369,7 @@ printing. Erroneous packages will have a non-empty ImportPath and
a non-nil Error field; other information may or may not be missing
(zeroed).
-The -tags flag specifies a list of build tags, like in the 'go build'
-command.
-
-The -race flag causes the package data to include the dependencies
-required by the race detector.
+For more about build flags, see 'go help build'.
For more about specifying packages, see 'go help packages'.
@@ -357,11 +378,20 @@ Compile and run Go program
Usage:
- go run [build flags] gofiles... [arguments...]
+ go run [build flags] [-exec xprog] gofiles... [arguments...]
Run compiles and runs the main package comprising the named Go source files.
A Go source file is defined to be a file ending in a literal ".go" suffix.
+By default, 'go run' runs the compiled binary directly: 'a.out arguments...'.
+If the -exec flag is given, 'go run' invokes the binary using xprog: 'xprog a.out arguments...'.
+If the -exec flag is not given, GOOS or GOARCH is different from the system
+default, and a program named go_$GOOS_$GOARCH_exec can be found
+on the current search path, 'go run' invokes the binary using that program,
+for example 'go_nacl_386_exec a.out arguments...'. This allows execution of
+cross-compiled programs when a simulator or other execution method is
+available.
+
For more about build flags, see 'go help build'.
See also: go build.
@@ -408,6 +438,10 @@ In addition to the build flags, the flags handled by 'go test' itself are:
Install packages that are dependencies of the test.
Do not run the test.
+ -exec xprog
+ Run the test binary using xprog. The behavior is the same as
+ in 'go run'. See 'go help run' for details.
+
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.
@@ -478,12 +512,49 @@ http://swig.org/. When running go build, any file with a .swig
extension will be passed to SWIG. Any file with a .swigcxx extension
will be passed to SWIG with the -c++ option.
-When either cgo or SWIG is used, go build will pass any .c, .s, or .S
-files to the C compiler, and any .cc, .cpp, .cxx files to the C++
+When either cgo or SWIG is used, go build will pass any .c, .m, .s,
+or .S files to the C compiler, and any .cc, .cpp, .cxx files to the C++
compiler. The CC or CXX environment variables may be set to determine
the C or C++ compiler, respectively, to use.
+File types
+
+The go command examines the contents of a restricted set of files
+in each directory. It identifies which files to examine based on
+the extension of the file name. These extensions are:
+
+ .go
+ Go source files.
+ .c, .h
+ C source files.
+ If the package uses cgo, these will be compiled with the
+ OS-native compiler (typically gcc); otherwise they will be
+ compiled with the Go-specific support compiler,
+ 5c, 6c, or 8c, etc. as appropriate.
+ .cc, .cpp, .cxx, .hh, .hpp, .hxx
+ C++ source files. Only useful with cgo or SWIG, and always
+ compiled with the OS-native compiler.
+ .m
+ Objective-C source files. Only useful with cgo, and always
+ compiled with the OS-native compiler.
+ .s, .S
+ Assembler source files.
+ If the package uses cgo, these will be assembled with the
+ OS-native assembler (typically gcc (sic)); otherwise they
+ will be assembled with the Go-specific support assembler,
+ 5a, 6a, or 8a, etc., as appropriate.
+ .swig, .swigcxx
+ SWIG definition files.
+ .syso
+ System object files.
+
+Files of each of these types except .syso may contain build
+constraints, but the go command stops scanning for build constraints
+at the first item in the file that is not a blank line or //-style
+line comment.
+
+
GOPATH environment variable
The Go path is used to resolve import statements.
@@ -638,7 +709,7 @@ example.org/user/foo or foo.hg, and
import "example.org/repo.git/foo/bar"
denotes the foo/bar directory of the Git repository at
-example.com/repo or repo.git.
+example.org/repo or repo.git.
When a version control system supports multiple protocols,
each is tried in turn when downloading. For example, a Git
@@ -788,7 +859,8 @@ control the execution of any test:
-covermode set,count,atomic
Set the mode for coverage analysis for the package[s]
- being tested. The default is "set".
+ being tested. The default is "set" unless -race is enabled,
+ in which case it is "atomic".
The values:
set: bool: does this statement run?
count: int: how many times does this statement run?
@@ -823,9 +895,7 @@ control the execution of any test:
Enable more precise (and expensive) memory profiles by setting
runtime.MemProfileRate. See 'godoc runtime MemProfileRate'.
To profile all memory allocations, use -test.memprofilerate=1
- and set the environment variable GOGC=off to disable the
- garbage collector, provided the test can run in the available
- memory without garbage collection.
+ and pass --alloc_space flag to the pprof tool.
-outputdir directory
Place output files from profiling in the specified directory,
diff --git a/src/cmd/go/env.go b/src/cmd/go/env.go
index 2db821797..26d37df4f 100644
--- a/src/cmd/go/env.go
+++ b/src/cmd/go/env.go
@@ -85,18 +85,28 @@ func runEnv(cmd *Command, args []string) {
return
}
- switch runtime.GOOS {
- default:
- for _, e := range env {
- fmt.Printf("%s=\"%s\"\n", e.name, e.value)
- }
- case "plan9":
- for _, e := range env {
- fmt.Printf("%s='%s'\n", e.name, strings.Replace(e.value, "'", "''", -1))
- }
- case "windows":
- for _, e := range env {
- fmt.Printf("set %s=%s\n", e.name, e.value)
+ for _, e := range env {
+ if e.name != "TERM" {
+ switch runtime.GOOS {
+ default:
+ fmt.Printf("%s=\"%s\"\n", e.name, e.value)
+ case "plan9":
+ if strings.IndexByte(e.value, '\x00') < 0 {
+ fmt.Printf("%s='%s'\n", e.name, strings.Replace(e.value, "'", "''", -1))
+ } else {
+ v := strings.Split(e.value, "\x00")
+ fmt.Printf("%s=(", e.name)
+ for x, s := range v {
+ if x > 0 {
+ fmt.Printf(" ")
+ }
+ fmt.Printf("%s", s)
+ }
+ fmt.Printf(")\n")
+ }
+ case "windows":
+ fmt.Printf("set %s=%s\n", e.name, e.value)
+ }
}
}
}
diff --git a/src/cmd/go/get.go b/src/cmd/go/get.go
index e61da7e2a..e708fcf77 100644
--- a/src/cmd/go/get.go
+++ b/src/cmd/go/get.go
@@ -2,8 +2,6 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// TODO: Dashboard upload
-
package main
import (
@@ -37,8 +35,7 @@ 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
missing packages but does not use it to look for updates to existing packages.
-Get also accepts all the flags in the 'go build' and 'go install' commands,
-to control the installation. See 'go help build'.
+Get also accepts build flags to control the installation. See 'go help build'.
When checking out or updating a package, get looks for a branch or tag
that matches the locally installed version of Go. The most important
@@ -73,7 +70,7 @@ func runGet(cmd *Command, args []string) {
}
exitIfErrors()
- // Phase 2. Rescan packages and reevaluate args list.
+ // Phase 2. Rescan packages and re-evaluate args list.
// Code we downloaded and all code that depends on it
// needs to be evicted from the package cache so that
@@ -143,6 +140,10 @@ var downloadRootCache = map[string]bool{}
// for the package named by the argument.
func download(arg string, stk *importStack, getTestDeps bool) {
p := loadPackage(arg, stk)
+ if p.Error != nil && p.Error.hard {
+ errorf("%s", p.Error)
+ return
+ }
// There's nothing to do if this is a package in the standard library.
if p.Standard {
diff --git a/src/cmd/go/help.go b/src/cmd/go/help.go
index 71e55175a..40da7e1f5 100644
--- a/src/cmd/go/help.go
+++ b/src/cmd/go/help.go
@@ -19,8 +19,8 @@ http://swig.org/. When running go build, any file with a .swig
extension will be passed to SWIG. Any file with a .swigcxx extension
will be passed to SWIG with the -c++ option.
-When either cgo or SWIG is used, go build will pass any .c, .s, or .S
-files to the C compiler, and any .cc, .cpp, .cxx files to the C++
+When either cgo or SWIG is used, go build will pass any .c, .m, .s,
+or .S files to the C compiler, and any .cc, .cpp, .cxx files to the C++
compiler. The CC or CXX environment variables may be set to determine
the C or C++ compiler, respectively, to use.
`,
@@ -182,7 +182,7 @@ example.org/user/foo or foo.hg, and
import "example.org/repo.git/foo/bar"
denotes the foo/bar directory of the Git repository at
-example.com/repo or repo.git.
+example.org/repo or repo.git.
When a version control system supports multiple protocols,
each is tried in turn when downloading. For example, a Git
@@ -295,3 +295,43 @@ but new packages are always downloaded into the first directory
in the list.
`,
}
+
+var helpFileType = &Command{
+ UsageLine: "filetype",
+ Short: "file types",
+ Long: `
+The go command examines the contents of a restricted set of files
+in each directory. It identifies which files to examine based on
+the extension of the file name. These extensions are:
+
+ .go
+ Go source files.
+ .c, .h
+ C source files.
+ If the package uses cgo, these will be compiled with the
+ OS-native compiler (typically gcc); otherwise they will be
+ compiled with the Go-specific support compiler,
+ 5c, 6c, or 8c, etc. as appropriate.
+ .cc, .cpp, .cxx, .hh, .hpp, .hxx
+ C++ source files. Only useful with cgo or SWIG, and always
+ compiled with the OS-native compiler.
+ .m
+ Objective-C source files. Only useful with cgo, and always
+ compiled with the OS-native compiler.
+ .s, .S
+ Assembler source files.
+ If the package uses cgo, these will be assembled with the
+ OS-native assembler (typically gcc (sic)); otherwise they
+ will be assembled with the Go-specific support assembler,
+ 5a, 6a, or 8a, etc., as appropriate.
+ .swig, .swigcxx
+ SWIG definition files.
+ .syso
+ System object files.
+
+Files of each of these types except .syso may contain build
+constraints, but the go command stops scanning for build constraints
+at the first item in the file that is not a blank line or //-style
+line comment.
+ `,
+}
diff --git a/src/cmd/go/list.go b/src/cmd/go/list.go
index f56ebed38..0ead43502 100644
--- a/src/cmd/go/list.go
+++ b/src/cmd/go/list.go
@@ -14,7 +14,7 @@ import (
)
var cmdList = &Command{
- UsageLine: "list [-e] [-race] [-f format] [-json] [-tags 'tag list'] [packages]",
+ UsageLine: "list [-e] [-f format] [-json] [build flags] [packages]",
Short: "list packages",
Long: `
List lists the packages named by the import paths, one per line.
@@ -27,8 +27,7 @@ The default output shows the package import path:
The -f flag specifies an alternate format for the list, using the
syntax of package template. The default output is equivalent to -f
-'{{.ImportPath}}'. One extra template function is available, "join",
-which calls strings.Join. The struct being passed to the template is:
+'{{.ImportPath}}'. The struct being passed to the template is:
type Package struct {
Dir string // directory containing package sources
@@ -47,6 +46,7 @@ which calls strings.Join. The struct being passed to the template is:
IgnoredGoFiles []string // .go sources ignored due to build constraints
CFiles []string // .c source files
CXXFiles []string // .cc, .cxx and .cpp source files
+ MFiles []string // .m source files
HFiles []string // .h, .hh, .hpp and .hxx source files
SFiles []string // .s source files
SwigFiles []string // .swig files
@@ -75,6 +75,26 @@ which calls strings.Join. The struct being passed to the template is:
XTestImports []string // imports from XTestGoFiles
}
+The template function "join" calls strings.Join.
+
+The template function "context" returns the build context, defined as:
+
+ type Context struct {
+ GOARCH string // target architecture
+ GOOS string // target operating system
+ GOROOT string // Go root
+ GOPATH string // Go path
+ CgoEnabled bool // whether cgo can be used
+ UseAllFiles bool // use files regardless of +build lines, file names
+ Compiler string // compiler to assume when computing target paths
+ BuildTags []string // build constraints to match in +build lines
+ ReleaseTags []string // releases the current release is compatible with
+ InstallSuffix string // suffix to use in the name of the install dir
+ }
+
+For more information about the meaning of these fields see the documentation
+for the go/build package's Context type.
+
The -json flag causes the package data to be printed in JSON format
instead of using the template format.
@@ -88,11 +108,7 @@ printing. Erroneous packages will have a non-empty ImportPath and
a non-nil Error field; other information may or may not be missing
(zeroed).
-The -tags flag specifies a list of build tags, like in the 'go build'
-command.
-
-The -race flag causes the package data to include the dependencies
-required by the race detector.
+For more about build flags, see 'go help build'.
For more about specifying packages, see 'go help packages'.
`,
@@ -100,24 +116,18 @@ For more about specifying packages, see 'go help packages'.
func init() {
cmdList.Run = runList // break init cycle
- cmdList.Flag.Var(buildCompiler{}, "compiler", "")
- cmdList.Flag.Var((*stringsFlag)(&buildContext.BuildTags), "tags", "")
+ addBuildFlags(cmdList)
}
var listE = cmdList.Flag.Bool("e", false, "")
var listFmt = cmdList.Flag.String("f", "{{.ImportPath}}", "")
var listJson = cmdList.Flag.Bool("json", false, "")
-var listRace = cmdList.Flag.Bool("race", false, "")
var nl = []byte{'\n'}
func runList(cmd *Command, args []string) {
out := newTrackingWriter(os.Stdout)
defer out.w.Flush()
- if *listRace {
- buildRace = true
- }
-
var do func(*Package)
if *listJson {
do = func(p *Package) {
@@ -130,7 +140,18 @@ func runList(cmd *Command, args []string) {
out.Write(nl)
}
} else {
- tmpl, err := template.New("main").Funcs(template.FuncMap{"join": strings.Join}).Parse(*listFmt)
+ var cachedCtxt *Context
+ context := func() *Context {
+ if cachedCtxt == nil {
+ cachedCtxt = newContext(&buildContext)
+ }
+ return cachedCtxt
+ }
+ fm := template.FuncMap{
+ "join": strings.Join,
+ "context": context,
+ }
+ tmpl, err := template.New("main").Funcs(fm).Parse(*listFmt)
if err != nil {
fatalf("%s", err)
}
@@ -140,7 +161,7 @@ func runList(cmd *Command, args []string) {
fatalf("%s", err)
}
if out.NeedNL() {
- out.Write([]byte{'\n'})
+ out.Write(nl)
}
}
}
diff --git a/src/cmd/go/main.go b/src/cmd/go/main.go
index df0cf1b3f..5b1194aaa 100644
--- a/src/cmd/go/main.go
+++ b/src/cmd/go/main.go
@@ -89,6 +89,7 @@ var commands = []*Command{
cmdVet,
helpC,
+ helpFileType,
helpGopath,
helpImportPath,
helpPackages,
@@ -238,6 +239,11 @@ func printUsage(w io.Writer) {
}
func usage() {
+ // special case "go test -h"
+ if len(os.Args) > 1 && os.Args[1] == "test" {
+ help([]string{"testflag"})
+ os.Exit(2)
+ }
printUsage(os.Stderr)
os.Exit(2)
}
diff --git a/src/cmd/go/pkg.go b/src/cmd/go/pkg.go
index 71f14c74a..d45df265b 100644
--- a/src/cmd/go/pkg.go
+++ b/src/cmd/go/pkg.go
@@ -42,6 +42,7 @@ type Package struct {
IgnoredGoFiles []string `json:",omitempty"` // .go sources ignored due to build constraints
CFiles []string `json:",omitempty"` // .c source files
CXXFiles []string `json:",omitempty"` // .cc, .cpp and .cxx source files
+ MFiles []string `json:",omitempty"` // .m source files
HFiles []string `json:",omitempty"` // .h, .hh, .hpp and .hxx source files
SFiles []string `json:",omitempty"` // .s source files
SwigFiles []string `json:",omitempty"` // .swig files
@@ -88,6 +89,7 @@ type Package struct {
exeName string // desired name for temporary executable
coverMode string // preprocess Go source files with the coverage tool in this mode
coverVars map[string]*CoverVar // variables created by coverage analysis
+ omitDWARF bool // tell linker not to write DWARF information
}
// CoverVar holds the name of the generated coverage variables targeting the named file.
@@ -113,6 +115,7 @@ func (p *Package) copyBuild(pp *build.Package) {
p.IgnoredGoFiles = pp.IgnoredGoFiles
p.CFiles = pp.CFiles
p.CXXFiles = pp.CXXFiles
+ p.MFiles = pp.MFiles
p.HFiles = pp.HFiles
p.SFiles = pp.SFiles
p.SwigFiles = pp.SwigFiles
@@ -136,12 +139,13 @@ type PackageError struct {
Pos string // position of error
Err string // the error itself
isImportCycle bool // the error is an import cycle
+ hard bool // whether the error is soft or hard; soft errors are ignored in some places
}
func (p *PackageError) Error() string {
// Import cycles deserve special treatment.
if p.isImportCycle {
- return fmt.Sprintf("%s: %s\npackage %s\n", p.Pos, p.Err, strings.Join(p.ImportStack, "\n\timports "))
+ return fmt.Sprintf("%s\npackage %s\n", p.Err, strings.Join(p.ImportStack, "\n\timports "))
}
if p.Pos != "" {
// Omit import stack. The full path to the file where the error
@@ -304,9 +308,14 @@ const (
// goTools is a map of Go program import path to install target directory.
var goTools = map[string]targetDir{
+ "cmd/addr2line": toTool,
"cmd/api": toTool,
"cmd/cgo": toTool,
"cmd/fix": toTool,
+ "cmd/link": toTool,
+ "cmd/nm": toTool,
+ "cmd/objdump": toTool,
+ "cmd/pack": toTool,
"cmd/yacc": toTool,
"code.google.com/p/go.tools/cmd/cover": toTool,
"code.google.com/p/go.tools/cmd/godoc": toBin,
@@ -454,6 +463,7 @@ func (p *Package) load(stk *importStack, bp *build.Package, err error) *Package
p.IgnoredGoFiles,
p.CFiles,
p.CXXFiles,
+ p.MFiles,
p.HFiles,
p.SFiles,
p.SysoFiles,
@@ -551,24 +561,6 @@ func (p *Package) usesCgo() bool {
return len(p.CgoFiles) > 0
}
-// swigSoname returns the name of the shared library we create for a
-// SWIG input file.
-func (p *Package) swigSoname(file string) string {
- return strings.Replace(p.ImportPath, "/", "-", -1) + "-" + strings.Replace(file, ".", "-", -1) + ".so"
-}
-
-// swigDir returns the name of the shared SWIG directory for a
-// package.
-func (p *Package) swigDir(ctxt *build.Context) string {
- dir := p.build.PkgRoot
- if ctxt.Compiler == "gccgo" {
- dir = filepath.Join(dir, "gccgo_"+ctxt.GOOS+"_"+ctxt.GOARCH)
- } else {
- dir = filepath.Join(dir, ctxt.GOOS+"_"+ctxt.GOARCH)
- }
- return filepath.Join(dir, "swig")
-}
-
// 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 {
@@ -681,7 +673,7 @@ func isStale(p *Package, topRoot map[string]bool) bool {
return false
}
- srcs := stringList(p.GoFiles, p.CFiles, p.CXXFiles, p.HFiles, p.SFiles, p.CgoFiles, p.SysoFiles, p.SwigFiles, p.SwigCXXFiles)
+ srcs := stringList(p.GoFiles, p.CFiles, p.CXXFiles, p.MFiles, p.HFiles, p.SFiles, p.CgoFiles, p.SysoFiles, p.SwigFiles, p.SwigCXXFiles)
for _, src := range srcs {
if olderThan(filepath.Join(p.Dir, src)) {
return true
@@ -724,6 +716,7 @@ func loadPackage(arg string, stk *importStack) *Package {
Error: &PackageError{
ImportStack: stk.copy(),
Err: fmt.Sprintf("invalid import path: cmd/... is reserved for Go commands"),
+ hard: true,
},
}
return p
diff --git a/src/cmd/go/pkg_test.go b/src/cmd/go/pkg_test.go
new file mode 100644
index 000000000..06b9f0ac6
--- /dev/null
+++ b/src/cmd/go/pkg_test.go
@@ -0,0 +1,73 @@
+// Copyright 2014 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.
+
+package main
+
+import (
+ "reflect"
+ "strings"
+ "testing"
+)
+
+var foldDupTests = []struct {
+ list []string
+ f1, f2 string
+}{
+ {stringList("math/rand", "math/big"), "", ""},
+ {stringList("math", "strings"), "", ""},
+ {stringList("strings"), "", ""},
+ {stringList("strings", "strings"), "strings", "strings"},
+ {stringList("Rand", "rand", "math", "math/rand", "math/Rand"), "Rand", "rand"},
+}
+
+func TestFoldDup(t *testing.T) {
+ for _, tt := range foldDupTests {
+ f1, f2 := foldDup(tt.list)
+ if f1 != tt.f1 || f2 != tt.f2 {
+ t.Errorf("foldDup(%q) = %q, %q, want %q, %q", tt.list, f1, f2, tt.f1, tt.f2)
+ }
+ }
+}
+
+var parseMetaGoImportsTests = []struct {
+ in string
+ out []metaImport
+}{
+ {
+ `<meta name="go-import" content="foo/bar git https://github.com/rsc/foo/bar">`,
+ []metaImport{{"foo/bar", "git", "https://github.com/rsc/foo/bar"}},
+ },
+ {
+ `<meta name="go-import" content="foo/bar git https://github.com/rsc/foo/bar">
+ <meta name="go-import" content="baz/quux git http://github.com/rsc/baz/quux">`,
+ []metaImport{
+ {"foo/bar", "git", "https://github.com/rsc/foo/bar"},
+ {"baz/quux", "git", "http://github.com/rsc/baz/quux"},
+ },
+ },
+ {
+ `<head>
+ <meta name="go-import" content="foo/bar git https://github.com/rsc/foo/bar">
+ </head>`,
+ []metaImport{{"foo/bar", "git", "https://github.com/rsc/foo/bar"}},
+ },
+ {
+ `<meta name="go-import" content="foo/bar git https://github.com/rsc/foo/bar">
+ <body>`,
+ []metaImport{{"foo/bar", "git", "https://github.com/rsc/foo/bar"}},
+ },
+}
+
+func TestParseMetaGoImports(t *testing.T) {
+ for i, tt := range parseMetaGoImportsTests {
+ out, err := parseMetaGoImports(strings.NewReader(tt.in))
+ if err != nil {
+ t.Errorf("test#%d: %v", i, err)
+ continue
+ }
+ if !reflect.DeepEqual(out, tt.out) {
+ t.Errorf("test#%d:\n\thave %q\n\twant %q", i, out, tt.out)
+ }
+ }
+}
diff --git a/src/cmd/go/run.go b/src/cmd/go/run.go
index e6dadd229..ef8aa95a3 100644
--- a/src/cmd/go/run.go
+++ b/src/cmd/go/run.go
@@ -8,16 +8,43 @@ import (
"fmt"
"os"
"os/exec"
+ "runtime"
"strings"
)
+var execCmd []string // -exec flag, for run and test
+
+func findExecCmd() []string {
+ if execCmd != nil {
+ return execCmd
+ }
+ execCmd = []string{} // avoid work the second time
+ if goos == runtime.GOOS && goarch == runtime.GOARCH {
+ return execCmd
+ }
+ path, err := exec.LookPath(fmt.Sprintf("go_%s_%s_exec", goos, goarch))
+ if err == nil {
+ execCmd = []string{path}
+ }
+ return execCmd
+}
+
var cmdRun = &Command{
- UsageLine: "run [build flags] gofiles... [arguments...]",
+ UsageLine: "run [build flags] [-exec xprog] gofiles... [arguments...]",
Short: "compile and run Go program",
Long: `
Run compiles and runs the main package comprising the named Go source files.
A Go source file is defined to be a file ending in a literal ".go" suffix.
+By default, 'go run' runs the compiled binary directly: 'a.out arguments...'.
+If the -exec flag is given, 'go run' invokes the binary using xprog: 'xprog a.out arguments...'.
+If the -exec flag is not given, GOOS or GOARCH is different from the system
+default, and a program named go_$GOOS_$GOARCH_exec can be found
+on the current search path, 'go run' invokes the binary using that program,
+for example 'go_nacl_386_exec a.out arguments...'. This allows execution of
+cross-compiled programs when a simulator or other execution method is
+available.
+
For more about build flags, see 'go help build'.
See also: go build.
@@ -28,6 +55,7 @@ func init() {
cmdRun.Run = runRun // break init loop
addBuildFlags(cmdRun)
+ cmdRun.Flag.Var((*stringsFlag)(&execCmd), "exec", "")
}
func printStderr(args ...interface{}) (int, error) {
@@ -58,6 +86,7 @@ func runRun(cmd *Command, args []string) {
if p.Error != nil {
fatalf("%s", p.Error)
}
+ p.omitDWARF = true
for _, err := range p.DepsErrors {
errorf("%s", err)
}
@@ -89,20 +118,20 @@ func runRun(cmd *Command, args []string) {
// runProgram is the action for running a binary that has already
// been compiled. We ignore exit status.
func (b *builder) runProgram(a *action) error {
+ cmdline := stringList(findExecCmd(), a.deps[0].target, a.args)
if buildN || buildX {
- b.showcmd("", "%s %s", a.deps[0].target, strings.Join(a.args, " "))
+ b.showcmd("", "%s", strings.Join(cmdline, " "))
if buildN {
return nil
}
}
- runStdin(a.deps[0].target, a.args)
+ runStdin(cmdline)
return nil
}
// runStdin is like run, but connects Stdin.
-func runStdin(cmdargs ...interface{}) {
- cmdline := stringList(cmdargs...)
+func runStdin(cmdline []string) {
cmd := exec.Command(cmdline[0], cmdline[1:]...)
cmd.Stdin = os.Stdin
cmd.Stdout = os.Stdout
diff --git a/src/cmd/go/signal_unix.go b/src/cmd/go/signal_unix.go
index 00c71657f..e86cd4652 100644
--- a/src/cmd/go/signal_unix.go
+++ b/src/cmd/go/signal_unix.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin dragonfly freebsd linux netbsd openbsd
+// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris
package main
diff --git a/src/cmd/go/test.bash b/src/cmd/go/test.bash
index f71d67818..0060ce218 100755
--- a/src/cmd/go/test.bash
+++ b/src/cmd/go/test.bash
@@ -36,8 +36,9 @@ stop() {
ok=true
allok=true
-unset GOPATH
unset GOBIN
+unset GOPATH
+unset GOROOT
TEST 'file:line in error messages'
# Test that error messages have file:line information at beginning of
@@ -258,6 +259,7 @@ if [ ! -x $d/gobin/godoc ]; then
fi
TEST godoc installs into GOROOT
+GOROOT=$(./testgo env GOROOT)
rm -f $GOROOT/bin/godoc
./testgo install code.google.com/p/go.tools/cmd/godoc
if [ ! -x $GOROOT/bin/godoc ]; then
@@ -425,10 +427,10 @@ d=$(TMPDIR=$tmp mktemp -d -t testgoXXX)
mkdir -p $d/src
(
ln -s $d $d/src/dir1
- cd $d/src/dir1
- echo package p >p.go
+ cd $d/src
+ echo package p >dir1/p.go
export GOPATH=$d
- if [ "$($old/testgo list -f '{{.Root}}' .)" != "$d" ]; then
+ if [ "$($old/testgo list -f '{{.Root}}' dir1)" != "$d" ]; then
echo Confused by symlinks.
echo "Package in current directory $(pwd) should have Root $d"
env|grep WD
@@ -477,14 +479,20 @@ rm -rf $d
TEST case collisions '(issue 4773)'
d=$(TMPDIR=/var/tmp mktemp -d -t testgoXXX)
export GOPATH=$d
-mkdir -p $d/src/example/a $d/src/example/b
+mkdir -p $d/src/example/{a/pkg,a/Pkg,b}
cat >$d/src/example/a/a.go <<EOF
package p
import (
- _ "math/rand"
- _ "math/Rand"
+ _ "example/a/pkg"
+ _ "example/a/Pkg"
)
EOF
+cat >$d/src/example/a/pkg/pkg.go <<EOF
+package pkg
+EOF
+cat >$d/src/example/a/Pkg/pkg.go <<EOF
+package pkg
+EOF
if ./testgo list example/a 2>$d/out; then
echo go list example/a should have failed, did not.
ok=false
@@ -545,7 +553,7 @@ fi
# The error for go install should mention the conflicting directory.
err=$(! ./testgo install ./testdata/shadow/root2/src/foo 2>&1)
-if [ "$err" != "go install: no install location for directory $(pwd)/testdata/shadow/root2/src/foo hidden by $(pwd)/testdata/shadow/root1/src/foo" ]; then
+if [ "$err" != "go install: no install location for $(pwd)/testdata/shadow/root2/src/foo: hidden by $(pwd)/testdata/shadow/root1/src/foo" ]; then
echo wrong shadowed install error: "$err"
ok=false
fi
@@ -555,10 +563,59 @@ TEST source file name order preserved
./testgo test testdata/example[12]_test.go || ok=false
# Check that coverage analysis works at all.
-# Don't worry about the exact numbers
+# Don't worry about the exact numbers but require not 0.0%.
+checkcoverage() {
+ if grep '[^0-9]0\.0%' testdata/cover.txt >/dev/null; then
+ echo 'some coverage results are 0.0%'
+ ok=false
+ fi
+ cat testdata/cover.txt
+ rm -f testdata/cover.txt
+}
+
TEST coverage runs
-./testgo test -short -coverpkg=strings strings regexp || ok=false
-./testgo test -short -cover strings math regexp || ok=false
+./testgo test -short -coverpkg=strings strings regexp >testdata/cover.txt 2>&1 || ok=false
+./testgo test -short -cover strings math regexp >>testdata/cover.txt 2>&1 || ok=false
+checkcoverage
+
+# Check that coverage analysis uses set mode.
+TEST coverage uses set mode
+if ./testgo test -short -cover encoding/binary -coverprofile=testdata/cover.out >testdata/cover.txt 2>&1; then
+ if ! grep -q 'mode: set' testdata/cover.out; then
+ ok=false
+ fi
+ checkcoverage
+else
+ ok=false
+fi
+rm -f testdata/cover.out testdata/cover.txt
+
+TEST coverage uses atomic mode for -race.
+if ./testgo test -short -race -cover encoding/binary -coverprofile=testdata/cover.out >testdata/cover.txt 2>&1; then
+ if ! grep -q 'mode: atomic' testdata/cover.out; then
+ ok=false
+ fi
+ checkcoverage
+else
+ ok=false
+fi
+rm -f testdata/cover.out
+
+TEST coverage uses actual setting to override even for -race.
+if ./testgo test -short -race -cover encoding/binary -covermode=count -coverprofile=testdata/cover.out >testdata/cover.txt 2>&1; then
+ if ! grep -q 'mode: count' testdata/cover.out; then
+ ok=false
+ fi
+ checkcoverage
+else
+ ok=false
+fi
+rm -f testdata/cover.out
+
+TEST coverage with cgo
+d=$(TMPDIR=/var/tmp mktemp -d -t testgoXXX)
+./testgo test -short -cover ./testdata/cgocover >testdata/cover.txt 2>&1 || ok=false
+checkcoverage
TEST cgo depends on syscall
rm -rf $GOROOT/pkg/*_race
@@ -600,7 +657,7 @@ export GOPATH=$d
mkdir -p $d/src/origin
echo '
package origin
-// #cgo LDFLAGS: -Wl,-rpath -Wl,$ORIGIN
+// #cgo !darwin LDFLAGS: -Wl,-rpath -Wl,$ORIGIN
// void f(void) {}
import "C"
@@ -620,6 +677,136 @@ if ! ./testgo test -c -test.bench=XXX fmt; then
fi
rm -f fmt.test
+TEST 'Issue 7573: cmd/cgo: undefined reference when linking a C-library using gccgo'
+d=$(mktemp -d -t testgoXXX)
+export GOPATH=$d
+mkdir -p $d/src/cgoref
+ldflags="-L alibpath -lalib"
+echo "
+package main
+// #cgo LDFLAGS: $ldflags
+// void f(void) {}
+import \"C\"
+
+func main() { C.f() }
+" >$d/src/cgoref/cgoref.go
+go_cmds="$(./testgo build -n -compiler gccgo cgoref 2>&1 1>/dev/null)"
+ldflags_count="$(echo "$go_cmds" | egrep -c "^gccgo.*$(echo $ldflags | sed -e 's/-/\\-/g')" || true)"
+if [ "$ldflags_count" -lt 1 ]; then
+ echo "No Go-inline "#cgo LDFLAGS:" (\"$ldflags\") passed to gccgo linking stage."
+ ok=false
+fi
+rm -rf $d
+unset ldflags_count
+unset go_cmds
+unset ldflags
+unset GOPATH
+
+TEST list template can use context function
+if ! ./testgo list -f "GOARCH: {{context.GOARCH}}"; then
+ echo unable to use context in list template
+ ok=false
+fi
+
+TEST 'Issue 7108: cmd/go: "go test" should fail if package does not build'
+export GOPATH=$(pwd)/testdata
+if ./testgo test notest >/dev/null 2>&1; then
+ echo 'go test notest succeeded, but should fail'
+ ok=false
+fi
+unset GOPATH
+
+TEST 'Issue 6844: cmd/go: go test -a foo does not rebuild regexp'
+if ! ./testgo test -x -a -c testdata/dep_test.go 2>deplist; then
+ echo "go test -x -a -c testdata/dep_test.go failed"
+ ok=false
+elif ! grep -q regexp deplist; then
+ echo "go test -x -a -c testdata/dep_test.go did not rebuild regexp"
+ ok=false
+fi
+rm -f deplist
+rm -f deps.test
+
+TEST list template can use context function
+if ! ./testgo list -f "GOARCH: {{context.GOARCH}}"; then
+ echo unable to use context in list template
+ ok=false
+fi
+
+TEST build -i installs dependencies
+d=$(TMPDIR=/var/tmp mktemp -d -t testgoXXX)
+export GOPATH=$d
+mkdir -p $d/src/x/y/foo $d/src/x/y/bar
+echo '
+package foo
+func F() {}
+' >$d/src/x/y/foo/foo.go
+echo '
+package bar
+import "x/y/foo"
+func F() { foo.F() }
+' >$d/src/x/y/bar/bar.go
+if ! ./testgo build -v -i x/y/bar &> $d/err; then
+ echo build -i failed
+ cat $d/err
+ ok=false
+elif ! grep x/y/foo $d/err >/dev/null; then
+ echo first build -i did not build x/y/foo
+ cat $d/err
+ ok=false
+fi
+if ! ./testgo build -v -i x/y/bar &> $d/err; then
+ echo second build -i failed
+ cat $d/err
+ ok=false
+elif grep x/y/foo $d/err >/dev/null; then
+ echo second build -i built x/y/foo
+ cat $d/err
+ ok=false
+fi
+rm -rf $d
+unset GOPATH
+
+TEST 'go build in test-only directory fails with a good error'
+if ./testgo build ./testdata/testonly 2>testdata/err.out; then
+ echo "go build ./testdata/testonly succeeded, should have failed"
+ ok=false
+elif ! grep 'no buildable Go' testdata/err.out >/dev/null; then
+ echo "go build ./testdata/testonly produced unexpected error:"
+ cat testdata/err.out
+ ok=false
+fi
+rm -f testdata/err.out
+
+TEST 'go test detects test-only import cycles'
+export GOPATH=$(pwd)/testdata
+if ./testgo test -c testcycle/p3 2>testdata/err.out; then
+ echo "go test testcycle/p3 succeeded, should have failed"
+ ok=false
+elif ! grep 'import cycle not allowed in test' testdata/err.out >/dev/null; then
+ echo "go test testcycle/p3 produced unexpected error:"
+ cat testdata/err.out
+ ok=false
+fi
+rm -f testdata/err.out
+unset GOPATH
+
+TEST 'go test foo_test.go works'
+if ! ./testgo test testdata/standalone_test.go; then
+ echo "go test testdata/standalone_test.go failed"
+ ok=false
+fi
+
+TEST 'go test xtestonly works'
+export GOPATH=$(pwd)/testdata
+./testgo clean -i xtestonly
+if ! ./testgo test xtestonly >/dev/null; then
+ echo "go test xtestonly failed"
+ ok=false
+fi
+unset GOPATH
+
+
# clean up
if $started; then stop; fi
rm -rf testdata/bin testdata/bin1
diff --git a/src/cmd/go/test.go b/src/cmd/go/test.go
index 06ac9d206..5935c98db 100644
--- a/src/cmd/go/test.go
+++ b/src/cmd/go/test.go
@@ -72,6 +72,10 @@ In addition to the build flags, the flags handled by 'go test' itself are:
Install packages that are dependencies of the test.
Do not run the test.
+ -exec xprog
+ Run the test binary using xprog. The behavior is the same as
+ in 'go run'. See 'go help run' for details.
+
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.
@@ -133,7 +137,8 @@ control the execution of any test:
-covermode set,count,atomic
Set the mode for coverage analysis for the package[s]
- being tested. The default is "set".
+ being tested. The default is "set" unless -race is enabled,
+ in which case it is "atomic".
The values:
set: bool: does this statement run?
count: int: how many times does this statement run?
@@ -168,9 +173,7 @@ control the execution of any test:
Enable more precise (and expensive) memory profiles by setting
runtime.MemProfileRate. See 'godoc runtime MemProfileRate'.
To profile all memory allocations, use -test.memprofilerate=1
- and set the environment variable GOGC=off to disable the
- garbage collector, provided the test can run in the available
- memory without garbage collection.
+ and pass --alloc_space flag to the pprof tool.
-outputdir directory
Place output files from profiling in the specified directory,
@@ -273,7 +276,6 @@ var (
testCoverPkgs []*Package // -coverpkg flag
testProfile bool // some profiling flag
testNeedBinary bool // profile needs to keep binary around
- testI bool // -i flag
testV bool // -v flag
testFiles []string // -file flag(s) TODO: not respected
testTimeout string // -timeout flag
@@ -295,6 +297,8 @@ func runTest(cmd *Command, args []string) {
var pkgArgs []string
pkgArgs, testArgs = testFlags(args)
+ findExecCmd() // initialize cached result
+
raceInit()
pkgs := packagesForBuild(pkgArgs)
if len(pkgs) == 0 {
@@ -334,7 +338,7 @@ func runTest(cmd *Command, args []string) {
var b builder
b.init()
- if testI {
+ if buildI {
buildV = testV
deps := make(map[string]bool)
@@ -411,7 +415,11 @@ func runTest(cmd *Command, args []string) {
p.Stale = true // rebuild
p.fake = true // do not warn about rebuild
p.coverMode = testCoverMode
- p.coverVars = declareCoverVars(p.ImportPath, p.GoFiles...)
+ var coverFiles []string
+ coverFiles = append(coverFiles, p.GoFiles...)
+ coverFiles = append(coverFiles, p.CgoFiles...)
+ coverFiles = append(coverFiles, p.TestGoFiles...)
+ p.coverVars = declareCoverVars(p.ImportPath, coverFiles...)
}
}
@@ -516,7 +524,7 @@ func contains(x []string, s string) bool {
func (b *builder) test(p *Package) (buildAction, runAction, printAction *action, err error) {
if len(p.TestGoFiles)+len(p.XTestGoFiles) == 0 {
- build := &action{p: p}
+ build := b.action(modeBuild, modeBuild, p)
run := &action{p: p, deps: []*action{build}}
print := &action{f: (*builder).notest, p: p, deps: []*action{run}}
return build, run, print, nil
@@ -530,16 +538,31 @@ func (b *builder) test(p *Package) (buildAction, runAction, printAction *action,
var imports, ximports []*Package
var stk importStack
- stk.push(p.ImportPath + "_test")
+ stk.push(p.ImportPath + " (test)")
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
}
+ if contains(p1.Deps, p.ImportPath) {
+ // Same error that loadPackage returns (via reusePackage) in pkg.go.
+ // Can't change that code, because that code is only for loading the
+ // non-test copy of a package.
+ err := &PackageError{
+ ImportStack: testImportStack(stk[0], p1, p.ImportPath),
+ Err: "import cycle not allowed in test",
+ isImportCycle: true,
+ }
+ return nil, nil, nil, err
+ }
imports = append(imports, p1)
}
+ stk.pop()
+ stk.push(p.ImportPath + "_test")
+ pxtestNeedsPtest := false
for _, path := range p.XTestImports {
if path == p.ImportPath {
+ pxtestNeedsPtest = true
continue
}
p1 := loadImport(path, p.Dir, &stk, p.build.XTestImportPos[path])
@@ -618,7 +641,10 @@ func (b *builder) test(p *Package) (buildAction, runAction, printAction *action,
if localCover {
ptest.coverMode = testCoverMode
- ptest.coverVars = declareCoverVars(ptest.ImportPath, ptest.GoFiles...)
+ var coverFiles []string
+ coverFiles = append(coverFiles, ptest.GoFiles...)
+ coverFiles = append(coverFiles, ptest.CgoFiles...)
+ ptest.coverVars = declareCoverVars(ptest.ImportPath, coverFiles...)
}
} else {
ptest = p
@@ -637,11 +663,14 @@ func (b *builder) test(p *Package) (buildAction, runAction, printAction *action,
build: &build.Package{
ImportPos: p.build.XTestImportPos,
},
- imports: append(ximports, ptest),
+ imports: ximports,
pkgdir: testDir,
fake: true,
Stale: true,
}
+ if pxtestNeedsPtest {
+ pxtest.imports = append(pxtest.imports, ptest)
+ }
}
// Action for building pkg.test.
@@ -651,21 +680,20 @@ func (b *builder) test(p *Package) (buildAction, runAction, printAction *action,
GoFiles: []string{"_testmain.go"},
ImportPath: "testmain",
Root: p.Root,
- imports: []*Package{ptest},
build: &build.Package{Name: "main"},
pkgdir: testDir,
fake: true,
Stale: true,
- }
- if pxtest != nil {
- pmain.imports = append(pmain.imports, pxtest)
+ omitDWARF: !testC && !testNeedBinary,
}
// The generated main also imports testing and regexp.
stk.push("testmain")
for dep := range testMainDeps {
- if ptest.ImportPath != dep {
- p1 := loadImport("testing", "", &stk, nil)
+ if dep == ptest.ImportPath {
+ pmain.imports = append(pmain.imports, ptest)
+ } else {
+ p1 := loadImport(dep, "", &stk, nil)
if p1.Error != nil {
return nil, nil, nil, p1.Error
}
@@ -687,6 +715,21 @@ func (b *builder) test(p *Package) (buildAction, runAction, printAction *action,
}
}
+ // Do initial scan for metadata needed for writing _testmain.go
+ // Use that metadata to update the list of imports for package main.
+ // The list of imports is used by recompileForTest and by the loop
+ // afterward that gathers t.Cover information.
+ t, err := loadTestFuncs(ptest)
+ if err != nil {
+ return nil, nil, nil, err
+ }
+ if t.NeedTest || ptest.coverMode != "" {
+ pmain.imports = append(pmain.imports, ptest)
+ }
+ if t.NeedXtest {
+ pmain.imports = append(pmain.imports, pxtest)
+ }
+
if ptest != p && localCover {
// We have made modifications to the package p being tested
// and are rebuilding p (as ptest), writing it to the testDir tree.
@@ -703,7 +746,15 @@ func (b *builder) test(p *Package) (buildAction, runAction, printAction *action,
recompileForTest(pmain, p, ptest, testDir)
}
- if err := writeTestmain(filepath.Join(testDir, "_testmain.go"), pmain, ptest); err != nil {
+ for _, cp := range pmain.imports {
+ if len(cp.coverVars) > 0 {
+ t.Cover = append(t.Cover, coverInfo{cp, cp.coverVars})
+ }
+ }
+
+ // writeTestmain writes _testmain.go. This must happen after recompileForTest,
+ // because recompileForTest modifies XXX.
+ if err := writeTestmain(filepath.Join(testDir, "_testmain.go"), t); err != nil {
return nil, nil, nil, err
}
@@ -711,7 +762,7 @@ func (b *builder) test(p *Package) (buildAction, runAction, printAction *action,
if ptest != p {
a := b.action(modeBuild, modeBuild, ptest)
- a.objdir = testDir + string(filepath.Separator)
+ a.objdir = testDir + string(filepath.Separator) + "_obj_test" + string(filepath.Separator)
a.objpkg = ptestObj
a.target = ptestObj
a.link = false
@@ -719,7 +770,7 @@ func (b *builder) test(p *Package) (buildAction, runAction, printAction *action,
if pxtest != nil {
a := b.action(modeBuild, modeBuild, pxtest)
- a.objdir = testDir + string(filepath.Separator)
+ a.objdir = testDir + string(filepath.Separator) + "_obj_xtest" + string(filepath.Separator)
a.objpkg = buildToolchain.pkgpath(testDir, pxtest)
a.target = a.objpkg
}
@@ -765,6 +816,24 @@ func (b *builder) test(p *Package) (buildAction, runAction, printAction *action,
return pmainAction, runAction, printAction, nil
}
+func testImportStack(top string, p *Package, target string) []string {
+ stk := []string{top, p.ImportPath}
+Search:
+ for p.ImportPath != target {
+ for _, p1 := range p.imports {
+ if p1.ImportPath == target || contains(p1.Deps, target) {
+ stk = append(stk, p1.ImportPath)
+ p = p1
+ continue Search
+ }
+ }
+ // Can't happen, but in case it does...
+ stk = append(stk, "<lost path to cycle>")
+ break
+ }
+ return stk
+}
+
func recompileForTest(pmain, preal, ptest *Package, testDir string) {
// The "test copy" of preal is ptest.
// For each package that depends on preal, make a "test copy"
@@ -836,7 +905,7 @@ func declareCoverVars(importPath string, files ...string) map[string]*CoverVar {
// runTest is the action for running a test binary.
func (b *builder) runTest(a *action) error {
- args := stringList(a.deps[0].target, testArgs)
+ args := stringList(findExecCmd(), a.deps[0].target, testArgs)
a.testOutput = new(bytes.Buffer)
if buildN || buildX {
@@ -1007,31 +1076,26 @@ type coverInfo struct {
Vars map[string]*CoverVar
}
-// writeTestmain writes the _testmain.go file for package p to
-// the file named out.
-func writeTestmain(out string, pmain, p *Package) error {
- var cover []coverInfo
- for _, cp := range pmain.imports {
- if len(cp.coverVars) > 0 {
- cover = append(cover, coverInfo{cp, cp.coverVars})
- }
- }
-
+// loadTestFuncs returns the testFuncs describing the tests that will be run.
+func loadTestFuncs(ptest *Package) (*testFuncs, error) {
t := &testFuncs{
- Package: p,
- Cover: cover,
+ Package: ptest,
}
- for _, file := range p.TestGoFiles {
- if err := t.load(filepath.Join(p.Dir, file), "_test", &t.NeedTest); err != nil {
- return err
+ for _, file := range ptest.TestGoFiles {
+ if err := t.load(filepath.Join(ptest.Dir, file), "_test", &t.NeedTest); err != nil {
+ return nil, err
}
}
- for _, file := range p.XTestGoFiles {
- if err := t.load(filepath.Join(p.Dir, file), "_xtest", &t.NeedXtest); err != nil {
- return err
+ for _, file := range ptest.XTestGoFiles {
+ if err := t.load(filepath.Join(ptest.Dir, file), "_xtest", &t.NeedXtest); err != nil {
+ return nil, err
}
}
+ return t, nil
+}
+// writeTestmain writes the _testmain.go file for t to the file named out.
+func writeTestmain(out string, t *testFuncs) error {
f, err := os.Create(out)
if err != nil {
return err
diff --git a/src/cmd/go/testdata/cgocover/p.go b/src/cmd/go/testdata/cgocover/p.go
new file mode 100644
index 000000000..a6a3891cd
--- /dev/null
+++ b/src/cmd/go/testdata/cgocover/p.go
@@ -0,0 +1,19 @@
+package p
+
+/*
+void
+f(void)
+{
+}
+*/
+import "C"
+
+var b bool
+
+func F() {
+ if b {
+ for {
+ }
+ }
+ C.f()
+}
diff --git a/src/cmd/go/testdata/cgocover/p_test.go b/src/cmd/go/testdata/cgocover/p_test.go
new file mode 100644
index 000000000..a8f057e35
--- /dev/null
+++ b/src/cmd/go/testdata/cgocover/p_test.go
@@ -0,0 +1,7 @@
+package p
+
+import "testing"
+
+func TestF(t *testing.T) {
+ F()
+}
diff --git a/src/cmd/go/testdata/dep_test.go b/src/cmd/go/testdata/dep_test.go
new file mode 100644
index 000000000..0c53ac4f9
--- /dev/null
+++ b/src/cmd/go/testdata/dep_test.go
@@ -0,0 +1,7 @@
+// Copyright 2014 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.
+
+package deps
+
+import _ "testing"
diff --git a/src/cmd/go/testdata/src/notest/hello.go b/src/cmd/go/testdata/src/notest/hello.go
new file mode 100644
index 000000000..7c42c32fb
--- /dev/null
+++ b/src/cmd/go/testdata/src/notest/hello.go
@@ -0,0 +1,6 @@
+package notest
+
+func hello() {
+ println("hello world")
+}
+Hello world
diff --git a/src/cmd/go/testdata/src/testcycle/p1/p1.go b/src/cmd/go/testdata/src/testcycle/p1/p1.go
new file mode 100644
index 000000000..65ab76d4e
--- /dev/null
+++ b/src/cmd/go/testdata/src/testcycle/p1/p1.go
@@ -0,0 +1,7 @@
+package p1
+
+import _ "testcycle/p2"
+
+func init() {
+ println("p1 init")
+}
diff --git a/src/cmd/go/testdata/src/testcycle/p1/p1_test.go b/src/cmd/go/testdata/src/testcycle/p1/p1_test.go
new file mode 100644
index 000000000..75abb13e6
--- /dev/null
+++ b/src/cmd/go/testdata/src/testcycle/p1/p1_test.go
@@ -0,0 +1,6 @@
+package p1
+
+import "testing"
+
+func Test(t *testing.T) {
+}
diff --git a/src/cmd/go/testdata/src/testcycle/p2/p2.go b/src/cmd/go/testdata/src/testcycle/p2/p2.go
new file mode 100644
index 000000000..7e26cdf19
--- /dev/null
+++ b/src/cmd/go/testdata/src/testcycle/p2/p2.go
@@ -0,0 +1,7 @@
+package p2
+
+import _ "testcycle/p3"
+
+func init() {
+ println("p2 init")
+}
diff --git a/src/cmd/go/testdata/src/testcycle/p3/p3.go b/src/cmd/go/testdata/src/testcycle/p3/p3.go
new file mode 100644
index 000000000..bb0a2f4f6
--- /dev/null
+++ b/src/cmd/go/testdata/src/testcycle/p3/p3.go
@@ -0,0 +1,5 @@
+package p3
+
+func init() {
+ println("p3 init")
+}
diff --git a/src/cmd/go/testdata/src/testcycle/p3/p3_test.go b/src/cmd/go/testdata/src/testcycle/p3/p3_test.go
new file mode 100644
index 000000000..9b4b0757f
--- /dev/null
+++ b/src/cmd/go/testdata/src/testcycle/p3/p3_test.go
@@ -0,0 +1,10 @@
+package p3
+
+import (
+ "testing"
+
+ _ "testcycle/p1"
+)
+
+func Test(t *testing.T) {
+}
diff --git a/src/cmd/go/testdata/src/xtestonly/f.go b/src/cmd/go/testdata/src/xtestonly/f.go
new file mode 100644
index 000000000..dac039e1a
--- /dev/null
+++ b/src/cmd/go/testdata/src/xtestonly/f.go
@@ -0,0 +1,3 @@
+package xtestonly
+
+func F() int { return 42 }
diff --git a/src/cmd/go/testdata/src/xtestonly/f_test.go b/src/cmd/go/testdata/src/xtestonly/f_test.go
new file mode 100644
index 000000000..01f6e8373
--- /dev/null
+++ b/src/cmd/go/testdata/src/xtestonly/f_test.go
@@ -0,0 +1,12 @@
+package xtestonly_test
+
+import (
+ "testing"
+ "xtestonly"
+)
+
+func TestF(t *testing.T) {
+ if x := xtestonly.F(); x != 42 {
+ t.Errorf("f.F() = %d, want 42", x)
+ }
+}
diff --git a/src/cmd/go/testdata/standalone_test.go b/src/cmd/go/testdata/standalone_test.go
new file mode 100644
index 000000000..59cf918b9
--- /dev/null
+++ b/src/cmd/go/testdata/standalone_test.go
@@ -0,0 +1,6 @@
+package standalone_test
+
+import "testing"
+
+func Test(t *testing.T) {
+}
diff --git a/src/cmd/go/testdata/testonly/p_test.go b/src/cmd/go/testdata/testonly/p_test.go
new file mode 100644
index 000000000..c89cd18d0
--- /dev/null
+++ b/src/cmd/go/testdata/testonly/p_test.go
@@ -0,0 +1 @@
+package p
diff --git a/src/cmd/go/testflag.go b/src/cmd/go/testflag.go
index aea81d8f8..73f311e5f 100644
--- a/src/cmd/go/testflag.go
+++ b/src/cmd/go/testflag.go
@@ -66,7 +66,6 @@ var testFlagDefn = []*testFlagSpec{
// local.
{name: "c", boolVar: &testC},
{name: "file", multiOK: true},
- {name: "i", boolVar: &testI},
{name: "cover", boolVar: &testCover},
{name: "coverpkg"},
@@ -75,8 +74,11 @@ var testFlagDefn = []*testFlagSpec{
{name: "n", boolVar: &buildN},
{name: "p"},
{name: "x", boolVar: &buildX},
+ {name: "i", boolVar: &buildI},
{name: "work", boolVar: &buildWork},
+ {name: "ccflags"},
{name: "gcflags"},
+ {name: "exec"},
{name: "ldflags"},
{name: "gccgoflags"},
{name: "tags"},
@@ -116,7 +118,6 @@ var testFlagDefn = []*testFlagSpec{
func testFlags(args []string) (packageNames, passToTest []string) {
inPkg := false
outputDir := ""
- testCoverMode = "set"
for i := 0; i < len(args); i++ {
if !strings.HasPrefix(args[i], "-") {
if !inPkg && packageNames == nil {
@@ -154,6 +155,16 @@ func testFlags(args []string) (packageNames, passToTest []string) {
setBoolFlag(f.boolVar, value)
case "p":
setIntFlag(&buildP, value)
+ case "exec":
+ execCmd, err = splitQuotedFields(value)
+ if err != nil {
+ fatalf("invalid flag argument for -%s: %v", f.name, err)
+ }
+ case "ccflags":
+ buildCcflags, err = splitQuotedFields(value)
+ if err != nil {
+ fatalf("invalid flag argument for -%s: %v", f.name, err)
+ }
case "gcflags":
buildGcflags, err = splitQuotedFields(value)
if err != nil {
@@ -212,6 +223,14 @@ func testFlags(args []string) (packageNames, passToTest []string) {
}
}
+ if testCoverMode == "" {
+ testCoverMode = "set"
+ if buildRace {
+ // Default coverage mode is atomic when -race is set.
+ testCoverMode = "atomic"
+ }
+ }
+
// Tell the test what directory we're running in, so it can write the profiles there.
if testProfile && outputDir == "" {
dir, err := os.Getwd()
diff --git a/src/cmd/go/vcs.go b/src/cmd/go/vcs.go
index 22d5ebc24..8f0bae0b7 100644
--- a/src/cmd/go/vcs.go
+++ b/src/cmd/go/vcs.go
@@ -354,6 +354,8 @@ type repoRoot struct {
root string
}
+var httpPrefixRE = regexp.MustCompile(`^https?:`)
+
// repoRootForImportPath analyzes importPath to determine the
// version control system, and code repository to use.
func repoRootForImportPath(importPath string) (*repoRoot, error) {
@@ -390,8 +392,12 @@ var errUnknownSite = errors.New("dynamic lookup required to find mapping")
//
// If scheme is non-empty, that scheme is forced.
func repoRootForImportPathStatic(importPath, scheme string) (*repoRoot, error) {
- if strings.Contains(importPath, "://") {
- return nil, fmt.Errorf("invalid import path %q", importPath)
+ // A common error is to use https://packagepath because that's what
+ // hg and git require. Diagnose this helpfully.
+ if loc := httpPrefixRE.FindStringIndex(importPath); loc != nil {
+ // The importPath has been cleaned, so has only one slash. The pattern
+ // ignores the slashes; the error message puts them back on the RHS at least.
+ return nil, fmt.Errorf("%q not allowed in import path", importPath[loc[0]:loc[1]]+"//")
}
for _, srv := range vcsPaths {
if !strings.HasPrefix(importPath, srv.prefix) {