summaryrefslogtreecommitdiff
path: root/libgo/go/cmd
diff options
context:
space:
mode:
Diffstat (limited to 'libgo/go/cmd')
-rw-r--r--libgo/go/cmd/cgo/ast.go3
-rw-r--r--libgo/go/cmd/cgo/doc.go12
-rw-r--r--libgo/go/cmd/cgo/gcc.go429
-rw-r--r--libgo/go/cmd/cgo/main.go15
-rw-r--r--libgo/go/cmd/cgo/out.go86
-rw-r--r--libgo/go/cmd/go/alldocs.go196
-rw-r--r--libgo/go/cmd/go/bootstrap.go3
-rw-r--r--libgo/go/cmd/go/bug.go213
-rw-r--r--libgo/go/cmd/go/build.go455
-rw-r--r--libgo/go/cmd/go/build_test.go44
-rw-r--r--libgo/go/cmd/go/env.go43
-rw-r--r--libgo/go/cmd/go/generate.go10
-rw-r--r--libgo/go/cmd/go/get.go100
-rw-r--r--libgo/go/cmd/go/go_test.go939
-rw-r--r--libgo/go/cmd/go/go_windows_test.go3
-rw-r--r--libgo/go/cmd/go/help.go54
-rw-r--r--libgo/go/cmd/go/http.go5
-rw-r--r--libgo/go/cmd/go/list.go19
-rw-r--r--libgo/go/cmd/go/main.go9
-rw-r--r--libgo/go/cmd/go/pkg.go263
-rw-r--r--libgo/go/cmd/go/test.go146
-rw-r--r--libgo/go/cmd/go/testdata/src/canonical/a/a.go3
-rw-r--r--libgo/go/cmd/go/testdata/src/canonical/a/c/c.go1
-rw-r--r--libgo/go/cmd/go/testdata/src/canonical/b/b.go3
-rw-r--r--libgo/go/cmd/go/testdata/src/canonical/d/d.go3
-rw-r--r--libgo/go/cmd/go/testdata/src/cgocover/p.go (renamed from libgo/go/cmd/go/testdata/cgocover/p.go)0
-rw-r--r--libgo/go/cmd/go/testdata/src/cgocover/p_test.go (renamed from libgo/go/cmd/go/testdata/cgocover/p_test.go)0
-rw-r--r--libgo/go/cmd/go/testdata/src/cgocover2/p.go19
-rw-r--r--libgo/go/cmd/go/testdata/src/cgocover2/x_test.go10
-rw-r--r--libgo/go/cmd/go/testdata/src/cgocover3/p.go19
-rw-r--r--libgo/go/cmd/go/testdata/src/cgocover3/p_test.go1
-rw-r--r--libgo/go/cmd/go/testdata/src/cgocover3/x_test.go10
-rw-r--r--libgo/go/cmd/go/testdata/src/cgocover4/notcgo.go1
-rw-r--r--libgo/go/cmd/go/testdata/src/cgocover4/p.go19
-rw-r--r--libgo/go/cmd/go/testdata/src/cgocover4/x_test.go10
-rw-r--r--libgo/go/cmd/go/testdata/src/dupload/dupload.go8
-rw-r--r--libgo/go/cmd/go/testdata/src/dupload/p/p.go1
-rw-r--r--libgo/go/cmd/go/testdata/src/dupload/p2/p2.go3
-rw-r--r--libgo/go/cmd/go/testdata/src/empty/pkg/pkg.go1
-rw-r--r--libgo/go/cmd/go/testdata/src/empty/pkgtest/pkg.go1
-rw-r--r--libgo/go/cmd/go/testdata/src/empty/pkgtest/test_test.go1
-rw-r--r--libgo/go/cmd/go/testdata/src/empty/pkgtestxtest/pkg.go1
-rw-r--r--libgo/go/cmd/go/testdata/src/empty/pkgtestxtest/test_test.go1
-rw-r--r--libgo/go/cmd/go/testdata/src/empty/pkgtestxtest/xtest_test.go1
-rw-r--r--libgo/go/cmd/go/testdata/src/empty/pkgxtest/pkg.go1
-rw-r--r--libgo/go/cmd/go/testdata/src/empty/pkgxtest/xtest_test.go1
-rw-r--r--libgo/go/cmd/go/testdata/src/empty/test/test_test.go1
-rw-r--r--libgo/go/cmd/go/testdata/src/empty/testxtest/test_test.go1
-rw-r--r--libgo/go/cmd/go/testdata/src/empty/testxtest/xtest_test.go1
-rw-r--r--libgo/go/cmd/go/testdata/src/empty/xtest/xtest_test.go1
-rw-r--r--libgo/go/cmd/go/testdata/src/gencycle/gencycle.go5
-rw-r--r--libgo/go/cmd/go/testdata/src/importmain/ismain/main.go5
-rw-r--r--libgo/go/cmd/go/testdata/src/importmain/test/test.go1
-rw-r--r--libgo/go/cmd/go/testdata/src/importmain/test/test_test.go6
-rw-r--r--libgo/go/cmd/go/testdata/src/my.pkg/main/main.go7
-rw-r--r--libgo/go/cmd/go/testdata/src/my.pkg/pkg.go3
-rw-r--r--libgo/go/cmd/go/testdata/src/testrace/race_test.go29
-rw-r--r--libgo/go/cmd/go/testdata/standalone_benchmark_test.go6
-rw-r--r--libgo/go/cmd/go/testdata/standalone_fail_sub_test.go8
-rw-r--r--libgo/go/cmd/go/testdata/standalone_parallel_sub_test.go14
-rw-r--r--libgo/go/cmd/go/testdata/standalone_sub_test.go7
-rw-r--r--libgo/go/cmd/go/testdata/testterminal18153/terminal_test.go39
-rw-r--r--libgo/go/cmd/go/testflag.go4
-rw-r--r--libgo/go/cmd/go/tool.go2
-rw-r--r--libgo/go/cmd/go/vcs.go70
-rw-r--r--libgo/go/cmd/go/vcs_test.go69
-rw-r--r--libgo/go/cmd/go/vendor_test.go36
-rw-r--r--libgo/go/cmd/gofmt/doc.go5
-rw-r--r--libgo/go/cmd/gofmt/gofmt.go52
-rw-r--r--libgo/go/cmd/gofmt/gofmt_test.go13
-rw-r--r--libgo/go/cmd/gofmt/simplify.go60
-rw-r--r--libgo/go/cmd/gofmt/testdata/composites.golden14
-rw-r--r--libgo/go/cmd/gofmt/testdata/composites.input14
-rw-r--r--libgo/go/cmd/internal/browser/browser.go46
74 files changed, 2902 insertions, 783 deletions
diff --git a/libgo/go/cmd/cgo/ast.go b/libgo/go/cmd/cgo/ast.go
index 000ecd44685..8ce824196d9 100644
--- a/libgo/go/cmd/cgo/ast.go
+++ b/libgo/go/cmd/cgo/ast.go
@@ -87,6 +87,7 @@ func (f *File) ReadGo(name string) {
if cg != nil {
f.Preamble += fmt.Sprintf("#line %d %q\n", sourceLine(cg), name)
f.Preamble += commentText(cg) + "\n"
+ f.Preamble += "#line 1 \"cgo-generated-wrapper\"\n"
}
}
}
@@ -296,7 +297,7 @@ func (f *File) walk(x interface{}, context string, visit func(*File, interface{}
// everything else just recurs
default:
- error_(token.NoPos, "unexpected type %T in walk", x, visit)
+ error_(token.NoPos, "unexpected type %T in walk", x)
panic("unexpected type")
case nil:
diff --git a/libgo/go/cmd/cgo/doc.go b/libgo/go/cmd/cgo/doc.go
index d3a7b6d2a73..85441e61c04 100644
--- a/libgo/go/cmd/cgo/doc.go
+++ b/libgo/go/cmd/cgo/doc.go
@@ -53,6 +53,8 @@ For example:
// #include <png.h>
import "C"
+The default pkg-config tool may be changed by setting the PKG_CONFIG environment variable.
+
When building, the CGO_CFLAGS, CGO_CPPFLAGS, CGO_CXXFLAGS, CGO_FFLAGS and
CGO_LDFLAGS environment variables are added to the flags derived from
these directives. Package-specific flags should be set using the
@@ -214,6 +216,13 @@ by making copies of the data. In pseudo-Go definitions:
// C data with explicit length to Go []byte
func C.GoBytes(unsafe.Pointer, C.int) []byte
+As a special case, C.malloc does not call the C library malloc directly
+but instead calls a Go helper function that wraps the C library malloc
+but guarantees never to return nil. If C's malloc indicates out of memory,
+the helper function crashes the program, like when Go itself runs out
+of memory. Because C.malloc cannot fail, it has no two-result form
+that returns errno.
+
C references to Go
Go functions can be exported for use by C code in the following way:
@@ -317,6 +326,9 @@ The following options are available when running cgo directly:
Write out input file in Go syntax replacing C package
names with real values. Used to generate files in the
syscall package when bootstrapping a new target.
+ -srcdir directory
+ Find the Go input files, listed on the command line,
+ in directory.
-objdir directory
Put all generated files in directory.
-importpath string
diff --git a/libgo/go/cmd/cgo/gcc.go b/libgo/go/cmd/cgo/gcc.go
index fc1d01100d2..5ea2d941ca2 100644
--- a/libgo/go/cmd/cgo/gcc.go
+++ b/libgo/go/cmd/cgo/gcc.go
@@ -167,7 +167,23 @@ func (p *Package) Translate(f *File) {
if len(needType) > 0 {
p.loadDWARF(f, needType)
}
- p.rewriteCalls(f)
+ if p.rewriteCalls(f) {
+ // Add `import _cgo_unsafe "unsafe"` as the first decl
+ // after the package statement.
+ imp := &ast.GenDecl{
+ Tok: token.IMPORT,
+ Specs: []ast.Spec{
+ &ast.ImportSpec{
+ Name: ast.NewIdent("_cgo_unsafe"),
+ Path: &ast.BasicLit{
+ Kind: token.STRING,
+ Value: `"unsafe"`,
+ },
+ },
+ },
+ }
+ f.AST.Decls = append([]ast.Decl{imp}, f.AST.Decls...)
+ }
p.rewriteRef(f)
}
@@ -413,6 +429,7 @@ func (p *Package) loadDWARF(f *File, names []*Name) {
var b bytes.Buffer
b.WriteString(f.Preamble)
b.WriteString(builtinProlog)
+ b.WriteString("#line 1 \"cgo-dwarf-inference\"\n")
for i, n := range names {
fmt.Fprintf(&b, "__typeof__(%s) *__cgo__%d;\n", n.C, i)
if n.Kind == "const" {
@@ -578,7 +595,9 @@ func (p *Package) mangleName(n *Name) {
// rewriteCalls rewrites all calls that pass pointers to check that
// they follow the rules for passing pointers between Go and C.
-func (p *Package) rewriteCalls(f *File) {
+// This returns whether the package needs to import unsafe as _cgo_unsafe.
+func (p *Package) rewriteCalls(f *File) bool {
+ needsUnsafe := false
for _, call := range f.Calls {
// This is a call to C.xxx; set goname to "xxx".
goname := call.Call.Fun.(*ast.SelectorExpr).Sel.Name
@@ -590,18 +609,24 @@ func (p *Package) rewriteCalls(f *File) {
// Probably a type conversion.
continue
}
- p.rewriteCall(f, call, name)
+ if p.rewriteCall(f, call, name) {
+ needsUnsafe = true
+ }
}
+ return needsUnsafe
}
-// rewriteCall rewrites one call to add pointer checks. We replace
-// each pointer argument x with _cgoCheckPointer(x).(T).
-func (p *Package) rewriteCall(f *File, call *Call, name *Name) {
+// rewriteCall rewrites one call to add pointer checks.
+// If any pointer checks are required, we rewrite the call into a
+// function literal that calls _cgoCheckPointer for each pointer
+// argument and then calls the original function.
+// This returns whether the package needs to import unsafe as _cgo_unsafe.
+func (p *Package) rewriteCall(f *File, call *Call, name *Name) bool {
// Avoid a crash if the number of arguments is
// less than the number of parameters.
// This will be caught when the generated file is compiled.
if len(call.Call.Args) < len(name.FuncType.Params) {
- return
+ return false
}
any := false
@@ -612,38 +637,60 @@ func (p *Package) rewriteCall(f *File, call *Call, name *Name) {
}
}
if !any {
- return
+ return false
}
// We need to rewrite this call.
//
- // We are going to rewrite C.f(p) to C.f(_cgoCheckPointer(p)).
- // If the call to C.f is deferred, that will check p at the
- // point of the defer statement, not when the function is called, so
- // rewrite to func(_cgo0 ptype) { C.f(_cgoCheckPointer(_cgo0)) }(p)
-
- var dargs []ast.Expr
- if call.Deferred {
- dargs = make([]ast.Expr, len(name.FuncType.Params))
- }
+ // We are going to rewrite C.f(p) to
+ // func (_cgo0 ptype) {
+ // _cgoCheckPointer(_cgo0)
+ // C.f(_cgo0)
+ // }(p)
+ // Using a function literal like this lets us do correct
+ // argument type checking, and works correctly if the call is
+ // deferred.
+ needsUnsafe := false
+ params := make([]*ast.Field, len(name.FuncType.Params))
+ nargs := make([]ast.Expr, len(name.FuncType.Params))
+ var stmts []ast.Stmt
for i, param := range name.FuncType.Params {
+ // params is going to become the parameters of the
+ // function literal.
+ // nargs is going to become the list of arguments made
+ // by the call within the function literal.
+ // nparam is the parameter of the function literal that
+ // corresponds to param.
+
origArg := call.Call.Args[i]
- darg := origArg
+ nparam := ast.NewIdent(fmt.Sprintf("_cgo%d", i))
+ nargs[i] = nparam
- if call.Deferred {
- dargs[i] = darg
- darg = ast.NewIdent(fmt.Sprintf("_cgo%d", i))
- call.Call.Args[i] = darg
+ // The Go version of the C type might use unsafe.Pointer,
+ // but the file might not import unsafe.
+ // Rewrite the Go type if necessary to use _cgo_unsafe.
+ ptype := p.rewriteUnsafe(param.Go)
+ if ptype != param.Go {
+ needsUnsafe = true
+ }
+
+ params[i] = &ast.Field{
+ Names: []*ast.Ident{nparam},
+ Type: ptype,
}
if !p.needsPointerCheck(f, param.Go, origArg) {
continue
}
+ // Run the cgo pointer checks on nparam.
+
+ // Change the function literal to call the real function
+ // with the parameter passed through _cgoCheckPointer.
c := &ast.CallExpr{
Fun: ast.NewIdent("_cgoCheckPointer"),
Args: []ast.Expr{
- darg,
+ nparam,
},
}
@@ -651,95 +698,83 @@ func (p *Package) rewriteCall(f *File, call *Call, name *Name) {
// expression.
c.Args = p.checkAddrArgs(f, c.Args, origArg)
- // _cgoCheckPointer returns interface{}.
- // We need to type assert that to the type we want.
- // If the Go version of this C type uses
- // unsafe.Pointer, we can't use a type assertion,
- // because the Go file might not import unsafe.
- // Instead we use a local variant of _cgoCheckPointer.
-
- var arg ast.Expr
- if n := p.unsafeCheckPointerName(param.Go, call.Deferred); n != "" {
- c.Fun = ast.NewIdent(n)
- arg = c
- } else {
- // In order for the type assertion to succeed,
- // we need it to match the actual type of the
- // argument. The only type we have is the
- // type of the function parameter. We know
- // that the argument type must be assignable
- // to the function parameter type, or the code
- // would not compile, but there is nothing
- // requiring that the types be exactly the
- // same. Add a type conversion to the
- // argument so that the type assertion will
- // succeed.
- c.Args[0] = &ast.CallExpr{
- Fun: param.Go,
- Args: []ast.Expr{
- c.Args[0],
- },
- }
-
- arg = &ast.TypeAssertExpr{
- X: c,
- Type: param.Go,
- }
+ stmt := &ast.ExprStmt{
+ X: c,
}
-
- call.Call.Args[i] = arg
+ stmts = append(stmts, stmt)
}
- if call.Deferred {
- params := make([]*ast.Field, len(name.FuncType.Params))
- for i, param := range name.FuncType.Params {
- ptype := param.Go
- if p.hasUnsafePointer(ptype) {
- // Avoid generating unsafe.Pointer by using
- // interface{}. This works because we are
- // going to call a _cgoCheckPointer function
- // anyhow.
- ptype = &ast.InterfaceType{
- Methods: &ast.FieldList{},
- }
- }
- params[i] = &ast.Field{
- Names: []*ast.Ident{
- ast.NewIdent(fmt.Sprintf("_cgo%d", i)),
- },
- Type: ptype,
- }
- }
-
- dbody := &ast.CallExpr{
- Fun: call.Call.Fun,
- Args: call.Call.Args,
+ fcall := &ast.CallExpr{
+ Fun: call.Call.Fun,
+ Args: nargs,
+ }
+ ftype := &ast.FuncType{
+ Params: &ast.FieldList{
+ List: params,
+ },
+ }
+ if name.FuncType.Result != nil {
+ rtype := p.rewriteUnsafe(name.FuncType.Result.Go)
+ if rtype != name.FuncType.Result.Go {
+ needsUnsafe = true
}
- call.Call.Fun = &ast.FuncLit{
- Type: &ast.FuncType{
- Params: &ast.FieldList{
- List: params,
- },
- },
- Body: &ast.BlockStmt{
- List: []ast.Stmt{
- &ast.ExprStmt{
- X: dbody,
- },
+ ftype.Results = &ast.FieldList{
+ List: []*ast.Field{
+ &ast.Field{
+ Type: rtype,
},
},
}
- call.Call.Args = dargs
- call.Call.Lparen = token.NoPos
- call.Call.Rparen = token.NoPos
+ }
- // There is a Ref pointing to the old call.Call.Fun.
- for _, ref := range f.Ref {
- if ref.Expr == &call.Call.Fun {
- ref.Expr = &dbody.Fun
+ // There is a Ref pointing to the old call.Call.Fun.
+ for _, ref := range f.Ref {
+ if ref.Expr == &call.Call.Fun {
+ ref.Expr = &fcall.Fun
+
+ // If this call expects two results, we have to
+ // adjust the results of the function we generated.
+ if ref.Context == "call2" {
+ if ftype.Results == nil {
+ // An explicit void argument
+ // looks odd but it seems to
+ // be how cgo has worked historically.
+ ftype.Results = &ast.FieldList{
+ List: []*ast.Field{
+ &ast.Field{
+ Type: ast.NewIdent("_Ctype_void"),
+ },
+ },
+ }
+ }
+ ftype.Results.List = append(ftype.Results.List,
+ &ast.Field{
+ Type: ast.NewIdent("error"),
+ })
}
}
}
+
+ var fbody ast.Stmt
+ if ftype.Results == nil {
+ fbody = &ast.ExprStmt{
+ X: fcall,
+ }
+ } else {
+ fbody = &ast.ReturnStmt{
+ Results: []ast.Expr{fcall},
+ }
+ }
+ call.Call.Fun = &ast.FuncLit{
+ Type: ftype,
+ Body: &ast.BlockStmt{
+ List: append(stmts, fbody),
+ },
+ }
+ call.Call.Lparen = token.NoPos
+ call.Call.Rparen = token.NoPos
+
+ return needsUnsafe
}
// needsPointerCheck returns whether the type t needs a pointer check.
@@ -782,6 +817,11 @@ func (p *Package) hasPointer(f *File, t ast.Expr, top bool) bool {
if !top {
return true
}
+ // Check whether this is a pointer to a C union (or class)
+ // type that contains a pointer.
+ if unionWithPointer[t.X] {
+ return true
+ }
return p.hasPointer(f, t.X, false)
case *ast.FuncType, *ast.InterfaceType, *ast.MapType, *ast.ChanType:
return true
@@ -935,69 +975,52 @@ func (p *Package) isType(t ast.Expr) bool {
return false
}
-// unsafeCheckPointerName is given the Go version of a C type. If the
-// type uses unsafe.Pointer, we arrange to build a version of
-// _cgoCheckPointer that returns that type. This avoids using a type
-// assertion to unsafe.Pointer in our copy of user code. We return
-// the name of the _cgoCheckPointer function we are going to build, or
-// the empty string if the type does not use unsafe.Pointer.
-//
-// The deferred parameter is true if this check is for the argument of
-// a deferred function. In that case we need to use an empty interface
-// as the argument type, because the deferred function we introduce in
-// rewriteCall will use an empty interface type, and we can't add a
-// type assertion. This is handled by keeping a separate list, and
-// writing out the lists separately in writeDefs.
-func (p *Package) unsafeCheckPointerName(t ast.Expr, deferred bool) string {
- if !p.hasUnsafePointer(t) {
- return ""
- }
- var buf bytes.Buffer
- conf.Fprint(&buf, fset, t)
- s := buf.String()
- checks := &p.CgoChecks
- if deferred {
- checks = &p.DeferredCgoChecks
- }
- for i, t := range *checks {
- if s == t {
- return p.unsafeCheckPointerNameIndex(i, deferred)
- }
- }
- *checks = append(*checks, s)
- return p.unsafeCheckPointerNameIndex(len(*checks)-1, deferred)
-}
-
-// hasUnsafePointer returns whether the Go type t uses unsafe.Pointer.
-// t is the Go version of a C type, so we don't need to handle every case.
-// We only care about direct references, not references via typedefs.
-func (p *Package) hasUnsafePointer(t ast.Expr) bool {
+// rewriteUnsafe returns a version of t with references to unsafe.Pointer
+// rewritten to use _cgo_unsafe.Pointer instead.
+func (p *Package) rewriteUnsafe(t ast.Expr) ast.Expr {
switch t := t.(type) {
case *ast.Ident:
// We don't see a SelectorExpr for unsafe.Pointer;
// this is created by code in this file.
- return t.Name == "unsafe.Pointer"
+ if t.Name == "unsafe.Pointer" {
+ return ast.NewIdent("_cgo_unsafe.Pointer")
+ }
case *ast.ArrayType:
- return p.hasUnsafePointer(t.Elt)
+ t1 := p.rewriteUnsafe(t.Elt)
+ if t1 != t.Elt {
+ r := *t
+ r.Elt = t1
+ return &r
+ }
case *ast.StructType:
+ changed := false
+ fields := *t.Fields
+ fields.List = nil
for _, f := range t.Fields.List {
- if p.hasUnsafePointer(f.Type) {
- return true
+ ft := p.rewriteUnsafe(f.Type)
+ if ft == f.Type {
+ fields.List = append(fields.List, f)
+ } else {
+ fn := *f
+ fn.Type = ft
+ fields.List = append(fields.List, &fn)
+ changed = true
}
}
+ if changed {
+ r := *t
+ r.Fields = &fields
+ return &r
+ }
case *ast.StarExpr: // Pointer type.
- return p.hasUnsafePointer(t.X)
- }
- return false
-}
-
-// unsafeCheckPointerNameIndex returns the name to use for a
-// _cgoCheckPointer variant based on the index in the CgoChecks slice.
-func (p *Package) unsafeCheckPointerNameIndex(i int, deferred bool) string {
- if deferred {
- return fmt.Sprintf("_cgoCheckPointerInDefer%d", i)
+ x1 := p.rewriteUnsafe(t.X)
+ if x1 != t.X {
+ r := *t
+ r.X = x1
+ return &r
+ }
}
- return fmt.Sprintf("_cgoCheckPointer%d", i)
+ return t
}
// rewriteRef rewrites all the C.xxx references in f.AST to refer to the
@@ -1187,6 +1210,8 @@ func (p *Package) gccMachine() []string {
return []string{"-m64"}
case "mips64", "mips64le":
return []string{"-mabi=64"}
+ case "mips", "mipsle":
+ return []string{"-mabi=32"}
}
return nil
}
@@ -1415,6 +1440,10 @@ var tagGen int
var typedef = make(map[string]*Type)
var goIdent = make(map[string]*ast.Ident)
+// unionWithPointer is true for a Go type that represents a C union (or class)
+// that may contain a pointer. This is used for cgo pointer checking.
+var unionWithPointer = make(map[ast.Expr]bool)
+
func (c *typeConv) Init(ptrSize, intSize int64) {
c.ptrSize = ptrSize
c.intSize = intSize
@@ -1464,6 +1493,19 @@ func base(dt dwarf.Type) dwarf.Type {
return dt
}
+// unqual strips away qualifiers from a DWARF type.
+// In general we don't care about top-level qualifiers.
+func unqual(dt dwarf.Type) dwarf.Type {
+ for {
+ if d, ok := dt.(*dwarf.QualType); ok {
+ dt = d.Type
+ } else {
+ break
+ }
+ }
+ return dt
+}
+
// Map from dwarf text names to aliases we use in package "C".
var dwarfToName = map[string]string{
"long int": "long",
@@ -1641,7 +1683,7 @@ func (c *typeConv) Type(dtype dwarf.Type, pos token.Pos) *Type {
case 16:
t.Go = c.complex128
}
- if t.Align = t.Size; t.Align >= c.ptrSize {
+ if t.Align = t.Size / 2; t.Align >= c.ptrSize {
t.Align = c.ptrSize
}
@@ -1687,6 +1729,15 @@ func (c *typeConv) Type(dtype dwarf.Type, pos token.Pos) *Type {
if _, ok := base(dt.Type).(*dwarf.VoidType); ok {
t.Go = c.goVoidPtr
t.C.Set("void*")
+ dq := dt.Type
+ for {
+ if d, ok := dq.(*dwarf.QualType); ok {
+ t.C.Set(d.Qual + " " + t.C.String())
+ dq = d.Type
+ } else {
+ break
+ }
+ }
break
}
@@ -1699,9 +1750,16 @@ func (c *typeConv) Type(dtype dwarf.Type, pos token.Pos) *Type {
c.ptrs[dt.Type] = append(c.ptrs[dt.Type], t)
case *dwarf.QualType:
- // Ignore qualifier.
- t = c.Type(dt.Type, pos)
- c.m[dtype] = t
+ t1 := c.Type(dt.Type, pos)
+ t.Size = t1.Size
+ t.Align = t1.Align
+ t.Go = t1.Go
+ if unionWithPointer[t1.Go] {
+ unionWithPointer[t.Go] = true
+ }
+ t.EnumValues = nil
+ t.Typedef = ""
+ t.C.Set("%s "+dt.Qual, t1.C)
return t
case *dwarf.StructType:
@@ -1733,6 +1791,9 @@ func (c *typeConv) Type(dtype dwarf.Type, pos token.Pos) *Type {
switch dt.Kind {
case "class", "union":
t.Go = c.Opaque(t.Size)
+ if c.dwarfHasPointer(dt, pos) {
+ unionWithPointer[t.Go] = true
+ }
if t.C.Empty() {
t.C.Set("__typeof__(unsigned char[%d])", t.Size)
}
@@ -1775,6 +1836,9 @@ func (c *typeConv) Type(dtype dwarf.Type, pos token.Pos) *Type {
goIdent[name.Name] = name
sub := c.Type(dt.Type, pos)
t.Go = name
+ if unionWithPointer[sub.Go] {
+ unionWithPointer[t.Go] = true
+ }
t.Size = sub.Size
t.Align = sub.Align
oldType := typedef[name.Name]
@@ -1905,7 +1969,7 @@ func isStructUnionClass(x ast.Expr) bool {
// FuncArg returns a Go type with the same memory layout as
// dtype when used as the type of a C function argument.
func (c *typeConv) FuncArg(dtype dwarf.Type, pos token.Pos) *Type {
- t := c.Type(dtype, pos)
+ t := c.Type(unqual(dtype), pos)
switch dt := dtype.(type) {
case *dwarf.ArrayType:
// Arrays are passed implicitly as pointers in C.
@@ -1935,9 +1999,12 @@ func (c *typeConv) FuncArg(dtype dwarf.Type, pos token.Pos) *Type {
return nil
}
- // Remember the C spelling, in case the struct
- // has __attribute__((unavailable)) on it. See issue 2888.
- t.Typedef = dt.Name
+ // For a struct/union/class, remember the C spelling,
+ // in case it has __attribute__((unavailable)).
+ // See issue 2888.
+ if isStructUnionClass(t.Go) {
+ t.Typedef = dt.Name
+ }
}
}
return t
@@ -1966,7 +2033,7 @@ func (c *typeConv) FuncType(dtype *dwarf.FuncType, pos token.Pos) *FuncType {
if _, ok := dtype.ReturnType.(*dwarf.VoidType); ok {
gr = []*ast.Field{{Type: c.goVoid}}
} else if dtype.ReturnType != nil {
- r = c.Type(dtype.ReturnType, pos)
+ r = c.Type(unqual(dtype.ReturnType), pos)
gr = []*ast.Field{{Type: r.Go}}
}
return &FuncType{
@@ -2153,6 +2220,44 @@ func (c *typeConv) Struct(dt *dwarf.StructType, pos token.Pos) (expr *ast.Struct
return
}
+// dwarfHasPointer returns whether the DWARF type dt contains a pointer.
+func (c *typeConv) dwarfHasPointer(dt dwarf.Type, pos token.Pos) bool {
+ switch dt := dt.(type) {
+ default:
+ fatalf("%s: unexpected type: %s", lineno(pos), dt)
+ return false
+
+ case *dwarf.AddrType, *dwarf.BoolType, *dwarf.CharType, *dwarf.EnumType,
+ *dwarf.FloatType, *dwarf.ComplexType, *dwarf.FuncType,
+ *dwarf.IntType, *dwarf.UcharType, *dwarf.UintType, *dwarf.VoidType:
+
+ return false
+
+ case *dwarf.ArrayType:
+ return c.dwarfHasPointer(dt.Type, pos)
+
+ case *dwarf.PtrType:
+ return true
+
+ case *dwarf.QualType:
+ return c.dwarfHasPointer(dt.Type, pos)
+
+ case *dwarf.StructType:
+ for _, f := range dt.Field {
+ if c.dwarfHasPointer(f.Type, pos) {
+ return true
+ }
+ }
+ return false
+
+ case *dwarf.TypedefType:
+ if dt.Name == "_GoString_" || dt.Name == "_GoBytes_" {
+ return true
+ }
+ return c.dwarfHasPointer(dt.Type, pos)
+ }
+}
+
func upper(s string) string {
if s == "" {
return ""
diff --git a/libgo/go/cmd/cgo/main.go b/libgo/go/cmd/cgo/main.go
index 219b2527323..c91c830260f 100644
--- a/libgo/go/cmd/cgo/main.go
+++ b/libgo/go/cmd/cgo/main.go
@@ -42,10 +42,6 @@ type Package struct {
GoFiles []string // list of Go files
GccFiles []string // list of gcc output files
Preamble string // collected preamble for _cgo_export.h
-
- // See unsafeCheckPointerName.
- CgoChecks []string
- DeferredCgoChecks []string
}
// A File collects information about a single Go input file.
@@ -153,6 +149,8 @@ var ptrSizeMap = map[string]int64{
"mipsn32": 4,
"mipso64": 8,
"mipsn64": 8,
+ "mips": 4,
+ "mipsle": 4,
"mips64": 8,
"mips64le": 8,
"ppc": 4,
@@ -175,6 +173,8 @@ var intSizeMap = map[string]int64{
"mipsn32": 4,
"mipso64": 8,
"mipsn64": 8,
+ "mips": 4,
+ "mipsle": 4,
"mips64": 8,
"mips64le": 8,
"ppc": 4,
@@ -200,6 +200,7 @@ var dynlinker = flag.Bool("dynlinker", false, "record dynamic linker information
// constant values used in the host's C libraries and system calls.
var godefs = flag.Bool("godefs", false, "for bootstrap: write Go definitions for C file to standard output")
+var srcDir = flag.String("srcdir", "", "source directory")
var objDir = flag.String("objdir", "", "object directory")
var importPath = flag.String("importpath", "", "import path of package being built (for comments in generated files)")
var exportHeader = flag.String("exportheader", "", "where to write export header if any exported functions")
@@ -278,6 +279,9 @@ func main() {
// Use the beginning of the md5 of the input to disambiguate.
h := md5.New()
for _, input := range goFiles {
+ if *srcDir != "" {
+ input = filepath.Join(*srcDir, input)
+ }
f, err := os.Open(input)
if err != nil {
fatalf("%s", err)
@@ -289,6 +293,9 @@ func main() {
fs := make([]*File, len(goFiles))
for i, input := range goFiles {
+ if *srcDir != "" {
+ input = filepath.Join(*srcDir, input)
+ }
f := new(File)
f.ReadGo(input)
f.DiscardCgoDirectives()
diff --git a/libgo/go/cmd/cgo/out.go b/libgo/go/cmd/cgo/out.go
index 842b1c5ef80..e82ec375a27 100644
--- a/libgo/go/cmd/cgo/out.go
+++ b/libgo/go/cmd/cgo/out.go
@@ -19,7 +19,10 @@ import (
"strings"
)
-var conf = printer.Config{Mode: printer.SourcePos, Tabwidth: 8}
+var (
+ conf = printer.Config{Mode: printer.SourcePos, Tabwidth: 8}
+ noSourceConf = printer.Config{Tabwidth: 8}
+)
// writeDefs creates output files to be compiled by gc and gcc.
func (p *Package) writeDefs() {
@@ -95,7 +98,19 @@ func (p *Package) writeDefs() {
for _, name := range typedefNames {
def := typedef[name]
fmt.Fprintf(fgo2, "type %s ", name)
- conf.Fprint(fgo2, fset, def.Go)
+ // We don't have source info for these types, so write them out without source info.
+ // Otherwise types would look like:
+ //
+ // type _Ctype_struct_cb struct {
+ // //line :1
+ // on_test *[0]byte
+ // //line :1
+ // }
+ //
+ // Which is not useful. Moreover we never override source info,
+ // so subsequent source code uses the same source info.
+ // Moreover, empty file name makes compile emit no source debug info at all.
+ noSourceConf.Fprint(fgo2, fset, def.Go)
fmt.Fprintf(fgo2, "\n\n")
}
if *gccgo {
@@ -111,17 +126,11 @@ func (p *Package) writeDefs() {
fmt.Fprint(fgo2, goProlog)
}
- for i, t := range p.CgoChecks {
- n := p.unsafeCheckPointerNameIndex(i, false)
- fmt.Fprintf(fgo2, "\nfunc %s(p %s, args ...interface{}) %s {\n", n, t, t)
- fmt.Fprintf(fgo2, "\treturn _cgoCheckPointer(p, args...).(%s)\n", t)
- fmt.Fprintf(fgo2, "}\n")
+ if fc != nil {
+ fmt.Fprintf(fc, "#line 1 \"cgo-generated-wrappers\"\n")
}
- for i, t := range p.DeferredCgoChecks {
- n := p.unsafeCheckPointerNameIndex(i, true)
- fmt.Fprintf(fgo2, "\nfunc %s(p interface{}, args ...interface{}) %s {\n", n, t)
- fmt.Fprintf(fgo2, "\treturn _cgoCheckPointer(p, args...).(%s)\n", t)
- fmt.Fprintf(fgo2, "}\n")
+ if fm != nil {
+ fmt.Fprintf(fm, "#line 1 \"cgo-generated-wrappers\"\n")
}
gccgoSymbolPrefix := p.gccgoSymbolPrefix()
@@ -346,11 +355,7 @@ func (p *Package) structType(n *Name) (string, int64) {
fmt.Fprintf(&buf, "\t\tchar __pad%d[%d];\n", off, pad)
off += pad
}
- qual := ""
- if c := t.C.String(); c[len(c)-1] == '*' {
- qual = "const "
- }
- fmt.Fprintf(&buf, "\t\t%s%s r;\n", qual, t.C)
+ fmt.Fprintf(&buf, "\t\t%s r;\n", t.C)
off += t.Size
}
if off%p.PtrSize != 0 {
@@ -611,20 +616,10 @@ func (p *Package) writeOutputFunc(fgcc *os.File, n *Name) {
}
}
fmt.Fprintf(fgcc, "%s(", n.C)
- for i, t := range n.FuncType.Params {
+ for i := range n.FuncType.Params {
if i > 0 {
fmt.Fprintf(fgcc, ", ")
}
- // We know the type params are correct, because
- // the Go equivalents had good type params.
- // However, our version of the type omits the magic
- // words const and volatile, which can provoke
- // C compiler warnings. Silence them by casting
- // all pointers to void*. (Eventually that will produce
- // other warnings.)
- if c := t.C.String(); c[len(c)-1] == '*' {
- fmt.Fprintf(fgcc, "(void*)")
- }
fmt.Fprintf(fgcc, "a->p%d", i)
}
fmt.Fprintf(fgcc, ");\n")
@@ -684,14 +679,10 @@ func (p *Package) writeGccgoOutputFunc(fgcc *os.File, n *Name) {
}
}
fmt.Fprintf(fgcc, "%s(", n.C)
- for i, t := range n.FuncType.Params {
+ for i := range n.FuncType.Params {
if i > 0 {
fmt.Fprintf(fgcc, ", ")
}
- // Cast to void* to avoid warnings due to omitted qualifiers.
- if c := t.C.String(); c[len(c)-1] == '*' {
- fmt.Fprintf(fgcc, "(void*)")
- }
fmt.Fprintf(fgcc, "p%d", i)
}
fmt.Fprintf(fgcc, ");\n")
@@ -1217,8 +1208,8 @@ var goTypes = map[string]*Type{
"uint64": {Size: 8, Align: 8, C: c("GoUint64")},
"float32": {Size: 4, Align: 4, C: c("GoFloat32")},
"float64": {Size: 8, Align: 8, C: c("GoFloat64")},
- "complex64": {Size: 8, Align: 8, C: c("GoComplex64")},
- "complex128": {Size: 16, Align: 16, C: c("GoComplex128")},
+ "complex64": {Size: 8, Align: 4, C: c("GoComplex64")},
+ "complex128": {Size: 16, Align: 8, C: c("GoComplex128")},
}
// Map an ast type to a Type.
@@ -1299,6 +1290,7 @@ func (p *Package) cgoType(e ast.Expr) *Type {
}
const gccProlog = `
+#line 1 "cgo-gcc-prolog"
/*
If x and y are not equal, the type will be invalid
(have a negative array count) and an inscrutable error will come
@@ -1332,6 +1324,7 @@ const noTsanProlog = `
// This must match the TSAN code in runtime/cgo/libcgo.h.
const yesTsanProlog = `
+#line 1 "cgo-tsan-prolog"
#define CGO_NO_SANITIZE_THREAD __attribute__ ((no_sanitize_thread))
long long _cgo_sync __attribute__ ((common));
@@ -1354,6 +1347,7 @@ static void _cgo_tsan_release() {
var tsanProlog = noTsanProlog
const builtinProlog = `
+#line 1 "cgo-builtin-prolog"
#include <stddef.h> /* for ptrdiff_t and size_t below */
/* Define intgo when compiling with GCC. */
@@ -1377,14 +1371,14 @@ func _cgo_runtime_cgocall(unsafe.Pointer, uintptr) int32
func _cgo_runtime_cgocallback(unsafe.Pointer, unsafe.Pointer, uintptr, uintptr)
//go:linkname _cgoCheckPointer runtime.cgoCheckPointer
-func _cgoCheckPointer(interface{}, ...interface{}) interface{}
+func _cgoCheckPointer(interface{}, ...interface{})
//go:linkname _cgoCheckResult runtime.cgoCheckResult
func _cgoCheckResult(interface{})
`
const gccgoGoProlog = `
-func _cgoCheckPointer(interface{}, ...interface{}) interface{}
+func _cgoCheckPointer(interface{}, ...interface{})
func _cgoCheckResult(interface{})
`
@@ -1461,9 +1455,15 @@ const cMallocDefGo = `
var __cgofn__cgoPREFIX_Cfunc__Cmalloc byte
var _cgoPREFIX_Cfunc__Cmalloc = unsafe.Pointer(&__cgofn__cgoPREFIX_Cfunc__Cmalloc)
+//go:linkname runtime_throw runtime.throw
+func runtime_throw(string)
+
//go:cgo_unsafe_args
func _cgo_cmalloc(p0 uint64) (r1 unsafe.Pointer) {
_cgo_runtime_cgocall(_cgoPREFIX_Cfunc__Cmalloc, uintptr(unsafe.Pointer(&p0)))
+ if r1 == nil {
+ runtime_throw("runtime: C malloc failed")
+ }
return
}
`
@@ -1500,6 +1500,7 @@ func (p *Package) cPrologGccgo() string {
}
const cPrologGccgo = `
+#line 1 "cgo-c-prolog-gccgo"
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
@@ -1564,18 +1565,17 @@ typedef struct __go_empty_interface {
void *__object;
} Eface;
-extern Eface runtimeCgoCheckPointer(Eface, Slice)
+extern void runtimeCgoCheckPointer(Eface, Slice)
__asm__("runtime.cgoCheckPointer")
__attribute__((weak));
-extern Eface localCgoCheckPointer(Eface, Slice)
+extern void localCgoCheckPointer(Eface, Slice)
__asm__("GCCGOSYMBOLPREF._cgoCheckPointer");
-Eface localCgoCheckPointer(Eface ptr, Slice args) {
+void localCgoCheckPointer(Eface ptr, Slice args) {
if(runtimeCgoCheckPointer) {
- return runtimeCgoCheckPointer(ptr, args);
+ runtimeCgoCheckPointer(ptr, args);
}
- return ptr;
}
extern void runtimeCgoCheckResult(Eface)
@@ -1598,6 +1598,7 @@ func (p *Package) gccExportHeaderProlog() string {
const gccExportHeaderProlog = `
/* Start of boilerplate cgo prologue. */
+#line 1 "cgo-gcc-export-header-prolog"
#ifndef GO_CGO_PROLOGUE_H
#define GO_CGO_PROLOGUE_H
@@ -1651,6 +1652,7 @@ const gccExportHeaderEpilog = `
// We use weak declarations, and test the addresses, so that this code
// works with older versions of gccgo.
const gccgoExportFileProlog = `
+#line 1 "cgo-gccgo-export-file-prolog"
extern _Bool runtime_iscgo __attribute__ ((weak));
static void GoInit(void) __attribute__ ((constructor));
diff --git a/libgo/go/cmd/go/alldocs.go b/libgo/go/cmd/go/alldocs.go
index 58b0d16b2b0..e93fd6ebed7 100644
--- a/libgo/go/cmd/go/alldocs.go
+++ b/libgo/go/cmd/go/alldocs.go
@@ -17,6 +17,7 @@
// clean remove object files
// doc show documentation for package or symbol
// env print Go environment information
+// bug print information for bug reports
// fix run go tool fix on packages
// fmt run gofmt on package sources
// generate generate Go files by processing source
@@ -323,6 +324,17 @@
// each named variable on its own line.
//
//
+// Print information for bug reports
+//
+// Usage:
+//
+// go bug
+//
+// Bug prints information that helps file effective bug reports.
+//
+// Bugs may be reported at https://golang.org/issue/new.
+//
+//
// Run go tool fix on packages
//
// Usage:
@@ -367,7 +379,7 @@
//
// Generate runs commands described by directives within existing
// files. Those commands can run any process but the intent is to
-// create or update Go source files, for instance by running yacc.
+// create or update Go source files.
//
// Go generate is never run automatically by go build, go get, go test,
// and so on. It must be run explicitly.
@@ -430,10 +442,10 @@
// can be used to create aliases or to handle multiword generators.
// For example,
//
-// //go:generate -command yacc go tool yacc
+// //go:generate -command foo go tool foo
//
-// specifies that the command "yacc" represents the generator
-// "go tool yacc".
+// specifies that the command "foo" represents the generator
+// "go tool foo".
//
// Generate processes packages in the order given on the command line,
// one at a time. If the command line lists .go files, they are treated
@@ -496,11 +508,13 @@
// 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.
//
+// The -v flag enables verbose progress and debug output.
+//
// Get also accepts build flags to control the installation. See 'go help build'.
//
// When checking out a new package, get creates the target directory
// GOPATH/src/<import-path>. If the GOPATH contains multiple entries,
-// get uses the first one. See 'go help gopath'.
+// get uses the first one. For more details see: 'go help gopath'.
//
// 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
@@ -584,6 +598,8 @@
// SwigFiles []string // .swig files
// SwigCXXFiles []string // .swigcxx files
// SysoFiles []string // .syso object files to add to archive
+// TestGoFiles []string // _test.go files in package
+// XTestGoFiles []string // _test.go files outside package
//
// // Cgo directives
// CgoCFLAGS []string // cgo: flags for C compiler
@@ -594,20 +610,23 @@
// CgoPkgConfig []string // cgo: pkg-config names
//
// // Dependency information
-// Imports []string // import paths used by this package
-// Deps []string // all (recursively) imported dependencies
+// Imports []string // import paths used by this package
+// Deps []string // all (recursively) imported dependencies
+// TestImports []string // imports from TestGoFiles
+// XTestImports []string // imports from XTestGoFiles
//
// // Error information
// Incomplete bool // this package or a dependency has an error
// Error *PackageError // error loading package
// DepsErrors []*PackageError // errors loading dependencies
-//
-// TestGoFiles []string // _test.go files in package
-// TestImports []string // imports from TestGoFiles
-// XTestGoFiles []string // _test.go files outside package
-// XTestImports []string // imports from XTestGoFiles
// }
//
+// Packages stored in vendor directories report an ImportPath that includes the
+// path to the vendor directory (for example, "d/vendor/p" instead of "p"),
+// so that the ImportPath uniquely identifies a given copy of a package.
+// The Imports, Deps, TestImports, and XTestImports lists also contain these
+// expanded imports paths. See golang.org/s/go15vendor for more about vendoring.
+//
// The error information, if any, is
//
// type PackageError struct {
@@ -852,6 +871,10 @@
// position independent executables (PIE). Packages not named
// main are ignored.
//
+// -buildmode=plugin
+// Build the listed main packages, plus all packages that they
+// import, into a Go plugin. Packages not named main are ignored.
+//
//
// File types
//
@@ -906,8 +929,13 @@
// On Windows, the value is a semicolon-separated string.
// On Plan 9, the value is a list.
//
-// GOPATH must be set to get, build and install packages outside the
-// standard Go tree.
+// If the environment variable is unset, GOPATH defaults
+// to a subdirectory named "go" in the user's home directory
+// ($HOME/go on Unix, %USERPROFILE%\go on Windows),
+// unless that directory holds a Go distribution.
+// Run "go env GOPATH" to see the current GOPATH.
+//
+// See https://golang.org/wiki/SettingGOPATH to set a custom GOPATH.
//
// Each directory listed in GOPATH must have a prescribed structure:
//
@@ -935,9 +963,9 @@
//
// Here's an example directory layout:
//
-// GOPATH=/home/user/gocode
+// GOPATH=/home/user/go
//
-// /home/user/gocode/
+// /home/user/go/
// src/
// foo/
// bar/ (go code in package bar)
@@ -963,7 +991,7 @@
// by code in the directory tree rooted at the parent of "internal".
// Here's an extended version of the directory layout above:
//
-// /home/user/gocode/
+// /home/user/go/
// src/
// crash/
// bang/ (go code in package bang)
@@ -1001,7 +1029,7 @@
// but with the "internal" directory renamed to "vendor"
// and a new foo/vendor/crash/bang directory added:
//
-// /home/user/gocode/
+// /home/user/go/
// src/
// crash/
// bang/ (go code in package bang)
@@ -1060,7 +1088,7 @@
// The operating system for which to compile code.
// Examples are linux, darwin, windows, netbsd.
// GOPATH
-// See 'go help gopath'.
+// For more details see: 'go help gopath'.
// GORACE
// Options for the race detector.
// See https://golang.org/doc/articles/race_detector.html.
@@ -1082,10 +1110,15 @@
// CGO_CXXFLAGS
// Flags that cgo will pass to the compiler when compiling
// C++ code.
+// CGO_FFLAGS
+// Flags that cgo will pass to the compiler when compiling
+// Fortran code.
// CGO_LDFLAGS
// Flags that cgo will pass to the compiler when linking.
// CXX
// The command to use to compile C++ code.
+// PKG_CONFIG
+// Path to pkg-config tool.
//
// Architecture-specific environment variables:
//
@@ -1107,14 +1140,18 @@
// Whether the linker should use external linking mode
// when using -linkmode=auto with code that uses cgo.
// Set to 0 to disable external linking mode, 1 to enable it.
+// GIT_ALLOW_PROTOCOL
+// Defined by Git. A colon-separated list of schemes that are allowed to be used
+// with git fetch/clone. If set, any scheme not explicitly mentioned will be
+// considered insecure by 'go get'.
//
//
// Import path syntax
//
-// An import path (see 'go help packages') denotes a package
-// stored in the local file system. In general, an import path denotes
-// either a standard package (such as "unicode/utf8") or a package
-// found in one of the work spaces (see 'go help gopath').
+// An import path (see 'go help packages') denotes a package stored in the local
+// file system. In general, an import path denotes either a standard package (such
+// as "unicode/utf8") or a package found in one of the work spaces (For more
+// details see: 'go help gopath').
//
// Relative import paths
//
@@ -1206,6 +1243,11 @@
// each is tried in turn when downloading. For example, a Git
// download tries https://, then git+ssh://.
//
+// By default, downloads are restricted to known secure protocols
+// (e.g. https, ssh). To override this setting for Git downloads, the
+// GIT_ALLOW_PROTOCOL environment variable can be set (For more details see:
+// 'go help environment').
+//
// If the import path is not a known code hosting site and also lacks a
// version control qualifier, the go tool attempts to fetch the import
// over https/http and looks for a <meta> tag in the document's HTML
@@ -1246,8 +1288,8 @@
// same meta tag and then git clone https://code.org/r/p/exproj into
// GOPATH/src/example.org.
//
-// New downloaded packages are written to the first directory
-// listed in the GOPATH environment variable (see 'go help gopath').
+// New downloaded packages are written to the first directory listed in the GOPATH
+// environment variable (For more details see: 'go help gopath').
//
// The go command attempts to download the version of the
// package appropriate for the Go release being used.
@@ -1291,7 +1333,7 @@
//
// Otherwise, the import path P denotes the package found in
// the directory DIR/src/P for some DIR listed in the GOPATH
-// environment variable (see 'go help gopath').
+// environment variable (For more details see: 'go help gopath').
//
// If no import paths are given, the action applies to the
// package in the current directory.
@@ -1311,6 +1353,9 @@
// - "cmd" expands to the Go repository's commands and their
// internal libraries.
//
+// Import paths beginning with "cmd/" only match source code in
+// the Go repository.
+//
// An import path is a pattern if it includes one or more "..." wildcards,
// each of which can match any string, including the empty string and
// strings containing slashes. Such a pattern expands to all package
@@ -1366,28 +1411,11 @@
// By default, no benchmarks run. To run all benchmarks,
// use '-bench .' or '-bench=.'.
//
-// -benchmem
-// Print memory allocation statistics for benchmarks.
-//
// -benchtime t
// Run enough iterations of each benchmark to take t, specified
// as a time.Duration (for example, -benchtime 1h30s).
// The default is 1 second (1s).
//
-// -blockprofile block.out
-// Write a goroutine blocking profile to the specified file
-// when all tests are complete.
-// Writes test binary as -c would.
-//
-// -blockprofilerate n
-// Control the detail provided in goroutine blocking profiles by
-// calling runtime.SetBlockProfileRate with n.
-// See 'go doc runtime.SetBlockProfileRate'.
-// The profiler aims to sample, on average, one blocking event every
-// n nanoseconds the program spends blocked. By default,
-// if -test.blockprofile is set without this flag, all blocking events
-// are recorded, equivalent to -test.blockprofilerate=1.
-//
// -count n
// Run each test and benchmark n times (default 1).
// If -cpu is set, run n times for each GOMAXPROCS value.
@@ -1413,33 +1441,11 @@
// Packages are specified as import paths.
// Sets -cover.
//
-// -coverprofile cover.out
-// Write a coverage profile to the file after all tests have passed.
-// Sets -cover.
-//
// -cpu 1,2,4
// Specify a list of GOMAXPROCS values for which the tests or
// benchmarks should be executed. The default is the current value
// of GOMAXPROCS.
//
-// -cpuprofile cpu.out
-// Write a CPU profile to the specified file before exiting.
-// Writes test binary as -c would.
-//
-// -memprofile mem.out
-// Write a memory profile to the file after all tests have passed.
-// Writes test binary as -c would.
-//
-// -memprofilerate n
-// Enable more precise (and expensive) memory profiles by setting
-// runtime.MemProfileRate. See 'go doc runtime.MemProfileRate'.
-// To profile all memory allocations, use -test.memprofilerate=1
-// and pass --alloc_space flag to the pprof tool.
-//
-// -outputdir directory
-// Place output files from profiling in the specified directory,
-// by default the directory in which "go test" is running.
-//
// -parallel n
// Allow parallel execution of test functions that call t.Parallel.
// The value of this flag is the maximum number of tests to run
@@ -1465,13 +1471,64 @@
// If a test runs longer than t, panic.
// The default is 10 minutes (10m).
//
-// -trace trace.out
-// Write an execution trace to the specified file before exiting.
-//
// -v
// Verbose output: log all tests as they are run. Also print all
// text from Log and Logf calls even if the test succeeds.
//
+// The following flags are also recognized by 'go test' and can be used to
+// profile the tests during execution:
+//
+// -benchmem
+// Print memory allocation statistics for benchmarks.
+//
+// -blockprofile block.out
+// Write a goroutine blocking profile to the specified file
+// when all tests are complete.
+// Writes test binary as -c would.
+//
+// -blockprofilerate n
+// Control the detail provided in goroutine blocking profiles by
+// calling runtime.SetBlockProfileRate with n.
+// See 'go doc runtime.SetBlockProfileRate'.
+// The profiler aims to sample, on average, one blocking event every
+// n nanoseconds the program spends blocked. By default,
+// if -test.blockprofile is set without this flag, all blocking events
+// are recorded, equivalent to -test.blockprofilerate=1.
+//
+// -coverprofile cover.out
+// Write a coverage profile to the file after all tests have passed.
+// Sets -cover.
+//
+// -cpuprofile cpu.out
+// Write a CPU profile to the specified file before exiting.
+// Writes test binary as -c would.
+//
+// -memprofile mem.out
+// Write a memory profile to the file after all tests have passed.
+// Writes test binary as -c would.
+//
+// -memprofilerate n
+// Enable more precise (and expensive) memory profiles by setting
+// runtime.MemProfileRate. See 'go doc runtime.MemProfileRate'.
+// To profile all memory allocations, use -test.memprofilerate=1
+// and pass --alloc_space flag to the pprof tool.
+//
+// -mutexprofile mutex.out
+// Write a mutex contention profile to the specified file
+// when all tests are complete.
+// Writes test binary as -c would.
+//
+// -mutexprofilefraction n
+// Sample 1 in n stack traces of goroutines holding a
+// contended mutex.
+//
+// -outputdir directory
+// Place output files from profiling in the specified directory,
+// by default the directory in which "go test" is running.
+//
+// -trace trace.out
+// Write an execution trace to the specified file before exiting.
+//
// Each of these flags is also recognized with an optional 'test.' prefix,
// as in -test.v. When invoking the generated test binary (the result of
// 'go test -c') directly, however, the prefix is mandatory.
@@ -1551,7 +1608,8 @@
// is compared exactly against the comment (see examples below). If the last
// comment begins with "Unordered output:" then the output is compared to the
// comment, however the order of the lines is ignored. An example with no such
-// comment, or with no text after "Output:" is compiled but not executed.
+// comment is compiled but not executed. An example with no text after
+// "Output:" is compiled, executed, and expected to produce no output.
//
// Godoc displays the body of ExampleXXX to demonstrate the use
// of the function, constant, or variable XXX. An example of a method M with
diff --git a/libgo/go/cmd/go/bootstrap.go b/libgo/go/cmd/go/bootstrap.go
index caa96769d84..2148d12685a 100644
--- a/libgo/go/cmd/go/bootstrap.go
+++ b/libgo/go/cmd/go/bootstrap.go
@@ -36,3 +36,6 @@ func httpsOrHTTP(importPath string, security securityMode) (string, io.ReadClose
func parseMetaGoImports(r io.Reader) ([]metaImport, error) {
panic("unreachable")
}
+
+func queryEscape(s string) string { panic("unreachable") }
+func openBrowser(url string) bool { panic("unreachable") }
diff --git a/libgo/go/cmd/go/bug.go b/libgo/go/cmd/go/bug.go
new file mode 100644
index 00000000000..cbd258b80bd
--- /dev/null
+++ b/libgo/go/cmd/go/bug.go
@@ -0,0 +1,213 @@
+// Copyright 2016 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 (
+ "bytes"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "os"
+ "os/exec"
+ "path/filepath"
+ "regexp"
+ "runtime"
+ "strings"
+)
+
+var cmdBug = &Command{
+ Run: runBug,
+ UsageLine: "bug",
+ Short: "print information for bug reports",
+ Long: `
+Bug prints information that helps file effective bug reports.
+
+Bugs may be reported at https://golang.org/issue/new.
+ `,
+}
+
+func init() {
+ cmdBug.Flag.BoolVar(&buildV, "v", false, "")
+}
+
+func runBug(cmd *Command, args []string) {
+ var buf bytes.Buffer
+ buf.WriteString(bugHeader)
+ inspectGoVersion(&buf)
+ fmt.Fprint(&buf, "#### System details\n\n")
+ fmt.Fprintln(&buf, "```")
+ fmt.Fprintf(&buf, "go version %s %s/%s\n", runtime.Version(), runtime.GOOS, runtime.GOARCH)
+ env := newEnv
+ env = append(env, extraEnvVars()...)
+ for _, e := range env {
+ // Hide the TERM environment variable from "go bug".
+ // See issue #18128
+ if e.name != "TERM" {
+ fmt.Fprintf(&buf, "%s=\"%s\"\n", e.name, e.value)
+ }
+ }
+ printGoDetails(&buf)
+ printOSDetails(&buf)
+ printCDetails(&buf)
+ fmt.Fprintln(&buf, "```")
+
+ body := buf.String()
+ url := "https://github.com/golang/go/issues/new?body=" + queryEscape(body)
+ if !openBrowser(url) {
+ fmt.Print("Please file a new issue at golang.org/issue/new using this template:\n\n")
+ fmt.Print(body)
+ }
+}
+
+const bugHeader = `Please answer these questions before submitting your issue. Thanks!
+
+#### What did you do?
+If possible, provide a recipe for reproducing the error.
+A complete runnable program is good.
+A link on play.golang.org is best.
+
+
+#### What did you expect to see?
+
+
+#### What did you see instead?
+
+
+`
+
+func printGoDetails(w io.Writer) {
+ printCmdOut(w, "GOROOT/bin/go version: ", filepath.Join(runtime.GOROOT(), "bin/go"), "version")
+ printCmdOut(w, "GOROOT/bin/go tool compile -V: ", filepath.Join(runtime.GOROOT(), "bin/go"), "tool", "compile", "-V")
+}
+
+func printOSDetails(w io.Writer) {
+ switch runtime.GOOS {
+ case "darwin":
+ printCmdOut(w, "uname -v: ", "uname", "-v")
+ printCmdOut(w, "", "sw_vers")
+ case "linux":
+ printCmdOut(w, "uname -sr: ", "uname", "-sr")
+ printCmdOut(w, "", "lsb_release", "-a")
+ printGlibcVersion(w)
+ case "openbsd", "netbsd", "freebsd", "dragonfly":
+ printCmdOut(w, "uname -v: ", "uname", "-v")
+ case "solaris":
+ out, err := ioutil.ReadFile("/etc/release")
+ if err == nil {
+ fmt.Fprintf(w, "/etc/release: %s\n", out)
+ } else {
+ if buildV {
+ fmt.Printf("failed to read /etc/release: %v\n", err)
+ }
+ }
+ }
+}
+
+func printCDetails(w io.Writer) {
+ printCmdOut(w, "lldb --version: ", "lldb", "--version")
+ cmd := exec.Command("gdb", "--version")
+ out, err := cmd.Output()
+ if err == nil {
+ // There's apparently no combination of command line flags
+ // to get gdb to spit out its version without the license and warranty.
+ // Print up to the first newline.
+ fmt.Fprintf(w, "gdb --version: %s\n", firstLine(out))
+ } else {
+ if buildV {
+ fmt.Printf("failed to run gdb --version: %v\n", err)
+ }
+ }
+}
+
+func inspectGoVersion(w io.Writer) {
+ data, err := httpGET("https://golang.org/VERSION?m=text")
+ if err != nil {
+ if buildV {
+ fmt.Printf("failed to read from golang.org/VERSION: %v\n", err)
+ }
+ return
+ }
+
+ // golang.org/VERSION currently returns a whitespace-free string,
+ // but just in case, protect against that changing.
+ // Similarly so for runtime.Version.
+ release := string(bytes.TrimSpace(data))
+ vers := strings.TrimSpace(runtime.Version())
+
+ if vers == release {
+ // Up to date
+ return
+ }
+
+ // Devel version or outdated release. Either way, this request is apropos.
+ fmt.Fprintf(w, "#### Does this issue reproduce with the latest release (%s)?\n\n\n", release)
+}
+
+// printCmdOut prints the output of running the given command.
+// It ignores failures; 'go bug' is best effort.
+func printCmdOut(w io.Writer, prefix, path string, args ...string) {
+ cmd := exec.Command(path, args...)
+ out, err := cmd.Output()
+ if err != nil {
+ if buildV {
+ fmt.Printf("%s %s: %v\n", path, strings.Join(args, " "), err)
+ }
+ return
+ }
+ fmt.Fprintf(w, "%s%s\n", prefix, bytes.TrimSpace(out))
+}
+
+// firstLine returns the first line of a given byte slice.
+func firstLine(buf []byte) []byte {
+ idx := bytes.IndexByte(buf, '\n')
+ if idx > 0 {
+ buf = buf[:idx]
+ }
+ return bytes.TrimSpace(buf)
+}
+
+// printGlibcVersion prints information about the glibc version.
+// It ignores failures.
+func printGlibcVersion(w io.Writer) {
+ tempdir := os.TempDir()
+ if tempdir == "" {
+ return
+ }
+ src := []byte(`int main() {}`)
+ srcfile := filepath.Join(tempdir, "go-bug.c")
+ outfile := filepath.Join(tempdir, "go-bug")
+ err := ioutil.WriteFile(srcfile, src, 0644)
+ if err != nil {
+ return
+ }
+ defer os.Remove(srcfile)
+ cmd := exec.Command("gcc", "-o", outfile, srcfile)
+ if _, err = cmd.CombinedOutput(); err != nil {
+ return
+ }
+ defer os.Remove(outfile)
+
+ cmd = exec.Command("ldd", outfile)
+ out, err := cmd.CombinedOutput()
+ if err != nil {
+ return
+ }
+ re := regexp.MustCompile(`libc\.so[^ ]* => ([^ ]+)`)
+ m := re.FindStringSubmatch(string(out))
+ if m == nil {
+ return
+ }
+ cmd = exec.Command(m[1])
+ out, err = cmd.Output()
+ if err != nil {
+ return
+ }
+ fmt.Fprintf(w, "%s: %s\n", m[1], firstLine(out))
+
+ // print another line (the one containing version string) in case of musl libc
+ if idx := bytes.IndexByte(out, '\n'); bytes.Index(out, []byte("musl")) != -1 && idx > -1 {
+ fmt.Fprintf(w, "%s\n", firstLine(out[idx+1:]))
+ }
+}
diff --git a/libgo/go/cmd/go/build.go b/libgo/go/cmd/go/build.go
index 10116f282f0..a8f90344c30 100644
--- a/libgo/go/cmd/go/build.go
+++ b/libgo/go/cmd/go/build.go
@@ -346,6 +346,13 @@ func buildModeInit() {
case "darwin/arm", "darwin/arm64":
codegenArg = "-shared"
default:
+ switch goos {
+ case "dragonfly", "freebsd", "linux", "netbsd", "openbsd", "solaris":
+ // Use -shared so that the result is
+ // suitable for inclusion in a PIE or
+ // shared library.
+ codegenArg = "-shared"
+ }
}
exeSuffix = ".a"
ldBuildmode = "c-archive"
@@ -407,6 +414,21 @@ func buildModeInit() {
fatalf("-buildmode=shared and -o not supported together")
}
ldBuildmode = "shared"
+ case "plugin":
+ pkgsFilter = pkgsMain
+ if gccgo {
+ codegenArg = "-fPIC"
+ } else {
+ switch platform {
+ case "linux/amd64", "linux/arm", "linux/arm64", "linux/386",
+ "android/amd64", "android/arm", "android/arm64", "android/386":
+ default:
+ fatalf("-buildmode=plugin not supported on %s\n", platform)
+ }
+ codegenArg = "-dynlink"
+ }
+ exeSuffix = ".so"
+ ldBuildmode = "plugin"
default:
fatalf("buildmode=%s not supported", buildBuildmode)
}
@@ -432,10 +454,13 @@ func buildModeInit() {
buildAsmflags = append(buildAsmflags, codegenArg)
buildGcflags = append(buildGcflags, codegenArg)
}
- if buildContext.InstallSuffix != "" {
- buildContext.InstallSuffix += "_"
+ // Don't alter InstallSuffix when modifying default codegen args.
+ if buildBuildmode != "default" || buildLinkshared {
+ if buildContext.InstallSuffix != "" {
+ buildContext.InstallSuffix += "_"
+ }
+ buildContext.InstallSuffix += codegenArg[1:]
}
- buildContext.InstallSuffix += codegenArg[1:]
}
}
@@ -452,6 +477,11 @@ func runBuild(cmd *Command, args []string) {
*buildO += exeSuffix
}
+ // Special case -o /dev/null by not writing at all.
+ if *buildO == os.DevNull {
+ *buildO = ""
+ }
+
// sanity check some often mis-used options
switch buildContext.Compiler {
case "gccgo":
@@ -580,6 +610,10 @@ func libname(args []string, pkgs []*Package) (string, error) {
}
func runInstall(cmd *Command, args []string) {
+ installPackages(args, false)
+}
+
+func installPackages(args []string, forGet bool) {
if gobin != "" && !filepath.IsAbs(gobin) {
fatalf("cannot install, GOBIN must be an absolute path")
}
@@ -599,7 +633,7 @@ func runInstall(cmd *Command, args []string) {
errorf("go install: no install location for %s: hidden by %s", p.Dir, p.ConflictDir)
default:
errorf("go install: no install location for directory %s outside GOPATH\n"+
- "\tFor more details see: go help gopath", p.Dir)
+ "\tFor more details see: 'go help gopath'", p.Dir)
}
}
}
@@ -607,6 +641,8 @@ func runInstall(cmd *Command, args []string) {
var b builder
b.init()
+ // Set the behavior for `go get` to not error on packages with test files only.
+ b.testFilesOnlyOK = forGet
var a *action
if buildBuildmode == "shared" {
if libName, err := libname(args, pkgs); err != nil {
@@ -697,6 +733,8 @@ type builder struct {
flagCache map[string]bool // a cache of supported compiler flags
print func(args ...interface{}) (int, error)
+ testFilesOnlyOK bool // do not error if the packages only have test files
+
output sync.Mutex
scriptDir string // current directory in printed script
@@ -1283,6 +1321,8 @@ func (b *builder) do(root *action) {
if err != nil {
if err == errPrintedOutput {
setExitStatus(2)
+ } else if _, ok := err.(*build.NoGoError); ok && len(a.p.TestGoFiles) > 0 && b.testFilesOnlyOK {
+ // Ignore the "no buildable Go source files" error for a package with only test files.
} else {
errorf("%s", err)
}
@@ -1369,7 +1409,7 @@ func (b *builder) build(a *action) (err error) {
}
defer func() {
- if err != nil && err != errPrintedOutput {
+ if _, ok := err.(*build.NoGoError); err != nil && err != errPrintedOutput && !(ok && b.testFilesOnlyOK && len(a.p.TestGoFiles) > 0) {
err = fmt.Errorf("go build %s: %v", a.p.ImportPath, err)
}
}()
@@ -1400,7 +1440,7 @@ func (b *builder) build(a *action) (err error) {
}
}
- var gofiles, cgofiles, cfiles, sfiles, cxxfiles, objects, cgoObjects, pcCFLAGS, pcLDFLAGS []string
+ var gofiles, cgofiles, objdirCgofiles, cfiles, sfiles, cxxfiles, objects, cgoObjects, pcCFLAGS, pcLDFLAGS []string
gofiles = append(gofiles, a.p.GoFiles...)
cgofiles = append(cgofiles, a.p.CgoFiles...)
@@ -1422,7 +1462,7 @@ func (b *builder) build(a *action) (err error) {
if err != nil {
return err
}
- cgofiles = append(cgofiles, outGo...)
+ objdirCgofiles = append(objdirCgofiles, outGo...)
cfiles = append(cfiles, outC...)
cxxfiles = append(cxxfiles, outCXX...)
}
@@ -1457,7 +1497,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, pcCFLAGS, pcLDFLAGS, cgofiles, gccfiles, cxxfiles, a.p.MFiles, a.p.FFiles)
+ outGo, outObj, err := b.cgo(a, cgoExe, obj, pcCFLAGS, pcLDFLAGS, cgofiles, objdirCgofiles, gccfiles, cxxfiles, a.p.MFiles, a.p.FFiles)
if err != nil {
return err
}
@@ -1555,12 +1595,12 @@ func (b *builder) build(a *action) (err error) {
}
// Assemble .s files.
- for _, file := range sfiles {
- out := file[:len(file)-len(".s")] + ".o"
- if err := buildToolchain.asm(b, a.p, obj, obj+out, file); err != nil {
+ if len(sfiles) > 0 {
+ ofiles, err := buildToolchain.asm(b, a.p, obj, sfiles)
+ if err != nil {
return err
}
- objects = append(objects, out)
+ objects = append(objects, ofiles...)
}
// NOTE(rsc): On Windows, it is critically important that the
@@ -1599,23 +1639,62 @@ func (b *builder) build(a *action) (err error) {
return nil
}
+// pkgconfigCmd returns a pkg-config binary name
+// defaultPkgConfig is defined in zdefaultcc.go, written by cmd/dist.
+func (b *builder) pkgconfigCmd() string {
+ return envList("PKG_CONFIG", defaultPkgConfig)[0]
+}
+
+// splitPkgConfigOutput parses the pkg-config output into a slice of
+// flags. pkg-config always uses \ to escape special characters.
+func splitPkgConfigOutput(out []byte) []string {
+ if len(out) == 0 {
+ return nil
+ }
+ var flags []string
+ flag := make([]byte, len(out))
+ r, w := 0, 0
+ for r < len(out) {
+ switch out[r] {
+ case ' ', '\t', '\r', '\n':
+ if w > 0 {
+ flags = append(flags, string(flag[:w]))
+ }
+ w = 0
+ case '\\':
+ r++
+ fallthrough
+ default:
+ if r < len(out) {
+ flag[w] = out[r]
+ w++
+ }
+ }
+ r++
+ }
+ if w > 0 {
+ flags = append(flags, string(flag[:w]))
+ }
+ return flags
+}
+
// Calls pkg-config if needed and returns the cflags/ldflags needed to build the package.
func (b *builder) getPkgConfigFlags(p *Package) (cflags, ldflags []string, err error) {
if pkgs := p.CgoPkgConfig; len(pkgs) > 0 {
var out []byte
- out, err = b.runOut(p.Dir, p.ImportPath, nil, "pkg-config", "--cflags", pkgs)
+ out, err = b.runOut(p.Dir, p.ImportPath, nil, b.pkgconfigCmd(), "--cflags", pkgs)
if err != nil {
- b.showOutput(p.Dir, "pkg-config --cflags "+strings.Join(pkgs, " "), string(out))
+ b.showOutput(p.Dir, b.pkgconfigCmd()+" --cflags "+strings.Join(pkgs, " "), string(out))
b.print(err.Error() + "\n")
err = errPrintedOutput
return
}
if len(out) > 0 {
- cflags = strings.Fields(string(out))
+ cflags = splitPkgConfigOutput(out)
}
- out, err = b.runOut(p.Dir, p.ImportPath, nil, "pkg-config", "--libs", pkgs)
+ out, err = b.runOut(p.Dir, p.ImportPath, nil, b.pkgconfigCmd(), "--libs", pkgs)
if err != nil {
- b.showOutput(p.Dir, "pkg-config --libs "+strings.Join(pkgs, " "), string(out))
+ b.showOutput(p.Dir, b.pkgconfigCmd()+" --libs "+strings.Join(pkgs, " "), string(out))
b.print(err.Error() + "\n")
err = errPrintedOutput
return
@@ -1656,7 +1735,7 @@ func (b *builder) install(a *action) (err error) {
perm := os.FileMode(0666)
if a1.link {
switch buildBuildmode {
- case "c-archive", "c-shared":
+ case "c-archive", "c-shared", "plugin":
default:
perm = 0777
}
@@ -2197,9 +2276,9 @@ type toolchain interface {
// cc runs the toolchain's C compiler in a directory on a C file
// to produce an output file.
cc(b *builder, p *Package, objdir, ofile, cfile string) error
- // asm runs the assembler in a specific directory on a specific file
- // to generate the named output file.
- asm(b *builder, p *Package, obj, ofile, sfile string) error
+ // asm runs the assembler in a specific directory on specific files
+ // and returns a list of named output files.
+ asm(b *builder, p *Package, obj string, sfiles []string) ([]string, error)
// pkgpath builds an appropriate path for a temporary package file.
pkgpath(basedir string, p *Package) string
// pack runs the archive packer in a specific directory to create
@@ -2236,8 +2315,8 @@ func (noToolchain) gc(b *builder, p *Package, archive, obj string, asmhdr bool,
return "", nil, noCompiler()
}
-func (noToolchain) asm(b *builder, p *Package, obj, ofile, sfile string) error {
- return noCompiler()
+func (noToolchain) asm(b *builder, p *Package, obj string, sfiles []string) ([]string, error) {
+ return nil, noCompiler()
}
func (noToolchain) pkgpath(basedir string, p *Package) string {
@@ -2342,11 +2421,10 @@ func (gcToolchain) gc(b *builder, p *Package, archive, obj string, asmhdr bool,
return ofile, output, err
}
-func (gcToolchain) asm(b *builder, p *Package, obj, ofile, sfile string) error {
+func (gcToolchain) asm(b *builder, p *Package, obj string, sfiles []string) ([]string, error) {
// Add -I pkg/GOOS_GOARCH so #include "textflag.h" works in .s files.
inc := filepath.Join(goroot, "pkg", "include")
- sfile = mkAbs(p.Dir, sfile)
- args := []interface{}{buildToolExec, tool("asm"), "-o", ofile, "-trimpath", b.work, "-I", obj, "-I", inc, "-D", "GOOS_" + goos, "-D", "GOARCH_" + goarch, buildAsmflags}
+ args := []interface{}{buildToolExec, tool("asm"), "-trimpath", b.work, "-I", obj, "-I", inc, "-D", "GOOS_" + goos, "-D", "GOARCH_" + goarch, buildAsmflags}
if p.ImportPath == "runtime" && goarch == "386" {
for _, arg := range buildAsmflags {
if arg == "-dynlink" {
@@ -2354,11 +2432,16 @@ func (gcToolchain) asm(b *builder, p *Package, obj, ofile, sfile string) error {
}
}
}
- args = append(args, sfile)
- if err := b.run(p.Dir, p.ImportPath, nil, args...); err != nil {
- return err
+ var ofiles []string
+ for _, sfile := range sfiles {
+ ofile := obj + sfile[:len(sfile)-len(".s")] + ".o"
+ ofiles = append(ofiles, ofile)
+ a := append(args, "-o", ofile, mkAbs(p.Dir, sfile))
+ if err := b.run(p.Dir, p.ImportPath, nil, a...); err != nil {
+ return nil, err
+ }
}
- return nil
+ return ofiles, nil
}
// toolVerify checks that the command line args writes the same output file
@@ -2516,6 +2599,13 @@ func (gcToolchain) ld(b *builder, root *action, out string, allactions []*action
if root.p.omitDWARF {
ldflags = append(ldflags, "-w")
}
+ if buildBuildmode == "plugin" {
+ pluginpath := root.p.ImportPath
+ if pluginpath == "command-line-arguments" {
+ pluginpath = "plugin/unnamed-" + root.p.buildID
+ }
+ ldflags = append(ldflags, "-pluginpath", pluginpath)
+ }
// If the user has not specified the -extld option, then specify the
// appropriate linker. In case of C++ code, use the compiler named
@@ -2625,15 +2715,24 @@ func (tools gccgoToolchain) gc(b *builder, p *Package, archive, obj string, asmh
return ofile, output, err
}
-func (tools gccgoToolchain) asm(b *builder, p *Package, obj, ofile, sfile string) error {
- sfile = mkAbs(p.Dir, sfile)
- defs := []string{"-D", "GOOS_" + goos, "-D", "GOARCH_" + goarch}
- if pkgpath := gccgoCleanPkgpath(p); pkgpath != "" {
- defs = append(defs, `-D`, `GOPKGPATH=`+pkgpath)
+func (tools gccgoToolchain) asm(b *builder, p *Package, obj string, sfiles []string) ([]string, error) {
+ var ofiles []string
+ for _, sfile := range sfiles {
+ ofile := obj + sfile[:len(sfile)-len(".s")] + ".o"
+ ofiles = append(ofiles, ofile)
+ sfile = mkAbs(p.Dir, sfile)
+ defs := []string{"-D", "GOOS_" + goos, "-D", "GOARCH_" + goarch}
+ if pkgpath := gccgoCleanPkgpath(p); pkgpath != "" {
+ defs = append(defs, `-D`, `GOPKGPATH=`+pkgpath)
+ }
+ defs = tools.maybePIC(defs)
+ defs = append(defs, b.gccArchArgs()...)
+ err := b.run(p.Dir, p.ImportPath, nil, tools.compiler(), "-xassembler-with-cpp", "-I", obj, "-c", "-o", ofile, defs, sfile)
+ if err != nil {
+ return nil, err
+ }
}
- defs = tools.maybePIC(defs)
- defs = append(defs, b.gccArchArgs()...)
- return b.run(p.Dir, p.ImportPath, nil, tools.compiler(), "-xassembler-with-cpp", "-I", obj, "-c", "-o", ofile, defs, sfile)
+ return ofiles, nil
}
func (gccgoToolchain) pkgpath(basedir string, p *Package) string {
@@ -2755,7 +2854,7 @@ func (tools gccgoToolchain) link(b *builder, root *action, out string, allaction
if !apackagePathsSeen[a.p.ImportPath] {
apackagePathsSeen[a.p.ImportPath] = true
target := a.target
- if len(a.p.CgoFiles) > 0 {
+ if len(a.p.CgoFiles) > 0 || a.p.usesSwig() {
target, err = readAndRemoveCgoFlags(target)
if err != nil {
return
@@ -2947,7 +3046,7 @@ func (tools gccgoToolchain) cc(b *builder, p *Package, objdir, ofile, cfile stri
// maybePIC adds -fPIC to the list of arguments if needed.
func (tools gccgoToolchain) maybePIC(args []string) []string {
switch buildBuildmode {
- case "c-shared", "shared":
+ case "c-shared", "shared", "plugin":
args = append(args, "-fPIC")
}
return args
@@ -2988,9 +3087,19 @@ func (b *builder) gfortran(p *Package, out string, flags []string, ffile string)
}
// ccompile runs the given C or C++ compiler and creates an object from a single source file.
-func (b *builder) ccompile(p *Package, out string, flags []string, file string, compiler []string) error {
+func (b *builder) ccompile(p *Package, outfile string, flags []string, file string, compiler []string) error {
file = mkAbs(p.Dir, file)
- return b.run(p.Dir, p.ImportPath, nil, compiler, flags, "-o", out, "-c", file)
+ desc := p.ImportPath
+ output, err := b.runOut(p.Dir, desc, nil, compiler, flags, "-o", outfile, "-c", file)
+ if len(output) > 0 {
+ b.showOutput(p.Dir, desc, b.processOutput(output))
+ if err != nil {
+ err = errPrintedOutput
+ } else if os.Getenv("GO_BUILDER_NAME") != "" {
+ return errors.New("C compiler warning promoted to error on Go builders")
+ }
+ }
+ return err
}
// gccld runs the gcc linker to create an executable from a set of object files.
@@ -3129,6 +3238,8 @@ func (b *builder) gccArchArgs() []string {
return []string{"-m64", "-march=z196"}
case "mips64", "mips64le":
return []string{"-mabi=64"}
+ case "mips", "mipsle":
+ return []string{"-mabi=32", "-march=mips32"}
}
return nil
}
@@ -3144,11 +3255,8 @@ func envList(key, def string) []string {
}
// Return the flags to use when invoking the C, C++ or Fortran compilers, or cgo.
-func (b *builder) cflags(p *Package, def bool) (cppflags, cflags, cxxflags, fflags, ldflags []string) {
- var defaults string
- if def {
- defaults = "-g -O2"
- }
+func (b *builder) cflags(p *Package) (cppflags, cflags, cxxflags, fflags, ldflags []string) {
+ defaults := "-g -O2"
cppflags = stringList(envList("CGO_CPPFLAGS", ""), p.CgoCPPFLAGS)
cflags = stringList(envList("CGO_CFLAGS", defaults), p.CgoCFLAGS)
@@ -3160,9 +3268,9 @@ func (b *builder) cflags(p *Package, def bool) (cppflags, cflags, cxxflags, ffla
var cgoRe = regexp.MustCompile(`[/\\:]`)
-func (b *builder) cgo(p *Package, cgoExe, obj string, pcCFLAGS, pcLDFLAGS, cgofiles, gccfiles, gxxfiles, mfiles, ffiles []string) (outGo, outObj []string, err error) {
- cgoCPPFLAGS, cgoCFLAGS, cgoCXXFLAGS, cgoFFLAGS, cgoLDFLAGS := b.cflags(p, true)
- _, cgoexeCFLAGS, _, _, _ := b.cflags(p, false)
+func (b *builder) cgo(a *action, cgoExe, obj string, pcCFLAGS, pcLDFLAGS, cgofiles, objdirCgofiles, gccfiles, gxxfiles, mfiles, ffiles []string) (outGo, outObj []string, err error) {
+ p := a.p
+ cgoCPPFLAGS, cgoCFLAGS, cgoCXXFLAGS, cgoFFLAGS, cgoLDFLAGS := b.cflags(p)
cgoCPPFLAGS = append(cgoCPPFLAGS, pcCFLAGS...)
cgoLDFLAGS = append(cgoLDFLAGS, pcLDFLAGS...)
// If we are compiling Objective-C code, then we need to link against libobjc
@@ -3183,7 +3291,7 @@ func (b *builder) cgo(p *Package, cgoExe, obj string, pcCFLAGS, pcLDFLAGS, cgofi
}
}
- if buildMSan && p.ImportPath != "runtime/cgo" {
+ if buildMSan {
cgoCFLAGS = append([]string{"-fsanitize=memory"}, cgoCFLAGS...)
cgoLDFLAGS = append([]string{"-fsanitize=memory"}, cgoLDFLAGS...)
}
@@ -3191,20 +3299,33 @@ func (b *builder) cgo(p *Package, cgoExe, obj string, pcCFLAGS, pcLDFLAGS, cgofi
// Allows including _cgo_export.h from .[ch] files in the package.
cgoCPPFLAGS = append(cgoCPPFLAGS, "-I", obj)
+ // If we have cgo files in the object directory, then copy any
+ // other cgo files into the object directory, and pass a
+ // -srcdir option to cgo.
+ var srcdirarg []string
+ if len(objdirCgofiles) > 0 {
+ for _, fn := range cgofiles {
+ if err := b.copyFile(a, obj+filepath.Base(fn), filepath.Join(p.Dir, fn), 0666, false); err != nil {
+ return nil, nil, err
+ }
+ }
+ cgofiles = append(cgofiles, objdirCgofiles...)
+ srcdirarg = []string{"-srcdir", obj}
+ }
+
// cgo
// TODO: CGO_FLAGS?
gofiles := []string{obj + "_cgo_gotypes.go"}
- cfiles := []string{"_cgo_main.c", "_cgo_export.c"}
+ cfiles := []string{"_cgo_export.c"}
for _, fn := range cgofiles {
f := cgoRe.ReplaceAllString(fn[:len(fn)-2], "_")
gofiles = append(gofiles, obj+f+"cgo1.go")
cfiles = append(cfiles, f+"cgo2.c")
}
- defunC := obj + "_cgo_defun.c"
- cgoflags := []string{}
// TODO: make cgo not depend on $GOARCH?
+ cgoflags := []string{}
if p.Standard && p.ImportPath == "runtime/cgo" {
cgoflags = append(cgoflags, "-import_runtime_cgo=false")
}
@@ -3241,165 +3362,166 @@ func (b *builder) cgo(p *Package, cgoExe, obj string, pcCFLAGS, pcLDFLAGS, cgofi
cgoflags = append(cgoflags, "-exportheader="+obj+"_cgo_install.h")
}
- if err := b.run(p.Dir, p.ImportPath, cgoenv, buildToolExec, cgoExe, "-objdir", obj, "-importpath", p.ImportPath, cgoflags, "--", cgoCPPFLAGS, cgoexeCFLAGS, cgofiles); err != nil {
+ if err := b.run(p.Dir, p.ImportPath, cgoenv, buildToolExec, cgoExe, srcdirarg, "-objdir", obj, "-importpath", p.ImportPath, cgoflags, "--", cgoCPPFLAGS, cgoCFLAGS, cgofiles); err != nil {
return nil, nil, err
}
outGo = append(outGo, gofiles...)
- // cc _cgo_defun.c
- _, gccgo := buildToolchain.(gccgoToolchain)
- if gccgo {
- defunObj := obj + "_cgo_defun.o"
- if err := buildToolchain.cc(b, p, obj, defunObj, defunC); err != nil {
- return nil, nil, err
- }
- outObj = append(outObj, defunObj)
- }
-
// gcc
- var linkobj []string
-
- var bareLDFLAGS []string
- // When linking relocatable objects, various flags need to be
- // filtered out as they are inapplicable and can cause some linkers
- // to fail.
- for i := 0; i < len(cgoLDFLAGS); i++ {
- f := cgoLDFLAGS[i]
- switch {
- // skip "-lc" or "-l somelib"
- case strings.HasPrefix(f, "-l"):
- if f == "-l" {
- i++
- }
- // skip "-framework X" on Darwin
- case goos == "darwin" && f == "-framework":
- i++
- // skip "*.{dylib,so,dll}"
- case strings.HasSuffix(f, ".dylib"),
- strings.HasSuffix(f, ".so"),
- strings.HasSuffix(f, ".dll"):
- // Remove any -fsanitize=foo flags.
- // Otherwise the compiler driver thinks that we are doing final link
- // and links sanitizer runtime into the object file. But we are not doing
- // the final link, we will link the resulting object file again. And
- // so the program ends up with two copies of sanitizer runtime.
- // See issue 8788 for details.
- case strings.HasPrefix(f, "-fsanitize="):
- continue
- // runpath flags not applicable unless building a shared
- // object or executable; see issue 12115 for details. This
- // is necessary as Go currently does not offer a way to
- // specify the set of LDFLAGS that only apply to shared
- // objects.
- case strings.HasPrefix(f, "-Wl,-rpath"):
- if f == "-Wl,-rpath" || f == "-Wl,-rpath-link" {
- // Skip following argument to -rpath* too.
- i++
- }
- default:
- bareLDFLAGS = append(bareLDFLAGS, f)
- }
- }
-
- var staticLibs []string
- if goos == "windows" {
- // libmingw32 and libmingwex have some inter-dependencies,
- // so must use linker groups.
- staticLibs = []string{"-Wl,--start-group", "-lmingwex", "-lmingw32", "-Wl,--end-group"}
- }
-
cflags := stringList(cgoCPPFLAGS, cgoCFLAGS)
for _, cfile := range cfiles {
ofile := obj + cfile[:len(cfile)-1] + "o"
if err := b.gcc(p, ofile, cflags, obj+cfile); err != nil {
return nil, nil, err
}
- linkobj = append(linkobj, ofile)
- if !strings.HasSuffix(ofile, "_cgo_main.o") {
- outObj = append(outObj, ofile)
- }
+ outObj = append(outObj, ofile)
}
for _, file := range gccfiles {
- ofile := obj + cgoRe.ReplaceAllString(file[:len(file)-1], "_") + "o"
+ base := filepath.Base(file)
+ ofile := obj + cgoRe.ReplaceAllString(base[:len(base)-1], "_") + "o"
if err := b.gcc(p, ofile, cflags, file); err != nil {
return nil, nil, err
}
- linkobj = append(linkobj, ofile)
outObj = append(outObj, ofile)
}
cxxflags := stringList(cgoCPPFLAGS, cgoCXXFLAGS)
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"
+ ofile := obj + cgoRe.ReplaceAllString(filepath.Base(file), "_") + ".o"
if err := b.gxx(p, ofile, cxxflags, file); err != nil {
return nil, nil, err
}
- linkobj = append(linkobj, ofile)
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"
+ ofile := obj + cgoRe.ReplaceAllString(filepath.Base(file), "_") + ".o"
if err := b.gcc(p, ofile, cflags, file); err != nil {
return nil, nil, err
}
- linkobj = append(linkobj, ofile)
outObj = append(outObj, ofile)
}
fflags := stringList(cgoCPPFLAGS, cgoFFLAGS)
for _, file := range ffiles {
// Append .o to the file, just in case the pkg has file.c and file.f
- ofile := obj + cgoRe.ReplaceAllString(file, "_") + ".o"
+ ofile := obj + cgoRe.ReplaceAllString(filepath.Base(file), "_") + ".o"
if err := b.gfortran(p, ofile, fflags, file); err != nil {
return nil, nil, err
}
- linkobj = append(linkobj, ofile)
outObj = append(outObj, ofile)
}
- linkobj = append(linkobj, p.SysoFiles...)
- dynobj := obj + "_cgo_.o"
- pie := (goarch == "arm" && goos == "linux") || goos == "android"
- if pie { // we need to use -pie for Linux/ARM to get accurate imported sym
- cgoLDFLAGS = append(cgoLDFLAGS, "-pie")
- }
- if err := b.gccld(p, dynobj, cgoLDFLAGS, linkobj); err != nil {
- return nil, nil, err
+ switch buildToolchain.(type) {
+ case gcToolchain:
+ importGo := obj + "_cgo_import.go"
+ if err := b.dynimport(p, obj, importGo, cgoExe, cflags, cgoLDFLAGS, outObj); err != nil {
+ return nil, nil, err
+ }
+ outGo = append(outGo, importGo)
+
+ ofile := obj + "_all.o"
+ if err := b.collect(p, obj, ofile, cgoLDFLAGS, outObj); err != nil {
+ return nil, nil, err
+ }
+ outObj = []string{ofile}
+
+ case gccgoToolchain:
+ defunC := obj + "_cgo_defun.c"
+ defunObj := obj + "_cgo_defun.o"
+ if err := buildToolchain.cc(b, p, obj, defunObj, defunC); err != nil {
+ return nil, nil, err
+ }
+ outObj = append(outObj, defunObj)
+
+ default:
+ noCompiler()
}
- if pie { // but we don't need -pie for normal cgo programs
- cgoLDFLAGS = cgoLDFLAGS[0 : len(cgoLDFLAGS)-1]
+
+ return outGo, outObj, nil
+}
+
+// dynimport creates a Go source file named importGo containing
+// //go:cgo_import_dynamic directives for each symbol or library
+// dynamically imported by the object files outObj.
+func (b *builder) dynimport(p *Package, obj, importGo, cgoExe string, cflags, cgoLDFLAGS, outObj []string) error {
+ cfile := obj + "_cgo_main.c"
+ ofile := obj + "_cgo_main.o"
+ if err := b.gcc(p, ofile, cflags, cfile); err != nil {
+ return err
}
- if _, ok := buildToolchain.(gccgoToolchain); ok {
- // we don't use dynimport when using gccgo.
- return outGo, outObj, nil
+ linkobj := stringList(ofile, outObj, p.SysoFiles)
+ dynobj := obj + "_cgo_.o"
+
+ // we need to use -pie for Linux/ARM to get accurate imported sym
+ ldflags := cgoLDFLAGS
+ if (goarch == "arm" && goos == "linux") || goos == "android" {
+ ldflags = append(ldflags, "-pie")
+ }
+ if err := b.gccld(p, dynobj, ldflags, linkobj); err != nil {
+ return err
}
// cgo -dynimport
- importGo := obj + "_cgo_import.go"
- cgoflags = []string{}
+ var cgoflags []string
if p.Standard && p.ImportPath == "runtime/cgo" {
- cgoflags = append(cgoflags, "-dynlinker") // record path to dynamic linker
- }
- if err := b.run(p.Dir, p.ImportPath, nil, buildToolExec, cgoExe, "-objdir", obj, "-dynpackage", p.Name, "-dynimport", dynobj, "-dynout", importGo, cgoflags); err != nil {
- return nil, nil, err
+ cgoflags = []string{"-dynlinker"} // record path to dynamic linker
}
- outGo = append(outGo, importGo)
+ return b.run(p.Dir, p.ImportPath, nil, buildToolExec, cgoExe, "-dynpackage", p.Name, "-dynimport", dynobj, "-dynout", importGo, cgoflags)
+}
- ofile := obj + "_all.o"
- var gccObjs, nonGccObjs []string
- for _, f := range outObj {
- if strings.HasSuffix(f, ".o") {
- gccObjs = append(gccObjs, f)
- } else {
- nonGccObjs = append(nonGccObjs, f)
+// collect partially links the object files outObj into a single
+// relocatable object file named ofile.
+func (b *builder) collect(p *Package, obj, ofile string, cgoLDFLAGS, outObj []string) error {
+ // When linking relocatable objects, various flags need to be
+ // filtered out as they are inapplicable and can cause some linkers
+ // to fail.
+ var ldflags []string
+ for i := 0; i < len(cgoLDFLAGS); i++ {
+ f := cgoLDFLAGS[i]
+ switch {
+ // skip "-lc" or "-l somelib"
+ case strings.HasPrefix(f, "-l"):
+ if f == "-l" {
+ i++
+ }
+ // skip "-framework X" on Darwin
+ case goos == "darwin" && f == "-framework":
+ i++
+ // skip "*.{dylib,so,dll,o,a}"
+ case strings.HasSuffix(f, ".dylib"),
+ strings.HasSuffix(f, ".so"),
+ strings.HasSuffix(f, ".dll"),
+ strings.HasSuffix(f, ".o"),
+ strings.HasSuffix(f, ".a"):
+ // Remove any -fsanitize=foo flags.
+ // Otherwise the compiler driver thinks that we are doing final link
+ // and links sanitizer runtime into the object file. But we are not doing
+ // the final link, we will link the resulting object file again. And
+ // so the program ends up with two copies of sanitizer runtime.
+ // See issue 8788 for details.
+ case strings.HasPrefix(f, "-fsanitize="):
+ continue
+ // runpath flags not applicable unless building a shared
+ // object or executable; see issue 12115 for details. This
+ // is necessary as Go currently does not offer a way to
+ // specify the set of LDFLAGS that only apply to shared
+ // objects.
+ case strings.HasPrefix(f, "-Wl,-rpath"):
+ if f == "-Wl,-rpath" || f == "-Wl,-rpath-link" {
+ // Skip following argument to -rpath* too.
+ i++
+ }
+ default:
+ ldflags = append(ldflags, f)
}
}
- ldflags := stringList(bareLDFLAGS, "-Wl,-r", "-nostdlib", staticLibs)
+
+ ldflags = append(ldflags, "-Wl,-r", "-nostdlib")
if b.gccSupportsNoPie() {
ldflags = append(ldflags, "-no-pie")
@@ -3408,16 +3530,7 @@ func (b *builder) cgo(p *Package, cgoExe, obj string, pcCFLAGS, pcLDFLAGS, cgofi
// We are creating an object file, so we don't want a build ID.
ldflags = b.disableBuildID(ldflags)
- if err := b.gccld(p, ofile, ldflags, gccObjs); err != nil {
- return nil, nil, err
- }
-
- // NOTE(rsc): The importObj is a 5c/6c/8c object and on Windows
- // must be processed before the gcc-generated objects.
- // Put it first. https://golang.org/issue/2601
- outObj = stringList(nonGccObjs, ofile)
-
- return outGo, outObj, nil
+ return b.gccld(p, ofile, ldflags, outObj)
}
// Run SWIG on all SWIG input files.
@@ -3570,7 +3683,7 @@ func (b *builder) swigIntSize(obj string) (intsize string, err error) {
// Run SWIG on one SWIG input file.
func (b *builder) swigOne(p *Package, file, obj string, pcCFLAGS []string, cxx bool, intgosize string) (outGo, outC string, err error) {
- cgoCPPFLAGS, cgoCFLAGS, cgoCXXFLAGS, _, _ := b.cflags(p, true)
+ cgoCPPFLAGS, cgoCFLAGS, cgoCXXFLAGS, _, _ := b.cflags(p)
var cflags []string
if cxx {
cflags = stringList(cgoCPPFLAGS, pcCFLAGS, cgoCXXFLAGS)
@@ -3633,7 +3746,7 @@ func (b *builder) swigOne(p *Package, file, obj string, pcCFLAGS []string, cxx b
b.showOutput(p.Dir, p.ImportPath, b.processOutput(out)) // swig warning
}
- return obj + goFile, obj + gccBase + gccExt, nil
+ return goFile, obj + gccBase + gccExt, nil
}
// disableBuildID adjusts a linker command line to avoid creating a
@@ -3682,7 +3795,11 @@ func instrumentInit() {
return
}
if buildRace && buildMSan {
- fmt.Fprintf(os.Stderr, "go %s: may not use -race and -msan simultaneously", flag.Args()[0])
+ fmt.Fprintf(os.Stderr, "go %s: may not use -race and -msan simultaneously\n", flag.Args()[0])
+ os.Exit(2)
+ }
+ if buildMSan && (goos != "linux" || goarch != "amd64") {
+ fmt.Fprintf(os.Stderr, "-msan is not supported on %s/%s\n", goos, goarch)
os.Exit(2)
}
if goarch != "amd64" || goos != "linux" && goos != "freebsd" && goos != "darwin" && goos != "windows" {
diff --git a/libgo/go/cmd/go/build_test.go b/libgo/go/cmd/go/build_test.go
new file mode 100644
index 00000000000..79bbd545915
--- /dev/null
+++ b/libgo/go/cmd/go/build_test.go
@@ -0,0 +1,44 @@
+// Copyright 2016 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 (
+ "os"
+ "reflect"
+ "testing"
+)
+
+func TestRemoveDevNull(t *testing.T) {
+ fi, err := os.Lstat(os.DevNull)
+ if err != nil {
+ t.Skip(err)
+ }
+ if fi.Mode().IsRegular() {
+ t.Errorf("Lstat(%s).Mode().IsRegular() = true; expected false", os.DevNull)
+ }
+ mayberemovefile(os.DevNull)
+ _, err = os.Lstat(os.DevNull)
+ if err != nil {
+ t.Errorf("mayberemovefile(%s) did remove it; oops", os.DevNull)
+ }
+}
+
+func TestSplitPkgConfigOutput(t *testing.T) {
+ for _, test := range []struct {
+ in []byte
+ want []string
+ }{
+ {[]byte(`-r:foo -L/usr/white\ space/lib -lfoo\ bar -lbar\ baz`), []string{"-r:foo", "-L/usr/white space/lib", "-lfoo bar", "-lbar baz"}},
+ {[]byte(`-lextra\ fun\ arg\\`), []string{`-lextra fun arg\`}},
+ {[]byte(`broken flag\`), []string{"broken", "flag"}},
+ {[]byte("\textra whitespace\r\n"), []string{"extra", "whitespace"}},
+ {[]byte(" \r\n "), nil},
+ } {
+ got := splitPkgConfigOutput(test.in)
+ if !reflect.DeepEqual(got, test.want) {
+ t.Errorf("splitPkgConfigOutput(%v) = %v; want %v", test.in, got, test.want)
+ }
+ }
+}
diff --git a/libgo/go/cmd/go/env.go b/libgo/go/cmd/go/env.go
index 8aaaf463292..31710b7e6d6 100644
--- a/libgo/go/cmd/go/env.go
+++ b/libgo/go/cmd/go/env.go
@@ -40,7 +40,7 @@ func mkEnv() []envVar {
{"GOHOSTARCH", runtime.GOARCH},
{"GOHOSTOS", runtime.GOOS},
{"GOOS", goos},
- {"GOPATH", os.Getenv("GOPATH")},
+ {"GOPATH", buildContext.GOPATH},
{"GORACE", os.Getenv("GORACE")},
{"GOROOT", goroot},
{"GOTOOLDIR", toolDir},
@@ -49,14 +49,25 @@ func mkEnv() []envVar {
{"TERM", "dumb"},
}
- if goos != "plan9" {
- cmd := b.gccCmd(".")
- env = append(env, envVar{"CC", cmd[0]})
- env = append(env, envVar{"GOGCCFLAGS", strings.Join(cmd[3:], " ")})
- cmd = b.gxxCmd(".")
- env = append(env, envVar{"CXX", cmd[0]})
+ if gccgoBin != "" {
+ env = append(env, envVar{"GCCGO", gccgoBin})
+ } else {
+ env = append(env, envVar{"GCCGO", gccgoName})
+ }
+
+ switch goarch {
+ case "arm":
+ env = append(env, envVar{"GOARM", os.Getenv("GOARM")})
+ case "386":
+ env = append(env, envVar{"GO386", os.Getenv("GO386")})
}
+ cmd := b.gccCmd(".")
+ env = append(env, envVar{"CC", cmd[0]})
+ env = append(env, envVar{"GOGCCFLAGS", strings.Join(cmd[3:], " ")})
+ cmd = b.gxxCmd(".")
+ env = append(env, envVar{"CXX", cmd[0]})
+
if buildContext.CgoEnabled {
env = append(env, envVar{"CGO_ENABLED", "1"})
} else {
@@ -75,8 +86,24 @@ func findEnv(env []envVar, name string) string {
return ""
}
+// extraEnvVars returns environment variables that should not leak into child processes.
+func extraEnvVars() []envVar {
+ var b builder
+ b.init()
+ cppflags, cflags, cxxflags, fflags, ldflags := b.cflags(&Package{})
+ return []envVar{
+ {"PKG_CONFIG", b.pkgconfigCmd()},
+ {"CGO_CFLAGS", strings.Join(cflags, " ")},
+ {"CGO_CPPFLAGS", strings.Join(cppflags, " ")},
+ {"CGO_CXXFLAGS", strings.Join(cxxflags, " ")},
+ {"CGO_FFLAGS", strings.Join(fflags, " ")},
+ {"CGO_LDFLAGS", strings.Join(ldflags, " ")},
+ }
+}
+
func runEnv(cmd *Command, args []string) {
- env := mkEnv()
+ env := newEnv
+ env = append(env, extraEnvVars()...)
if len(args) > 0 {
for _, name := range args {
fmt.Printf("%s\n", findEnv(env, name))
diff --git a/libgo/go/cmd/go/generate.go b/libgo/go/cmd/go/generate.go
index 3c6065e89aa..2d92a0c100c 100644
--- a/libgo/go/cmd/go/generate.go
+++ b/libgo/go/cmd/go/generate.go
@@ -25,7 +25,7 @@ var cmdGenerate = &Command{
Long: `
Generate runs commands described by directives within existing
files. Those commands can run any process but the intent is to
-create or update Go source files, for instance by running yacc.
+create or update Go source files.
Go generate is never run automatically by go build, go get, go test,
and so on. It must be run explicitly.
@@ -88,10 +88,10 @@ string xxx represents the command identified by the arguments. This
can be used to create aliases or to handle multiword generators.
For example,
- //go:generate -command yacc go tool yacc
+ //go:generate -command foo go tool foo
-specifies that the command "yacc" represents the generator
-"go tool yacc".
+specifies that the command "foo" represents the generator
+"go tool foo".
Generate processes packages in the order given on the command line,
one at a time. If the command line lists .go files, they are treated
@@ -136,6 +136,8 @@ func init() {
}
func runGenerate(cmd *Command, args []string) {
+ ignoreImports = true
+
if generateRunFlag != "" {
var err error
generateRunRE, err = regexp.Compile(generateRunFlag)
diff --git a/libgo/go/cmd/go/get.go b/libgo/go/cmd/go/get.go
index 19858f7e55d..1d7677c615c 100644
--- a/libgo/go/cmd/go/get.go
+++ b/libgo/go/cmd/go/get.go
@@ -43,11 +43,13 @@ 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.
+The -v flag enables verbose progress and debug output.
+
Get also accepts build flags to control the installation. See 'go help build'.
When checking out a new package, get creates the target directory
GOPATH/src/<import-path>. If the GOPATH contains multiple entries,
-get uses the first one. See 'go help gopath'.
+get uses the first one. For more details see: 'go help gopath'.
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
@@ -96,13 +98,31 @@ func runGet(cmd *Command, args []string) {
os.Setenv("GIT_TERMINAL_PROMPT", "0")
}
+ // Disable any ssh connection pooling by Git.
+ // If a Git subprocess forks a child into the background to cache a new connection,
+ // that child keeps stdout/stderr open. After the Git subprocess exits,
+ // os /exec expects to be able to read from the stdout/stderr pipe
+ // until EOF to get all the data that the Git subprocess wrote before exiting.
+ // The EOF doesn't come until the child exits too, because the child
+ // is holding the write end of the pipe.
+ // This is unfortunate, but it has come up at least twice
+ // (see golang.org/issue/13453 and golang.org/issue/16104)
+ // and confuses users when it does.
+ // If the user has explicitly set GIT_SSH or GIT_SSH_COMMAND,
+ // assume they know what they are doing and don't step on it.
+ // But default to turning off ControlMaster.
+ if os.Getenv("GIT_SSH") == "" && os.Getenv("GIT_SSH_COMMAND") == "" {
+ os.Setenv("GIT_SSH_COMMAND", "ssh -o ControlMaster=no")
+ }
+
// Phase 1. Download/update.
var stk importStack
mode := 0
if *getT {
mode |= getTestDeps
}
- for _, arg := range downloadPaths(args) {
+ args = downloadPaths(args)
+ for _, arg := range args {
download(arg, nil, &stk, mode)
}
exitIfErrors()
@@ -137,7 +157,7 @@ func runGet(cmd *Command, args []string) {
return
}
- runInstall(cmd, args)
+ installPackages(args, true)
}
// downloadPaths prepares the list of paths to pass to download.
@@ -177,7 +197,7 @@ var downloadCache = map[string]bool{}
// downloadRootCache records the version control repository
// root directories we have already considered during the download.
-// For example, all the packages in the code.google.com/p/codesearch repo
+// For example, all the packages in the github.com/google/codesearch repo
// share the same root (the directory for that path), and we only need
// to run the hg commands to consider each repository once.
var downloadRootCache = map[string]bool{}
@@ -185,6 +205,10 @@ var downloadRootCache = map[string]bool{}
// download runs the download half of the get command
// for the package named by the argument.
func download(arg string, parent *Package, stk *importStack, mode int) {
+ if mode&useVendor != 0 {
+ // Caller is responsible for expanding vendor paths.
+ panic("internal error: download mode has useVendor set")
+ }
load := func(path string, mode int) *Package {
if parent == nil {
return loadPackage(path, stk)
@@ -295,32 +319,42 @@ func download(arg string, parent *Package, stk *importStack, mode int) {
}
// Process dependencies, now that we know what they are.
- for _, path := range p.Imports {
+ imports := p.Imports
+ if mode&getTestDeps != 0 {
+ // Process test dependencies when -t is specified.
+ // (But don't get test dependencies for test dependencies:
+ // we always pass mode 0 to the recursive calls below.)
+ imports = stringList(imports, p.TestImports, p.XTestImports)
+ }
+ for i, path := range imports {
if path == "C" {
continue
}
- // Don't get test dependencies recursively.
- // Imports is already vendor-expanded.
- download(path, p, stk, 0)
- }
- if mode&getTestDeps != 0 {
- // Process test dependencies when -t is specified.
- // (Don't get test dependencies for test dependencies.)
- // We pass useVendor here because p.load does not
- // vendor-expand TestImports and XTestImports.
- // The call to loadImport inside download needs to do that.
- for _, path := range p.TestImports {
- if path == "C" {
- continue
- }
- download(path, p, stk, useVendor)
+ // Fail fast on import naming full vendor path.
+ // Otherwise expand path as needed for test imports.
+ // Note that p.Imports can have additional entries beyond p.build.Imports.
+ orig := path
+ if i < len(p.build.Imports) {
+ orig = p.build.Imports[i]
}
- for _, path := range p.XTestImports {
- if path == "C" {
- continue
+ if j, ok := findVendor(orig); ok {
+ stk.push(path)
+ err := &PackageError{
+ ImportStack: stk.copy(),
+ Err: "must be imported as " + path[j+len("vendor/"):],
}
- download(path, p, stk, useVendor)
+ stk.pop()
+ errorf("%s", err)
+ continue
+ }
+ // If this is a test import, apply vendor lookup now.
+ // We cannot pass useVendor to download, because
+ // download does caching based on the value of path,
+ // so it must be the fully qualified path already.
+ if i >= len(p.Imports) {
+ path = vendoredImportPath(p, path)
}
+ download(path, p, stk, 0)
}
if isWildcard {
@@ -368,7 +402,7 @@ func downloadPackage(p *Package) error {
repo = resolved
}
}
- if remote != repo && p.ImportComment != "" {
+ if remote != repo && rr.isCustom {
return fmt.Errorf("%s is a custom import path for %s, but %s is checked out from %s", rr.root, repo, dir, remote)
}
}
@@ -391,12 +425,16 @@ func downloadPackage(p *Package) error {
// Package not found. Put in first directory of $GOPATH.
list := filepath.SplitList(buildContext.GOPATH)
if len(list) == 0 {
- return fmt.Errorf("cannot download, $GOPATH not set. For more details see: go help gopath")
+ return fmt.Errorf("cannot download, $GOPATH not set. For more details see: 'go help gopath'")
}
// Guard against people setting GOPATH=$GOROOT.
if list[0] == goroot {
- return fmt.Errorf("cannot download, $GOPATH must not be set to $GOROOT. For more details see: go help gopath")
+ return fmt.Errorf("cannot download, $GOPATH must not be set to $GOROOT. For more details see: 'go help gopath'")
}
+ if _, err := os.Stat(filepath.Join(list[0], "src/cmd/go/alldocs.go")); err == nil {
+ return fmt.Errorf("cannot download, %s is a GOROOT, not a GOPATH. For more details see: 'go help gopath'", list[0])
+ }
+ p.build.Root = list[0]
p.build.SrcRoot = filepath.Join(list[0], "src")
p.build.PkgRoot = filepath.Join(list[0], "pkg")
}
@@ -425,11 +463,19 @@ func downloadPackage(p *Package) error {
if _, err := os.Stat(root); err == nil {
return fmt.Errorf("%s exists but %s does not - stale checkout?", root, meta)
}
+
+ _, err := os.Stat(p.build.Root)
+ gopathExisted := err == nil
+
// Some version control tools require the parent of the target to exist.
parent, _ := filepath.Split(root)
if err = os.MkdirAll(parent, 0777); err != nil {
return err
}
+ if buildV && !gopathExisted && p.build.Root == buildContext.GOPATH {
+ fmt.Fprintf(os.Stderr, "created GOPATH=%s; see 'go help gopath'\n", p.build.Root)
+ }
+
if err = vcs.create(root, repo); err != nil {
return err
}
diff --git a/libgo/go/cmd/go/go_test.go b/libgo/go/cmd/go/go_test.go
index 66c641347cb..5727eb094e5 100644
--- a/libgo/go/cmd/go/go_test.go
+++ b/libgo/go/cmd/go/go_test.go
@@ -6,7 +6,6 @@ package main_test
import (
"bytes"
- "flag"
"fmt"
"go/build"
"go/format"
@@ -50,6 +49,17 @@ func init() {
// many linux/arm machines are too slow to run
// the full set of external tests.
skipExternal = true
+ case "mips", "mipsle", "mips64", "mips64le":
+ // Also slow.
+ skipExternal = true
+ if testenv.Builder() != "" {
+ // On the builders, skip the cmd/go
+ // tests. They're too slow and already
+ // covered by other ports. There's
+ // nothing os/arch specific in the
+ // tests.
+ canRun = false
+ }
}
case "freebsd":
switch runtime.GOARCH {
@@ -67,8 +77,6 @@ func init() {
// The TestMain function creates a go command for testing purposes and
// deletes it after the tests have been run.
func TestMain(m *testing.M) {
- flag.Parse()
-
if canRun {
args := []string{"build", "-tags", "testgo", "-o", "testgo" + exeSuffix}
if race.Enabled {
@@ -99,6 +107,14 @@ func TestMain(m *testing.M) {
// Don't let these environment variables confuse the test.
os.Unsetenv("GOBIN")
os.Unsetenv("GOPATH")
+ os.Unsetenv("GIT_ALLOW_PROTOCOL")
+ if home, ccacheDir := os.Getenv("HOME"), os.Getenv("CCACHE_DIR"); home != "" && ccacheDir == "" {
+ // On some systems the default C compiler is ccache.
+ // Setting HOME to a non-existent directory will break
+ // those systems. Set CCACHE_DIR to cope. Issue 17668.
+ os.Setenv("CCACHE_DIR", filepath.Join(home, ".ccache"))
+ }
+ os.Setenv("HOME", "/test-go-home-does-not-exist")
r := m.Run()
@@ -627,6 +643,7 @@ func TestProgramNameInCrashMessages(t *testing.T) {
func TestBrokenTestsWithoutTestFunctionsAllFail(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
+ // TODO: tg.parallel()
tg.runFail("test", "./testdata/src/badtest/...")
tg.grepBothNot("^ok", "test passed unexpectedly")
tg.grepBoth("FAIL.*badtest/badexec", "test did not run everything")
@@ -742,6 +759,7 @@ func TestNewReleaseRebuildsStalePackagesInGOPATH(t *testing.T) {
func TestGoListStandard(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
+ // TODO: tg.parallel()
tg.cd(runtime.GOROOT() + "/src")
tg.run("list", "-f", "{{if not .Standard}}{{.ImportPath}}{{end}}", "./...")
stdout := tg.getStdout()
@@ -766,6 +784,7 @@ func TestGoListStandard(t *testing.T) {
func TestGoInstallCleansUpAfterGoBuild(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
+ // TODO: tg.parallel()
tg.tempFile("src/mycmd/main.go", `package main; func main(){}`)
tg.setenv("GOPATH", tg.path("."))
tg.cd(tg.path("src/mycmd"))
@@ -857,6 +876,7 @@ func TestGoInstallDetectsRemovedFiles(t *testing.T) {
func TestWildcardMatchesSyntaxErrorDirs(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
+ // TODO: tg.parallel()
tg.tempFile("src/mypkg/x.go", `package mypkg`)
tg.tempFile("src/mypkg/y.go", `pkg mypackage`)
tg.setenv("GOPATH", tg.path("."))
@@ -1013,6 +1033,7 @@ func copyBad(tg *testgoData) {
func TestBadImportsEasy(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
+ // TODO: tg.parallel()
copyBad(tg)
testLocalEasy(tg, badDirName)
}
@@ -1042,14 +1063,14 @@ func TestInternalPackagesInGOROOTAreRespected(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
tg.runFail("build", "-v", "./testdata/testinternal")
- tg.grepBoth("use of internal package not allowed", "wrong error message for testdata/testinternal")
+ tg.grepBoth(`testinternal(\/|\\)p\.go\:3\:8\: use of internal package not allowed`, "wrong error message for testdata/testinternal")
}
func TestInternalPackagesOutsideGOROOTAreRespected(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
tg.runFail("build", "-v", "./testdata/testinternal2")
- tg.grepBoth("use of internal package not allowed", "wrote error message for testdata/testinternal2")
+ tg.grepBoth(`testinternal2(\/|\\)p\.go\:3\:8\: use of internal package not allowed`, "wrote error message for testdata/testinternal2")
}
func TestRunInternal(t *testing.T) {
@@ -1059,7 +1080,7 @@ func TestRunInternal(t *testing.T) {
tg.setenv("GOPATH", dir)
tg.run("run", filepath.Join(dir, "src/run/good.go"))
tg.runFail("run", filepath.Join(dir, "src/run/bad.go"))
- tg.grepStderr("use of internal package not allowed", "unexpected error for run/bad.go")
+ tg.grepStderr(`testdata(\/|\\)src(\/|\\)run(\/|\\)bad\.go\:3\:8\: use of internal package not allowed`, "unexpected error for run/bad.go")
}
func testMove(t *testing.T, vcs, url, base, config string) {
@@ -1180,6 +1201,23 @@ func TestIssue10952(t *testing.T) {
tg.run("get", "-d", "-u", importPath)
}
+func TestIssue16471(t *testing.T) {
+ testenv.MustHaveExternalNetwork(t)
+ if _, err := exec.LookPath("git"); err != nil {
+ t.Skip("skipping because git binary not found")
+ }
+
+ tg := testgo(t)
+ defer tg.cleanup()
+ tg.parallel()
+ tg.tempDir("src")
+ tg.setenv("GOPATH", tg.path("."))
+ tg.must(os.MkdirAll(tg.path("src/rsc.io/go-get-issue-10952"), 0755))
+ tg.runGit(tg.path("src/rsc.io"), "clone", "https://github.com/zombiezen/go-get-issue-10952")
+ tg.runFail("get", "-u", "rsc.io/go-get-issue-10952")
+ tg.grepStderr("rsc.io/go-get-issue-10952 is a custom import path for https://github.com/rsc/go-get-issue-10952, but .* is checked out from https://github.com/zombiezen/go-get-issue-10952", "did not detect updated import path")
+}
+
// Test git clone URL that uses SCP-like syntax and custom import path checking.
func TestIssue11457(t *testing.T) {
testenv.MustHaveExternalNetwork(t)
@@ -1192,7 +1230,7 @@ func TestIssue11457(t *testing.T) {
tg.parallel()
tg.tempDir("src")
tg.setenv("GOPATH", tg.path("."))
- const importPath = "github.com/rsc/go-get-issue-11457"
+ const importPath = "rsc.io/go-get-issue-11457"
tg.run("get", "-d", "-u", importPath)
repoDir := tg.path("src/" + importPath)
tg.runGit(repoDir, "remote", "set-url", "origin", "git@github.com:rsc/go-get-issue-11457")
@@ -1267,11 +1305,23 @@ func TestRelativeImportsGoTestDashI(t *testing.T) {
func TestRelativeImportsInCommandLinePackage(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
+ // TODO: tg.parallel()
files, err := filepath.Glob("./testdata/testimport/*.go")
tg.must(err)
tg.run(append([]string{"test"}, files...)...)
}
+func TestNonCanonicalImportPaths(t *testing.T) {
+ tg := testgo(t)
+ defer tg.cleanup()
+ tg.parallel()
+ tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata"))
+ tg.runFail("build", "canonical/d")
+ tg.grepStderr("package canonical/d", "did not report canonical/d")
+ tg.grepStderr("imports canonical/b", "did not report canonical/b")
+ tg.grepStderr("imports canonical/a/: non-canonical", "did not report canonical/a/")
+}
+
func TestVersionControlErrorMessageIncludesCorrectDirectory(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
@@ -1317,9 +1367,6 @@ func TestInstallIntoGOPATH(t *testing.T) {
// Issue 12407
func TestBuildOutputToDevNull(t *testing.T) {
- if runtime.GOOS == "plan9" {
- t.Skip("skipping because /dev/null is a regular file on plan9")
- }
tg := testgo(t)
defer tg.cleanup()
tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata"))
@@ -1430,6 +1477,17 @@ func TestGoGetNonPkg(t *testing.T) {
tg.grepStderr("golang.org/x/tools: no buildable Go source files", "missing error")
}
+func TestGoGetTestOnlyPkg(t *testing.T) {
+ testenv.MustHaveExternalNetwork(t)
+
+ tg := testgo(t)
+ defer tg.cleanup()
+ tg.tempDir("gopath")
+ tg.setenv("GOPATH", tg.path("gopath"))
+ tg.run("get", "golang.org/x/tour/content")
+ tg.run("get", "-t", "golang.org/x/tour/content")
+}
+
func TestInstalls(t *testing.T) {
if testing.Short() {
t.Skip("don't install into GOROOT in short mode")
@@ -1511,6 +1569,7 @@ func TestGoTestWithPackageListedMultipleTimes(t *testing.T) {
func TestGoListHasAConsistentOrder(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
+ tg.parallel()
tg.run("list", "std")
first := tg.getStdout()
tg.run("list", "std")
@@ -1522,6 +1581,7 @@ func TestGoListHasAConsistentOrder(t *testing.T) {
func TestGoListStdDoesNotIncludeCommands(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
+ tg.parallel()
tg.run("list", "std")
tg.grepStdoutNot("cmd/", "go list std shows commands")
}
@@ -1529,6 +1589,7 @@ func TestGoListStdDoesNotIncludeCommands(t *testing.T) {
func TestGoListCmdOnlyShowsCommands(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
+ tg.parallel()
tg.run("list", "cmd")
out := strings.TrimSpace(tg.getStdout())
for _, line := range strings.Split(out, "\n") {
@@ -1542,6 +1603,7 @@ func TestGoListCmdOnlyShowsCommands(t *testing.T) {
func TestGoListDedupsPackages(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
+ // TODO: tg.parallel()
tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata"))
tg.run("list", "xtestonly", "./testdata/src/xtestonly/...")
got := strings.TrimSpace(tg.getStdout())
@@ -1555,6 +1617,7 @@ func TestGoListDedupsPackages(t *testing.T) {
func TestUnsuccessfulGoInstallShouldMentionMissingPackage(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
+ tg.parallel()
tg.runFail("install", "foo/quxx")
if tg.grepCountBoth(`cannot find package "foo/quxx" in any of`) != 1 {
t.Error(`go install foo/quxx expected error: .*cannot find package "foo/quxx" in any of`)
@@ -1564,6 +1627,7 @@ func TestUnsuccessfulGoInstallShouldMentionMissingPackage(t *testing.T) {
func TestGOROOTSearchFailureReporting(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
+ tg.parallel()
tg.runFail("install", "foo/quxx")
if tg.grepCountBoth(regexp.QuoteMeta(filepath.Join("foo", "quxx"))+` \(from \$GOROOT\)$`) != 1 {
t.Error(`go install foo/quxx expected error: .*foo/quxx (from $GOROOT)`)
@@ -1573,6 +1637,7 @@ func TestGOROOTSearchFailureReporting(t *testing.T) {
func TestMultipleGOPATHEntriesReportedSeparately(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
+ tg.parallel()
sep := string(filepath.ListSeparator)
tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata", "a")+sep+filepath.Join(tg.pwd(), "testdata", "b"))
tg.runFail("install", "foo/quxx")
@@ -1585,6 +1650,7 @@ func TestMultipleGOPATHEntriesReportedSeparately(t *testing.T) {
func TestMentionGOPATHInFirstGOPATHEntry(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
+ tg.parallel()
sep := string(filepath.ListSeparator)
tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata", "a")+sep+filepath.Join(tg.pwd(), "testdata", "b"))
tg.runFail("install", "foo/quxx")
@@ -1597,6 +1663,7 @@ func TestMentionGOPATHInFirstGOPATHEntry(t *testing.T) {
func TestMentionGOPATHNotOnSecondEntry(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
+ tg.parallel()
sep := string(filepath.ListSeparator)
tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata", "a")+sep+filepath.Join(tg.pwd(), "testdata", "b"))
tg.runFail("install", "foo/quxx")
@@ -1605,14 +1672,156 @@ func TestMentionGOPATHNotOnSecondEntry(t *testing.T) {
}
}
-// Test missing GOPATH is reported.
-func TestMissingGOPATHIsReported(t *testing.T) {
+func homeEnvName() string {
+ switch runtime.GOOS {
+ case "windows":
+ return "USERPROFILE"
+ case "plan9":
+ return "home"
+ default:
+ return "HOME"
+ }
+}
+
+// Test go env missing GOPATH shows default.
+func TestMissingGOPATHEnvShowsDefault(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
+ tg.parallel()
tg.setenv("GOPATH", "")
- tg.runFail("install", "foo/quxx")
- if tg.grepCountBoth(`\(\$GOPATH not set\)$`) != 1 {
- t.Error(`go install foo/quxx expected error: ($GOPATH not set)`)
+ tg.run("env", "GOPATH")
+
+ want := filepath.Join(os.Getenv(homeEnvName()), "go")
+ got := strings.TrimSpace(tg.getStdout())
+ if got != want {
+ t.Errorf("got %q; want %q", got, want)
+ }
+}
+
+// Test go get missing GOPATH causes go get to warn if directory doesn't exist.
+func TestMissingGOPATHGetWarnsIfNotExists(t *testing.T) {
+ testenv.MustHaveExternalNetwork(t)
+
+ if _, err := exec.LookPath("git"); err != nil {
+ t.Skip("skipping because git binary not found")
+ }
+
+ tg := testgo(t)
+ defer tg.cleanup()
+
+ // setenv variables for test and defer deleting temporary home directory.
+ tg.setenv("GOPATH", "")
+ tmp, err := ioutil.TempDir("", "")
+ if err != nil {
+ t.Fatalf("could not create tmp home: %v", err)
+ }
+ defer os.RemoveAll(tmp)
+ tg.setenv(homeEnvName(), tmp)
+
+ tg.run("get", "-v", "github.com/golang/example/hello")
+
+ want := fmt.Sprintf("created GOPATH=%s; see 'go help gopath'", filepath.Join(tmp, "go"))
+ got := strings.TrimSpace(tg.getStderr())
+ if !strings.Contains(got, want) {
+ t.Errorf("got %q; want %q", got, want)
+ }
+}
+
+// Test go get missing GOPATH causes no warning if directory exists.
+func TestMissingGOPATHGetDoesntWarnIfExists(t *testing.T) {
+ testenv.MustHaveExternalNetwork(t)
+
+ if _, err := exec.LookPath("git"); err != nil {
+ t.Skip("skipping because git binary not found")
+ }
+
+ tg := testgo(t)
+ defer tg.cleanup()
+
+ // setenv variables for test and defer resetting them.
+ tg.setenv("GOPATH", "")
+ tmp, err := ioutil.TempDir("", "")
+ if err != nil {
+ t.Fatalf("could not create tmp home: %v", err)
+ }
+ defer os.RemoveAll(tmp)
+ if err := os.Mkdir(filepath.Join(tmp, "go"), 0777); err != nil {
+ t.Fatalf("could not create $HOME/go: %v", err)
+ }
+
+ tg.setenv(homeEnvName(), tmp)
+
+ tg.run("get", "github.com/golang/example/hello")
+
+ got := strings.TrimSpace(tg.getStderr())
+ if got != "" {
+ t.Errorf("got %q; wants empty", got)
+ }
+}
+
+// Test go get missing GOPATH fails if pointed file is not a directory.
+func TestMissingGOPATHGetFailsIfItsNotDirectory(t *testing.T) {
+ testenv.MustHaveExternalNetwork(t)
+
+ tg := testgo(t)
+ defer tg.cleanup()
+
+ // setenv variables for test and defer resetting them.
+ tg.setenv("GOPATH", "")
+ tmp, err := ioutil.TempDir("", "")
+ if err != nil {
+ t.Fatalf("could not create tmp home: %v", err)
+ }
+ defer os.RemoveAll(tmp)
+
+ path := filepath.Join(tmp, "go")
+ if err := ioutil.WriteFile(path, nil, 0777); err != nil {
+ t.Fatalf("could not create GOPATH at %s: %v", path, err)
+ }
+ tg.setenv(homeEnvName(), tmp)
+
+ const pkg = "github.com/golang/example/hello"
+ tg.runFail("get", pkg)
+
+ msg := "not a directory"
+ if runtime.GOOS == "windows" {
+ msg = "The system cannot find the path specified."
+ }
+ want := fmt.Sprintf("package %s: mkdir %s: %s", pkg, filepath.Join(tmp, "go"), msg)
+ got := strings.TrimSpace(tg.getStderr())
+ if got != want {
+ t.Errorf("got %q; wants %q", got, want)
+ }
+}
+
+// Test go install of missing package when missing GOPATH fails and shows default GOPATH.
+func TestMissingGOPATHInstallMissingPackageFailsAndShowsDefault(t *testing.T) {
+ tg := testgo(t)
+ defer tg.cleanup()
+
+ // setenv variables for test and defer resetting them.
+ tg.setenv("GOPATH", "")
+ tmp, err := ioutil.TempDir("", "")
+ if err != nil {
+ t.Fatalf("could not create tmp home: %v", err)
+ }
+ defer os.RemoveAll(tmp)
+ if err := os.Mkdir(filepath.Join(tmp, "go"), 0777); err != nil {
+ t.Fatalf("could not create $HOME/go: %v", err)
+ }
+ tg.setenv(homeEnvName(), tmp)
+
+ const pkg = "github.com/golang/example/hello"
+ tg.runFail("install", pkg)
+
+ pkgPath := filepath.Join(strings.Split(pkg, "/")...)
+ want := fmt.Sprintf("can't load package: package %s: cannot find package \"%s\" in any of:", pkg, pkg) +
+ fmt.Sprintf("\n\t%s (from $GOROOT)", filepath.Join(runtime.GOROOT(), "src", pkgPath)) +
+ fmt.Sprintf("\n\t%s (from $GOPATH)", filepath.Join(tmp, "go", "src", pkgPath))
+
+ got := strings.TrimSpace(tg.getStderr())
+ if got != want {
+ t.Errorf("got %q; wants %q", got, want)
}
}
@@ -1659,6 +1868,7 @@ func TestLdflagsArgumentsWithSpacesIssue3941(t *testing.T) {
func TestGoTestCpuprofileLeavesBinaryBehind(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
+ // TODO: tg.parallel()
tg.makeTempdir()
tg.cd(tg.path("."))
tg.run("test", "-cpuprofile", "errors.prof", "errors")
@@ -1668,12 +1878,33 @@ func TestGoTestCpuprofileLeavesBinaryBehind(t *testing.T) {
func TestGoTestCpuprofileDashOControlsBinaryLocation(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
+ // TODO: tg.parallel()
tg.makeTempdir()
tg.cd(tg.path("."))
tg.run("test", "-cpuprofile", "errors.prof", "-o", "myerrors.test"+exeSuffix, "errors")
tg.wantExecutable("myerrors.test"+exeSuffix, "go test -cpuprofile -o myerrors.test did not create myerrors.test")
}
+func TestGoTestMutexprofileLeavesBinaryBehind(t *testing.T) {
+ tg := testgo(t)
+ defer tg.cleanup()
+ // TODO: tg.parallel()
+ tg.makeTempdir()
+ tg.cd(tg.path("."))
+ tg.run("test", "-mutexprofile", "errors.prof", "errors")
+ tg.wantExecutable("errors.test"+exeSuffix, "go test -mutexprofile did not create errors.test")
+}
+
+func TestGoTestMutexprofileDashOControlsBinaryLocation(t *testing.T) {
+ tg := testgo(t)
+ defer tg.cleanup()
+ // TODO: tg.parallel()
+ tg.makeTempdir()
+ tg.cd(tg.path("."))
+ tg.run("test", "-mutexprofile", "errors.prof", "-o", "myerrors.test"+exeSuffix, "errors")
+ tg.wantExecutable("myerrors.test"+exeSuffix, "go test -mutexprofile -o myerrors.test did not create myerrors.test")
+}
+
func TestGoTestDashCDashOControlsBinaryLocation(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
@@ -1692,6 +1923,16 @@ func TestGoTestDashOWritesBinary(t *testing.T) {
tg.wantExecutable(tg.path("myerrors.test"+exeSuffix), "go test -o myerrors.test did not create myerrors.test")
}
+func TestGoTestDashIDashOWritesBinary(t *testing.T) {
+ tg := testgo(t)
+ defer tg.cleanup()
+ tg.parallel()
+ tg.makeTempdir()
+ tg.run("test", "-v", "-i", "-o", tg.path("myerrors.test"+exeSuffix), "errors")
+ tg.grepBothNot("PASS|FAIL", "test should not have run")
+ tg.wantExecutable(tg.path("myerrors.test"+exeSuffix), "go test -o myerrors.test did not create myerrors.test")
+}
+
// Issue 4568.
func TestSymlinksList(t *testing.T) {
switch runtime.GOOS {
@@ -1701,6 +1942,7 @@ func TestSymlinksList(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
+ // TODO: tg.parallel()
tg.tempDir("src")
tg.must(os.Symlink(tg.path("."), tg.path("src/dir1")))
tg.tempFile("src/dir1/p.go", "package p")
@@ -1721,6 +1963,7 @@ func TestSymlinksVendor(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
+ // TODO: tg.parallel()
tg.tempDir("gopath/src/dir1/vendor/v")
tg.tempFile("gopath/src/dir1/p.go", "package main\nimport _ `v`\nfunc main(){}")
tg.tempFile("gopath/src/dir1/vendor/v/v.go", "package v")
@@ -1738,6 +1981,27 @@ func TestSymlinksVendor(t *testing.T) {
tg.run("install")
}
+// Issue 15201.
+func TestSymlinksVendor15201(t *testing.T) {
+ switch runtime.GOOS {
+ case "plan9", "windows":
+ t.Skipf("skipping symlink test on %s", runtime.GOOS)
+ }
+
+ tg := testgo(t)
+ defer tg.cleanup()
+
+ tg.tempDir("gopath/src/x/y/_vendor/src/x")
+ tg.must(os.Symlink("../../..", tg.path("gopath/src/x/y/_vendor/src/x/y")))
+ tg.tempFile("gopath/src/x/y/w/w.go", "package w\nimport \"x/y/z\"\n")
+ tg.must(os.Symlink("../_vendor/src", tg.path("gopath/src/x/y/w/vendor")))
+ tg.tempFile("gopath/src/x/y/z/z.go", "package z\n")
+
+ tg.setenv("GOPATH", tg.path("gopath/src/x/y/_vendor")+string(filepath.ListSeparator)+tg.path("gopath"))
+ tg.cd(tg.path("gopath/src"))
+ tg.run("list", "./...")
+}
+
func TestSymlinksInternal(t *testing.T) {
switch runtime.GOOS {
case "plan9", "windows":
@@ -1829,9 +2093,7 @@ func TestCaseCollisions(t *testing.T) {
// Issue 8181.
func TestGoGetDashTIssue8181(t *testing.T) {
- if testing.Short() {
- t.Skip("skipping test that uses network in short mode")
- }
+ testenv.MustHaveExternalNetwork(t)
tg := testgo(t)
defer tg.cleanup()
@@ -1840,14 +2102,12 @@ func TestGoGetDashTIssue8181(t *testing.T) {
tg.setenv("GOPATH", tg.path("."))
tg.run("get", "-v", "-t", "github.com/rsc/go-get-issue-8181/a", "github.com/rsc/go-get-issue-8181/b")
tg.run("list", "...")
- tg.grepStdout("x/build/cmd/cl", "missing expected x/build/cmd/cl")
+ tg.grepStdout("x/build/gerrit", "missing expected x/build/gerrit")
}
func TestIssue11307(t *testing.T) {
// go get -u was not working except in checkout directory
- if testing.Short() {
- t.Skip("skipping test that uses network in short mode")
- }
+ testenv.MustHaveExternalNetwork(t)
tg := testgo(t)
defer tg.cleanup()
@@ -1997,6 +2257,38 @@ func TestCoverageUsesActualSettingToOverrideEvenForRace(t *testing.T) {
checkCoverage(tg, data)
}
+func TestCoverageImportMainLoop(t *testing.T) {
+ tg := testgo(t)
+ defer tg.cleanup()
+ tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata"))
+ tg.runFail("test", "importmain/test")
+ tg.grepStderr("not an importable package", "did not detect import main")
+ tg.runFail("test", "-cover", "importmain/test")
+ tg.grepStderr("not an importable package", "did not detect import main")
+}
+
+func TestTestEmpty(t *testing.T) {
+ if !canRace {
+ t.Skip("no race detector")
+ }
+
+ wd, _ := os.Getwd()
+ testdata := filepath.Join(wd, "testdata")
+
+ for _, dir := range []string{"pkg", "test", "xtest", "pkgtest", "pkgxtest", "pkgtestxtest", "testxtest"} {
+ t.Run(dir, func(t *testing.T) {
+ tg := testgo(t)
+ defer tg.cleanup()
+ tg.setenv("GOPATH", testdata)
+ tg.cd(filepath.Join(testdata, "src/empty/"+dir))
+ tg.run("test", "-cover", "-coverpkg=.", "-race")
+ })
+ if testing.Short() {
+ break
+ }
+ }
+}
+
func TestBuildDryRunWithCgo(t *testing.T) {
if !canCgo {
t.Skip("skipping because cgo not enabled")
@@ -2023,11 +2315,17 @@ func TestCoverageWithCgo(t *testing.T) {
t.Skip("skipping because cgo not enabled")
}
- tg := testgo(t)
- defer tg.cleanup()
- tg.run("test", "-short", "-cover", "./testdata/cgocover")
- data := tg.getStdout() + tg.getStderr()
- checkCoverage(tg, data)
+ for _, dir := range []string{"cgocover", "cgocover2", "cgocover3", "cgocover4"} {
+ t.Run(dir, func(t *testing.T) {
+ tg := testgo(t)
+ tg.parallel()
+ defer tg.cleanup()
+ tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata"))
+ tg.run("test", "-short", "-cover", dir)
+ data := tg.getStdout() + tg.getStderr()
+ checkCoverage(tg, data)
+ })
+ }
}
func TestCgoDependsOnSyscall(t *testing.T) {
@@ -2090,10 +2388,57 @@ func TestCgoHandlesWlORIGIN(t *testing.T) {
tg.run("build", "origin")
}
+func TestCgoPkgConfig(t *testing.T) {
+ if !canCgo {
+ t.Skip("skipping because cgo not enabled")
+ }
+ tg := testgo(t)
+ defer tg.cleanup()
+ tg.parallel()
+
+ tg.run("env", "PKG_CONFIG")
+ pkgConfig := strings.TrimSpace(tg.getStdout())
+ if out, err := exec.Command(pkgConfig, "--atleast-pkgconfig-version", "0.24").CombinedOutput(); err != nil {
+ t.Skipf("%s --atleast-pkgconfig-version 0.24: %v\n%s", pkgConfig, err, out)
+ }
+
+ // OpenBSD's pkg-config is strict about whitespace and only
+ // supports backslash-escaped whitespace. It does not support
+ // quotes, which the normal freedesktop.org pkg-config does
+ // support. See http://man.openbsd.org/pkg-config.1
+ tg.tempFile("foo.pc", `
+Name: foo
+Description: The foo library
+Version: 1.0.0
+Cflags: -Dhello=10 -Dworld=+32 -DDEFINED_FROM_PKG_CONFIG=hello\ world
+`)
+ tg.tempFile("foo.go", `package main
+
+/*
+#cgo pkg-config: foo
+int value() {
+ return DEFINED_FROM_PKG_CONFIG;
+}
+*/
+import "C"
+import "os"
+
+func main() {
+ if C.value() != 42 {
+ println("value() =", C.value(), "wanted 42")
+ os.Exit(1)
+ }
+}
+`)
+ tg.setenv("PKG_CONFIG_PATH", tg.path("."))
+ tg.run("run", tg.path("foo.go"))
+}
+
// "go test -c -test.bench=XXX errors" should not hang
func TestIssue6480(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
+ // TODO: tg.parallel()
tg.makeTempdir()
tg.cd(tg.path("."))
tg.run("test", "-c", "-test.bench=XXX", "errors")
@@ -2124,8 +2469,7 @@ func main() { C.f() }`)
}
func TestListTemplateContextFunction(t *testing.T) {
- tg := testgo(t)
- defer tg.cleanup()
+ t.Parallel()
for _, tt := range []struct {
v string
want string
@@ -2141,14 +2485,20 @@ func TestListTemplateContextFunction(t *testing.T) {
{"ReleaseTags", ""},
{"InstallSuffix", ""},
} {
- tmpl := "{{context." + tt.v + "}}"
- tg.run("list", "-f", tmpl)
- if tt.want == "" {
- continue
- }
- if got := strings.TrimSpace(tg.getStdout()); got != tt.want {
- t.Errorf("go list -f %q: got %q; want %q", tmpl, got, tt.want)
- }
+ tt := tt
+ t.Run(tt.v, func(t *testing.T) {
+ tg := testgo(t)
+ tg.parallel()
+ defer tg.cleanup()
+ tmpl := "{{context." + tt.v + "}}"
+ tg.run("list", "-f", tmpl)
+ if tt.want == "" {
+ return
+ }
+ if got := strings.TrimSpace(tg.getStdout()); got != tt.want {
+ t.Errorf("go list -f %q: got %q; want %q", tmpl, got, tt.want)
+ }
+ })
}
}
@@ -2307,6 +2657,20 @@ func TestGoGenerateEnv(t *testing.T) {
}
}
+func TestGoGenerateBadImports(t *testing.T) {
+ if runtime.GOOS == "windows" {
+ t.Skip("skipping because windows has no echo command")
+ }
+
+ // This package has an invalid import causing an import cycle,
+ // but go generate is supposed to still run.
+ tg := testgo(t)
+ defer tg.cleanup()
+ tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata"))
+ tg.run("generate", "gencycle")
+ tg.grepStdout("hello world", "go generate gencycle did not run generator")
+}
+
func TestGoGetCustomDomainWildcard(t *testing.T) {
testenv.MustHaveExternalNetwork(t)
@@ -2382,35 +2746,254 @@ func TestGoGetHTTPS404(t *testing.T) {
}
// Test that you cannot import a main package.
-func TestIssue4210(t *testing.T) {
+// See golang.org/issue/4210 and golang.org/issue/17475.
+func TestImportMain(t *testing.T) {
tg := testgo(t)
+ tg.parallel()
defer tg.cleanup()
+
+ // Importing package main from that package main's test should work.
tg.tempFile("src/x/main.go", `package main
var X int
func main() {}`)
- tg.tempFile("src/y/main.go", `package main
- import "fmt"
+ tg.tempFile("src/x/main_test.go", `package main_test
import xmain "x"
- func main() {
- fmt.Println(xmain.X)
- }`)
+ import "testing"
+ var _ = xmain.X
+ func TestFoo(t *testing.T) {}
+ `)
+ tg.setenv("GOPATH", tg.path("."))
+ tg.creatingTemp("x")
+ tg.run("build", "x")
+ tg.run("test", "x")
+
+ // Importing package main from another package should fail.
+ tg.tempFile("src/p1/p.go", `package p1
+ import xmain "x"
+ var _ = xmain.X
+ `)
+ tg.runFail("build", "p1")
+ tg.grepStderr("import \"x\" is a program, not an importable package", "did not diagnose package main")
+
+ // ... even in that package's test.
+ tg.tempFile("src/p2/p.go", `package p2
+ `)
+ tg.tempFile("src/p2/p_test.go", `package p2
+ import xmain "x"
+ import "testing"
+ var _ = xmain.X
+ func TestFoo(t *testing.T) {}
+ `)
+ tg.run("build", "p2")
+ tg.runFail("test", "p2")
+ tg.grepStderr("import \"x\" is a program, not an importable package", "did not diagnose package main")
+
+ // ... even if that package's test is an xtest.
+ tg.tempFile("src/p3/p.go", `package p
+ `)
+ tg.tempFile("src/p3/p_test.go", `package p_test
+ import xmain "x"
+ import "testing"
+ var _ = xmain.X
+ func TestFoo(t *testing.T) {}
+ `)
+ tg.run("build", "p3")
+ tg.runFail("test", "p3")
+ tg.grepStderr("import \"x\" is a program, not an importable package", "did not diagnose package main")
+
+ // ... even if that package is a package main
+ tg.tempFile("src/p4/p.go", `package main
+ func main() {}
+ `)
+ tg.tempFile("src/p4/p_test.go", `package main
+ import xmain "x"
+ import "testing"
+ var _ = xmain.X
+ func TestFoo(t *testing.T) {}
+ `)
+ tg.creatingTemp("p4" + exeSuffix)
+ tg.run("build", "p4")
+ tg.runFail("test", "p4")
+ tg.grepStderr("import \"x\" is a program, not an importable package", "did not diagnose package main")
+
+ // ... even if that package is a package main using an xtest.
+ tg.tempFile("src/p5/p.go", `package main
+ func main() {}
+ `)
+ tg.tempFile("src/p5/p_test.go", `package main_test
+ import xmain "x"
+ import "testing"
+ var _ = xmain.X
+ func TestFoo(t *testing.T) {}
+ `)
+ tg.creatingTemp("p5" + exeSuffix)
+ tg.run("build", "p5")
+ tg.runFail("test", "p5")
+ tg.grepStderr("import \"x\" is a program, not an importable package", "did not diagnose package main")
+}
+
+// Test that you cannot use a local import in a package
+// accessed by a non-local import (found in a GOPATH/GOROOT).
+// See golang.org/issue/17475.
+func TestImportLocal(t *testing.T) {
+ tg := testgo(t)
+ tg.parallel()
+ defer tg.cleanup()
+
+ tg.tempFile("src/dir/x/x.go", `package x
+ var X int
+ `)
tg.setenv("GOPATH", tg.path("."))
- tg.runFail("build", "y")
- tg.grepBoth("is a program", `did not find expected error message ("is a program")`)
+ tg.run("build", "dir/x")
+
+ // Ordinary import should work.
+ tg.tempFile("src/dir/p0/p.go", `package p0
+ import "dir/x"
+ var _ = x.X
+ `)
+ tg.run("build", "dir/p0")
+
+ // Relative import should not.
+ tg.tempFile("src/dir/p1/p.go", `package p1
+ import "../x"
+ var _ = x.X
+ `)
+ tg.runFail("build", "dir/p1")
+ tg.grepStderr("local import.*in non-local package", "did not diagnose local import")
+
+ // ... even in a test.
+ tg.tempFile("src/dir/p2/p.go", `package p2
+ `)
+ tg.tempFile("src/dir/p2/p_test.go", `package p2
+ import "../x"
+ import "testing"
+ var _ = x.X
+ func TestFoo(t *testing.T) {}
+ `)
+ tg.run("build", "dir/p2")
+ tg.runFail("test", "dir/p2")
+ tg.grepStderr("local import.*in non-local package", "did not diagnose local import")
+
+ // ... even in an xtest.
+ tg.tempFile("src/dir/p2/p_test.go", `package p2_test
+ import "../x"
+ import "testing"
+ var _ = x.X
+ func TestFoo(t *testing.T) {}
+ `)
+ tg.run("build", "dir/p2")
+ tg.runFail("test", "dir/p2")
+ tg.grepStderr("local import.*in non-local package", "did not diagnose local import")
+
+ // Relative import starting with ./ should not work either.
+ tg.tempFile("src/dir/d.go", `package dir
+ import "./x"
+ var _ = x.X
+ `)
+ tg.runFail("build", "dir")
+ tg.grepStderr("local import.*in non-local package", "did not diagnose local import")
+
+ // ... even in a test.
+ tg.tempFile("src/dir/d.go", `package dir
+ `)
+ tg.tempFile("src/dir/d_test.go", `package dir
+ import "./x"
+ import "testing"
+ var _ = x.X
+ func TestFoo(t *testing.T) {}
+ `)
+ tg.run("build", "dir")
+ tg.runFail("test", "dir")
+ tg.grepStderr("local import.*in non-local package", "did not diagnose local import")
+
+ // ... even in an xtest.
+ tg.tempFile("src/dir/d_test.go", `package dir_test
+ import "./x"
+ import "testing"
+ var _ = x.X
+ func TestFoo(t *testing.T) {}
+ `)
+ tg.run("build", "dir")
+ tg.runFail("test", "dir")
+ tg.grepStderr("local import.*in non-local package", "did not diagnose local import")
+
+ // Relative import plain ".." should not work.
+ tg.tempFile("src/dir/x/y/y.go", `package dir
+ import ".."
+ var _ = x.X
+ `)
+ tg.runFail("build", "dir/x/y")
+ tg.grepStderr("local import.*in non-local package", "did not diagnose local import")
+
+ // ... even in a test.
+ tg.tempFile("src/dir/x/y/y.go", `package y
+ `)
+ tg.tempFile("src/dir/x/y/y_test.go", `package y
+ import ".."
+ import "testing"
+ var _ = x.X
+ func TestFoo(t *testing.T) {}
+ `)
+ tg.run("build", "dir/x/y")
+ tg.runFail("test", "dir/x/y")
+ tg.grepStderr("local import.*in non-local package", "did not diagnose local import")
+
+ // ... even in an x test.
+ tg.tempFile("src/dir/x/y/y_test.go", `package y_test
+ import ".."
+ import "testing"
+ var _ = x.X
+ func TestFoo(t *testing.T) {}
+ `)
+ tg.run("build", "dir/x/y")
+ tg.runFail("test", "dir/x/y")
+ tg.grepStderr("local import.*in non-local package", "did not diagnose local import")
+
+ // Relative import "." should not work.
+ tg.tempFile("src/dir/x/xx.go", `package x
+ import "."
+ var _ = x.X
+ `)
+ tg.runFail("build", "dir/x")
+ tg.grepStderr("local import.*in non-local package", "did not diagnose local import")
+
+ // ... even in a test.
+ tg.tempFile("src/dir/x/xx.go", `package x
+ `)
+ tg.tempFile("src/dir/x/xx_test.go", `package x
+ import "."
+ import "testing"
+ var _ = x.X
+ func TestFoo(t *testing.T) {}
+ `)
+ tg.run("build", "dir/x")
+ tg.runFail("test", "dir/x")
+ tg.grepStderr("local import.*in non-local package", "did not diagnose local import")
+
+ // ... even in an xtest.
+ tg.tempFile("src/dir/x/xx.go", `package x
+ `)
+ tg.tempFile("src/dir/x/xx_test.go", `package x_test
+ import "."
+ import "testing"
+ var _ = x.X
+ func TestFoo(t *testing.T) {}
+ `)
+ tg.run("build", "dir/x")
+ tg.runFail("test", "dir/x")
+ tg.grepStderr("local import.*in non-local package", "did not diagnose local import")
}
func TestGoGetInsecure(t *testing.T) {
testenv.MustHaveExternalNetwork(t)
- t.Skip("golang.org/issue/15410")
-
tg := testgo(t)
defer tg.cleanup()
tg.makeTempdir()
tg.setenv("GOPATH", tg.path("."))
tg.failSSH()
- const repo = "wh3rd.net/git.git"
+ const repo = "insecure.go-get-issue-15410.appspot.com/pkg/p"
// Try go get -d of HTTP-only repo (should fail).
tg.runFail("get", "-d", repo)
@@ -2454,7 +3037,7 @@ func TestGoGetInsecureCustomDomain(t *testing.T) {
tg.makeTempdir()
tg.setenv("GOPATH", tg.path("."))
- const repo = "wh3rd.net/repo"
+ const repo = "insecure.go-get-issue-15410.appspot.com/pkg/p"
tg.runFail("get", "-d", repo)
tg.run("get", "-d", "-insecure", repo)
}
@@ -2471,6 +3054,7 @@ func TestGoRunDirs(t *testing.T) {
func TestGoInstallPkgdir(t *testing.T) {
tg := testgo(t)
+ tg.parallel()
defer tg.cleanup()
tg.makeTempdir()
pkg := tg.path(".")
@@ -2509,6 +3093,27 @@ func TestGoTestRaceInstallCgo(t *testing.T) {
}
}
+func TestGoTestRaceFailures(t *testing.T) {
+ if !canRace {
+ t.Skip("skipping because race detector not supported")
+ }
+
+ tg := testgo(t)
+ tg.parallel()
+ defer tg.cleanup()
+ tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata"))
+
+ tg.run("test", "testrace")
+
+ tg.runFail("test", "-race", "testrace")
+ tg.grepStdout("FAIL: TestRace", "TestRace did not fail")
+ tg.grepBothNot("PASS", "something passed")
+
+ tg.runFail("test", "-race", "testrace", "-run", "XXX", "-bench", ".")
+ tg.grepStdout("FAIL: BenchmarkRace", "BenchmarkRace did not fail")
+ tg.grepBothNot("PASS", "something passed")
+}
+
func TestGoTestImportErrorStack(t *testing.T) {
const out = `package testdep/p1 (test)
imports testdep/p2
@@ -2773,6 +3378,7 @@ func TestIssue13655(t *testing.T) {
// For issue 14337.
func TestParallelTest(t *testing.T) {
tg := testgo(t)
+ tg.parallel()
defer tg.cleanup()
tg.makeTempdir()
const testSrc = `package package_test
@@ -2793,9 +3399,11 @@ func TestCgoConsistentResults(t *testing.T) {
if !canCgo {
t.Skip("skipping because cgo not enabled")
}
- if runtime.GOOS == "solaris" {
- // See https://golang.org/issue/13247
- t.Skip("skipping because Solaris builds are known to be inconsistent; see #13247")
+ switch runtime.GOOS {
+ case "freebsd":
+ testenv.SkipFlaky(t, 15405)
+ case "solaris":
+ testenv.SkipFlaky(t, 13247)
}
tg := testgo(t)
@@ -2832,10 +3440,23 @@ func TestGoGetUpdateAllDoesNotTryToLoadDuplicates(t *testing.T) {
tg.grepStderrNot("duplicate loads of", "did not remove old packages from cache")
}
+// Issue 17119 more duplicate load errors
+func TestIssue17119(t *testing.T) {
+ testenv.MustHaveExternalNetwork(t)
+
+ tg := testgo(t)
+ defer tg.cleanup()
+ tg.parallel()
+ tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata"))
+ tg.runFail("build", "dupload")
+ tg.grepBothNot("duplicate load|internal error", "internal error")
+}
+
func TestFatalInBenchmarkCauseNonZeroExitStatus(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
- tg.runFail("test", "-bench", ".", "./testdata/src/benchfatal")
+ // TODO: tg.parallel()
+ tg.runFail("test", "-run", "^$", "-bench", ".", "./testdata/src/benchfatal")
tg.grepBothNot("^ok", "test passed unexpectedly")
tg.grepBoth("FAIL.*benchfatal", "test did not run everything")
}
@@ -2843,6 +3464,7 @@ func TestFatalInBenchmarkCauseNonZeroExitStatus(t *testing.T) {
func TestBinaryOnlyPackages(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
+ tg.parallel()
tg.makeTempdir()
tg.setenv("GOPATH", tg.path("."))
@@ -2907,6 +3529,16 @@ func TestBinaryOnlyPackages(t *testing.T) {
tg.run("run", tg.path("src/p3/p3.go"))
tg.grepStdout("hello from p1", "did not see message from p1")
+
+ tg.tempFile("src/p4/p4.go", `package main`)
+ tg.tempFile("src/p4/p4not.go", `//go:binary-only-package
+
+ // +build asdf
+
+ package main
+ `)
+ tg.run("list", "-f", "{{.BinaryOnly}}", "p4")
+ tg.grepStdout("false", "did not see BinaryOnly=false for p4")
}
// Issue 16050.
@@ -2954,3 +3586,204 @@ func TestGenerateUsesBuildContext(t *testing.T) {
tg.run("generate", "gen")
tg.grepStdout("darwin 386", "unexpected GOOS/GOARCH combination")
}
+
+// Issue 14450: go get -u .../ tried to import not downloaded package
+func TestGoGetUpdateWithWildcard(t *testing.T) {
+ testenv.MustHaveExternalNetwork(t)
+
+ tg := testgo(t)
+ defer tg.cleanup()
+ tg.parallel()
+ tg.makeTempdir()
+ tg.setenv("GOPATH", tg.path("."))
+ const aPkgImportPath = "github.com/tmwh/go-get-issue-14450/a"
+ tg.run("get", aPkgImportPath)
+ tg.run("get", "-u", ".../")
+ tg.grepStderrNot("cannot find package", "did not update packages given wildcard path")
+
+ var expectedPkgPaths = []string{
+ "src/github.com/tmwh/go-get-issue-14450/b",
+ "src/github.com/tmwh/go-get-issue-14450-b-dependency/c",
+ "src/github.com/tmwh/go-get-issue-14450-b-dependency/d",
+ }
+
+ for _, importPath := range expectedPkgPaths {
+ _, err := os.Stat(tg.path(importPath))
+ tg.must(err)
+ }
+ const notExpectedPkgPath = "src/github.com/tmwh/go-get-issue-14450-c-dependency/e"
+ tg.mustNotExist(tg.path(notExpectedPkgPath))
+}
+
+func TestGoEnv(t *testing.T) {
+ tg := testgo(t)
+ tg.parallel()
+ defer tg.cleanup()
+ tg.setenv("GOARCH", "arm")
+ tg.run("env", "GOARCH")
+ tg.grepStdout("^arm$", "GOARCH not honored")
+
+ tg.run("env", "GCCGO")
+ tg.grepStdout(".", "GCCGO unexpectedly empty")
+
+ tg.run("env", "CGO_CFLAGS")
+ tg.grepStdout(".", "default CGO_CFLAGS unexpectedly empty")
+
+ tg.setenv("CGO_CFLAGS", "-foobar")
+ tg.run("env", "CGO_CFLAGS")
+ tg.grepStdout("^-foobar$", "CGO_CFLAGS not honored")
+
+ tg.setenv("CC", "gcc -fmust -fgo -ffaster")
+ tg.run("env", "CC")
+ tg.grepStdout("gcc", "CC not found")
+ tg.run("env", "GOGCCFLAGS")
+ tg.grepStdout("-ffaster", "CC arguments not found")
+}
+
+const (
+ noMatchesPattern = `(?m)^ok.*\[no tests to run\]`
+ okPattern = `(?m)^ok`
+)
+
+func TestMatchesNoTests(t *testing.T) {
+ tg := testgo(t)
+ defer tg.cleanup()
+ // TODO: tg.parallel()
+ tg.run("test", "-run", "ThisWillNotMatch", "testdata/standalone_test.go")
+ tg.grepBoth(noMatchesPattern, "go test did not say [no tests to run]")
+}
+
+func TestMatchesNoTestsDoesNotOverrideBuildFailure(t *testing.T) {
+ tg := testgo(t)
+ defer tg.cleanup()
+ tg.parallel()
+ tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata"))
+ tg.runFail("test", "-run", "ThisWillNotMatch", "syntaxerror")
+ tg.grepBothNot(noMatchesPattern, "go test did say [no tests to run]")
+ tg.grepBoth("FAIL", "go test did not say FAIL")
+}
+
+func TestMatchesNoBenchmarksIsOK(t *testing.T) {
+ tg := testgo(t)
+ defer tg.cleanup()
+ // TODO: tg.parallel()
+ tg.run("test", "-run", "^$", "-bench", "ThisWillNotMatch", "testdata/standalone_benchmark_test.go")
+ tg.grepBothNot(noMatchesPattern, "go test did say [no tests to run]")
+ tg.grepBoth(okPattern, "go test did not say ok")
+}
+
+func TestMatchesOnlyExampleIsOK(t *testing.T) {
+ tg := testgo(t)
+ defer tg.cleanup()
+ // TODO: tg.parallel()
+ tg.run("test", "-run", "Example", "testdata/example1_test.go")
+ tg.grepBothNot(noMatchesPattern, "go test did say [no tests to run]")
+ tg.grepBoth(okPattern, "go test did not say ok")
+}
+
+func TestMatchesOnlyBenchmarkIsOK(t *testing.T) {
+ tg := testgo(t)
+ defer tg.cleanup()
+ // TODO: tg.parallel()
+ tg.run("test", "-run", "^$", "-bench", ".", "testdata/standalone_benchmark_test.go")
+ tg.grepBothNot(noMatchesPattern, "go test did say [no tests to run]")
+ tg.grepBoth(okPattern, "go test did not say ok")
+}
+
+func TestMatchesOnlyTestIsOK(t *testing.T) {
+ tg := testgo(t)
+ defer tg.cleanup()
+ // TODO: tg.parallel()
+ tg.run("test", "-run", "Test", "testdata/standalone_test.go")
+ tg.grepBothNot(noMatchesPattern, "go test did say [no tests to run]")
+ tg.grepBoth(okPattern, "go test did not say ok")
+}
+
+func TestMatchesNoTestsWithSubtests(t *testing.T) {
+ tg := testgo(t)
+ defer tg.cleanup()
+ tg.run("test", "-run", "ThisWillNotMatch", "testdata/standalone_sub_test.go")
+ tg.grepBoth(noMatchesPattern, "go test did not say [no tests to run]")
+}
+
+func TestMatchesNoSubtestsMatch(t *testing.T) {
+ tg := testgo(t)
+ defer tg.cleanup()
+ tg.run("test", "-run", "Test/ThisWillNotMatch", "testdata/standalone_sub_test.go")
+ tg.grepBoth(noMatchesPattern, "go test did not say [no tests to run]")
+}
+
+func TestMatchesNoSubtestsDoesNotOverrideFailure(t *testing.T) {
+ tg := testgo(t)
+ defer tg.cleanup()
+ tg.runFail("test", "-run", "TestThatFails/ThisWillNotMatch", "testdata/standalone_fail_sub_test.go")
+ tg.grepBothNot(noMatchesPattern, "go test did say [no tests to run]")
+ tg.grepBoth("FAIL", "go test did not say FAIL")
+}
+
+func TestMatchesOnlySubtestIsOK(t *testing.T) {
+ tg := testgo(t)
+ defer tg.cleanup()
+ tg.run("test", "-run", "Test/Sub", "testdata/standalone_sub_test.go")
+ tg.grepBothNot(noMatchesPattern, "go test did say [no tests to run]")
+ tg.grepBoth(okPattern, "go test did not say ok")
+}
+
+func TestMatchesNoSubtestsParallel(t *testing.T) {
+ tg := testgo(t)
+ defer tg.cleanup()
+ tg.run("test", "-run", "Test/Sub/ThisWillNotMatch", "testdata/standalone_parallel_sub_test.go")
+ tg.grepBoth(noMatchesPattern, "go test did not say [no tests to run]")
+}
+
+func TestMatchesOnlySubtestParallelIsOK(t *testing.T) {
+ tg := testgo(t)
+ defer tg.cleanup()
+ tg.run("test", "-run", "Test/Sub/Nested", "testdata/standalone_parallel_sub_test.go")
+ tg.grepBothNot(noMatchesPattern, "go test did say [no tests to run]")
+ tg.grepBoth(okPattern, "go test did not say ok")
+}
+
+func TestLinkXImportPathEscape(t *testing.T) {
+ // golang.org/issue/16710
+ tg := testgo(t)
+ defer tg.cleanup()
+ tg.parallel()
+ tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata"))
+ exe := "./linkx" + exeSuffix
+ tg.creatingTemp(exe)
+ tg.run("build", "-o", exe, "-ldflags", "-X=my.pkg.Text=linkXworked", "my.pkg/main")
+ out, err := exec.Command(exe).CombinedOutput()
+ if err != nil {
+ tg.t.Fatal(err)
+ }
+ if string(out) != "linkXworked\n" {
+ tg.t.Log(string(out))
+ tg.t.Fatal(`incorrect output: expected "linkXworked\n"`)
+ }
+}
+
+// Issue 18044.
+func TestLdBindNow(t *testing.T) {
+ tg := testgo(t)
+ defer tg.cleanup()
+ tg.parallel()
+ tg.setenv("LD_BIND_NOW", "1")
+ tg.run("help")
+}
+
+// Issue 18225.
+// This is really a cmd/asm issue but this is a convenient place to test it.
+func TestConcurrentAsm(t *testing.T) {
+ tg := testgo(t)
+ defer tg.cleanup()
+ tg.parallel()
+ asm := `DATA ·constants<>+0x0(SB)/8,$0
+GLOBL ·constants<>(SB),8,$8
+`
+ tg.tempFile("go/src/p/a.s", asm)
+ tg.tempFile("go/src/p/b.s", asm)
+ tg.tempFile("go/src/p/p.go", `package p`)
+ tg.setenv("GOPATH", tg.path("go"))
+ tg.run("build", "p")
+}
diff --git a/libgo/go/cmd/go/go_windows_test.go b/libgo/go/cmd/go/go_windows_test.go
index 53d695cccc8..d8d04aaf497 100644
--- a/libgo/go/cmd/go/go_windows_test.go
+++ b/libgo/go/cmd/go/go_windows_test.go
@@ -5,6 +5,7 @@
package main
import (
+ "internal/testenv"
"io/ioutil"
"os"
"os/exec"
@@ -45,7 +46,7 @@ func TestAbsolutePath(t *testing.T) {
noVolume := file[len(filepath.VolumeName(file)):]
wrongPath := filepath.Join(dir, noVolume)
- output, err := exec.Command("go", "build", noVolume).CombinedOutput()
+ output, err := exec.Command(testenv.GoToolPath(t), "build", noVolume).CombinedOutput()
if err == nil {
t.Fatal("build should fail")
}
diff --git a/libgo/go/cmd/go/help.go b/libgo/go/cmd/go/help.go
index 056a0af1125..0c663ad463f 100644
--- a/libgo/go/cmd/go/help.go
+++ b/libgo/go/cmd/go/help.go
@@ -42,7 +42,7 @@ denotes the package in that directory.
Otherwise, the import path P denotes the package found in
the directory DIR/src/P for some DIR listed in the GOPATH
-environment variable (see 'go help gopath').
+environment variable (For more details see: 'go help gopath').
If no import paths are given, the action applies to the
package in the current directory.
@@ -62,6 +62,9 @@ Go library.
- "cmd" expands to the Go repository's commands and their
internal libraries.
+Import paths beginning with "cmd/" only match source code in
+the Go repository.
+
An import path is a pattern if it includes one or more "..." wildcards,
each of which can match any string, including the empty string and
strings containing slashes. Such a pattern expands to all package
@@ -102,10 +105,10 @@ var helpImportPath = &Command{
Short: "import path syntax",
Long: `
-An import path (see 'go help packages') denotes a package
-stored in the local file system. In general, an import path denotes
-either a standard package (such as "unicode/utf8") or a package
-found in one of the work spaces (see 'go help gopath').
+An import path (see 'go help packages') denotes a package stored in the local
+file system. In general, an import path denotes either a standard package (such
+as "unicode/utf8") or a package found in one of the work spaces (For more
+details see: 'go help gopath').
Relative import paths
@@ -197,6 +200,11 @@ When a version control system supports multiple protocols,
each is tried in turn when downloading. For example, a Git
download tries https://, then git+ssh://.
+By default, downloads are restricted to known secure protocols
+(e.g. https, ssh). To override this setting for Git downloads, the
+GIT_ALLOW_PROTOCOL environment variable can be set (For more details see:
+'go help environment').
+
If the import path is not a known code hosting site and also lacks a
version control qualifier, the go tool attempts to fetch the import
over https/http and looks for a <meta> tag in the document's HTML
@@ -237,8 +245,8 @@ the go tool will verify that https://example.org/?go-get=1 contains the
same meta tag and then git clone https://code.org/r/p/exproj into
GOPATH/src/example.org.
-New downloaded packages are written to the first directory
-listed in the GOPATH environment variable (see 'go help gopath').
+New downloaded packages are written to the first directory listed in the GOPATH
+environment variable (For more details see: 'go help gopath').
The go command attempts to download the version of the
package appropriate for the Go release being used.
@@ -281,8 +289,13 @@ On Unix, the value is a colon-separated string.
On Windows, the value is a semicolon-separated string.
On Plan 9, the value is a list.
-GOPATH must be set to get, build and install packages outside the
-standard Go tree.
+If the environment variable is unset, GOPATH defaults
+to a subdirectory named "go" in the user's home directory
+($HOME/go on Unix, %USERPROFILE%\go on Windows),
+unless that directory holds a Go distribution.
+Run "go env GOPATH" to see the current GOPATH.
+
+See https://golang.org/wiki/SettingGOPATH to set a custom GOPATH.
Each directory listed in GOPATH must have a prescribed structure:
@@ -310,9 +323,9 @@ of DIR/bin. GOBIN must be an absolute path.
Here's an example directory layout:
- GOPATH=/home/user/gocode
+ GOPATH=/home/user/go
- /home/user/gocode/
+ /home/user/go/
src/
foo/
bar/ (go code in package bar)
@@ -338,7 +351,7 @@ Code in or below a directory named "internal" is importable only
by code in the directory tree rooted at the parent of "internal".
Here's an extended version of the directory layout above:
- /home/user/gocode/
+ /home/user/go/
src/
crash/
bang/ (go code in package bang)
@@ -376,7 +389,7 @@ Here's the example from the previous section,
but with the "internal" directory renamed to "vendor"
and a new foo/vendor/crash/bang directory added:
- /home/user/gocode/
+ /home/user/go/
src/
crash/
bang/ (go code in package bang)
@@ -439,7 +452,7 @@ General-purpose environment variables:
The operating system for which to compile code.
Examples are linux, darwin, windows, netbsd.
GOPATH
- See 'go help gopath'.
+ For more details see: 'go help gopath'.
GORACE
Options for the race detector.
See https://golang.org/doc/articles/race_detector.html.
@@ -461,10 +474,15 @@ Environment variables for use with cgo:
CGO_CXXFLAGS
Flags that cgo will pass to the compiler when compiling
C++ code.
+ CGO_FFLAGS
+ Flags that cgo will pass to the compiler when compiling
+ Fortran code.
CGO_LDFLAGS
Flags that cgo will pass to the compiler when linking.
CXX
The command to use to compile C++ code.
+ PKG_CONFIG
+ Path to pkg-config tool.
Architecture-specific environment variables:
@@ -486,6 +504,10 @@ Special-purpose environment variables:
Whether the linker should use external linking mode
when using -linkmode=auto with code that uses cgo.
Set to 0 to disable external linking mode, 1 to enable it.
+ GIT_ALLOW_PROTOCOL
+ Defined by Git. A colon-separated list of schemes that are allowed to be used
+ with git fetch/clone. If set, any scheme not explicitly mentioned will be
+ considered insecure by 'go get'.
`,
}
@@ -577,5 +599,9 @@ are:
Build the listed main packages and everything they import into
position independent executables (PIE). Packages not named
main are ignored.
+
+ -buildmode=plugin
+ Build the listed main packages, plus all packages that they
+ import, into a Go plugin. Packages not named main are ignored.
`,
}
diff --git a/libgo/go/cmd/go/http.go b/libgo/go/cmd/go/http.go
index 05ea5030499..dcb4e9fea5f 100644
--- a/libgo/go/cmd/go/http.go
+++ b/libgo/go/cmd/go/http.go
@@ -12,6 +12,7 @@
package main
import (
+ "cmd/internal/browser"
"crypto/tls"
"fmt"
"io"
@@ -32,6 +33,7 @@ var httpClient = http.DefaultClient
var impatientInsecureHTTPClient = &http.Client{
Timeout: 5 * time.Second,
Transport: &http.Transport{
+ Proxy: http.ProxyFromEnvironment,
TLSClientConfig: &tls.Config{
InsecureSkipVerify: true,
},
@@ -113,3 +115,6 @@ func httpsOrHTTP(importPath string, security securityMode) (urlStr string, body
}
return urlStr, res.Body, nil
}
+
+func queryEscape(s string) string { return url.QueryEscape(s) }
+func openBrowser(url string) bool { return browser.Open(url) }
diff --git a/libgo/go/cmd/go/list.go b/libgo/go/cmd/go/list.go
index 48678e73955..2f240834b2a 100644
--- a/libgo/go/cmd/go/list.go
+++ b/libgo/go/cmd/go/list.go
@@ -59,6 +59,8 @@ syntax of package template. The default output is equivalent to -f
SwigFiles []string // .swig files
SwigCXXFiles []string // .swigcxx files
SysoFiles []string // .syso object files to add to archive
+ TestGoFiles []string // _test.go files in package
+ XTestGoFiles []string // _test.go files outside package
// Cgo directives
CgoCFLAGS []string // cgo: flags for C compiler
@@ -69,20 +71,23 @@ syntax of package template. The default output is equivalent to -f
CgoPkgConfig []string // cgo: pkg-config names
// Dependency information
- Imports []string // import paths used by this package
- Deps []string // all (recursively) imported dependencies
+ Imports []string // import paths used by this package
+ Deps []string // all (recursively) imported dependencies
+ TestImports []string // imports from TestGoFiles
+ XTestImports []string // imports from XTestGoFiles
// Error information
Incomplete bool // this package or a dependency has an error
Error *PackageError // error loading package
DepsErrors []*PackageError // errors loading dependencies
-
- TestGoFiles []string // _test.go files in package
- TestImports []string // imports from TestGoFiles
- XTestGoFiles []string // _test.go files outside package
- XTestImports []string // imports from XTestGoFiles
}
+Packages stored in vendor directories report an ImportPath that includes the
+path to the vendor directory (for example, "d/vendor/p" instead of "p"),
+so that the ImportPath uniquely identifies a given copy of a package.
+The Imports, Deps, TestImports, and XTestImports lists also contain these
+expanded imports paths. See golang.org/s/go15vendor for more about vendoring.
+
The error information, if any, is
type PackageError struct {
diff --git a/libgo/go/cmd/go/main.go b/libgo/go/cmd/go/main.go
index 65ec61bd7db..07fc4e2a905 100644
--- a/libgo/go/cmd/go/main.go
+++ b/libgo/go/cmd/go/main.go
@@ -79,6 +79,7 @@ var commands = []*Command{
cmdClean,
cmdDoc,
cmdEnv,
+ cmdBug,
cmdFix,
cmdFmt,
cmdGenerate,
@@ -114,6 +115,7 @@ func setExitStatus(n int) {
}
var origEnv []string
+var newEnv []envVar
func main() {
_ = go11tag
@@ -134,7 +136,7 @@ func main() {
// Diagnose common mistake: GOPATH==GOROOT.
// This setting is equivalent to not setting GOPATH at all,
// which is not what most people want when they do it.
- if gopath := os.Getenv("GOPATH"); gopath == runtime.GOROOT() {
+ if gopath := buildContext.GOPATH; gopath == runtime.GOROOT() {
fmt.Fprintf(os.Stderr, "warning: GOPATH set to GOROOT (%s) has no effect\n", gopath)
} else {
for _, p := range filepath.SplitList(gopath) {
@@ -146,7 +148,7 @@ func main() {
os.Exit(2)
}
if !filepath.IsAbs(p) {
- fmt.Fprintf(os.Stderr, "go: GOPATH entry is relative; must be absolute path: %q.\nRun 'go help gopath' for usage.\n", p)
+ fmt.Fprintf(os.Stderr, "go: GOPATH entry is relative; must be absolute path: %q.\nFor more details see: 'go help gopath'\n", p)
os.Exit(2)
}
}
@@ -163,7 +165,8 @@ func main() {
// but in practice there might be skew
// This makes sure we all agree.
origEnv = os.Environ()
- for _, env := range mkEnv() {
+ newEnv = mkEnv()
+ for _, env := range newEnv {
if os.Getenv(env.name) != env.value {
os.Setenv(env.name, env.value)
}
diff --git a/libgo/go/cmd/go/pkg.go b/libgo/go/cmd/go/pkg.go
index ea223d6203d..af8c1d959fa 100644
--- a/libgo/go/cmd/go/pkg.go
+++ b/libgo/go/cmd/go/pkg.go
@@ -24,6 +24,8 @@ import (
"unicode"
)
+var ignoreImports bool // control whether we ignore imports in packages
+
// A Package describes a single package found in a directory.
type Package struct {
// Note: These fields are part of the go command's public API.
@@ -180,11 +182,18 @@ func (p *Package) copyBuild(pp *build.Package) {
p.CgoCXXFLAGS = pp.CgoCXXFLAGS
p.CgoLDFLAGS = pp.CgoLDFLAGS
p.CgoPkgConfig = pp.CgoPkgConfig
- p.Imports = pp.Imports
+ // We modify p.Imports in place, so make copy now.
+ p.Imports = make([]string, len(pp.Imports))
+ copy(p.Imports, pp.Imports)
p.TestGoFiles = pp.TestGoFiles
p.TestImports = pp.TestImports
p.XTestGoFiles = pp.XTestGoFiles
p.XTestImports = pp.XTestImports
+ if ignoreImports {
+ p.Imports = nil
+ p.TestImports = nil
+ p.XTestImports = nil
+ }
}
// isStandardImportPath reports whether $GOROOT/src/path should be considered
@@ -338,62 +347,98 @@ func loadImport(path, srcDir string, parent *Package, stk *importStack, importPo
importPath = path
}
- if p := packageCache[importPath]; p != nil {
- if perr := disallowInternal(srcDir, p, stk); perr != p {
- return perr
+ p := packageCache[importPath]
+ if p != nil {
+ p = reusePackage(p, stk)
+ } else {
+ p = new(Package)
+ p.local = isLocal
+ p.ImportPath = importPath
+ packageCache[importPath] = p
+
+ // Load package.
+ // Import always returns bp != nil, even if an error occurs,
+ // in order to return partial information.
+ //
+ // TODO: After Go 1, decide when to pass build.AllowBinary here.
+ // See issue 3268 for mistakes to avoid.
+ buildMode := build.ImportComment
+ if mode&useVendor == 0 || path != origPath {
+ // Not vendoring, or we already found the vendored path.
+ buildMode |= build.IgnoreVendor
}
- if mode&useVendor != 0 {
- if perr := disallowVendor(srcDir, origPath, p, stk); perr != p {
- return perr
- }
+ bp, err := buildContext.Import(path, srcDir, buildMode)
+ bp.ImportPath = importPath
+ if gobin != "" {
+ bp.BinDir = gobin
+ }
+ if err == nil && !isLocal && bp.ImportComment != "" && bp.ImportComment != path &&
+ !strings.Contains(path, "/vendor/") && !strings.HasPrefix(path, "vendor/") {
+ err = fmt.Errorf("code in directory %s expects import %q", bp.Dir, bp.ImportComment)
+ }
+ p.load(stk, bp, err)
+ if p.Error != nil && p.Error.Pos == "" {
+ p = setErrorPos(p, importPos)
}
- return reusePackage(p, stk)
- }
-
- p := new(Package)
- p.local = isLocal
- p.ImportPath = importPath
- packageCache[importPath] = p
- // Load package.
- // Import always returns bp != nil, even if an error occurs,
- // in order to return partial information.
- //
- // TODO: After Go 1, decide when to pass build.AllowBinary here.
- // See issue 3268 for mistakes to avoid.
- buildMode := build.ImportComment
- if mode&useVendor == 0 || path != origPath {
- // Not vendoring, or we already found the vendored path.
- buildMode |= build.IgnoreVendor
- }
- bp, err := buildContext.Import(path, srcDir, buildMode)
- bp.ImportPath = importPath
- if gobin != "" {
- bp.BinDir = gobin
- }
- if err == nil && !isLocal && bp.ImportComment != "" && bp.ImportComment != path &&
- !strings.Contains(path, "/vendor/") && !strings.HasPrefix(path, "vendor/") {
- err = fmt.Errorf("code in directory %s expects import %q", bp.Dir, bp.ImportComment)
- }
- p.load(stk, bp, err)
- if p.Error != nil && p.Error.Pos == "" && len(importPos) > 0 {
- pos := importPos[0]
- pos.Filename = shortPath(pos.Filename)
- p.Error.Pos = pos.String()
+ if origPath != cleanImport(origPath) {
+ p.Error = &PackageError{
+ ImportStack: stk.copy(),
+ Err: fmt.Sprintf("non-canonical import path: %q should be %q", origPath, pathpkg.Clean(origPath)),
+ }
+ p.Incomplete = true
+ }
}
+ // Checked on every import because the rules depend on the code doing the importing.
if perr := disallowInternal(srcDir, p, stk); perr != p {
- return perr
+ return setErrorPos(perr, importPos)
}
if mode&useVendor != 0 {
if perr := disallowVendor(srcDir, origPath, p, stk); perr != p {
- return perr
+ return setErrorPos(perr, importPos)
+ }
+ }
+
+ if p.Name == "main" && parent != nil && parent.Dir != p.Dir {
+ perr := *p
+ perr.Error = &PackageError{
+ ImportStack: stk.copy(),
+ Err: fmt.Sprintf("import %q is a program, not an importable package", path),
}
+ return setErrorPos(&perr, importPos)
}
+ if p.local && parent != nil && !parent.local {
+ perr := *p
+ perr.Error = &PackageError{
+ ImportStack: stk.copy(),
+ Err: fmt.Sprintf("local import %q in non-local package", path),
+ }
+ return setErrorPos(&perr, importPos)
+ }
+
+ return p
+}
+
+func setErrorPos(p *Package, importPos []token.Position) *Package {
+ if len(importPos) > 0 {
+ pos := importPos[0]
+ pos.Filename = shortPath(pos.Filename)
+ p.Error.Pos = pos.String()
+ }
return p
}
+func cleanImport(path string) string {
+ orig := path
+ path = pathpkg.Clean(path)
+ if strings.HasPrefix(orig, "./") && path != ".." && path != "." && !strings.HasPrefix(path, "../") {
+ path = "./" + path
+ }
+ return path
+}
+
var isDirCache = map[string]bool{}
func isDir(path string) bool {
@@ -419,13 +464,26 @@ func vendoredImportPath(parent *Package, path string) (found string) {
dir := filepath.Clean(parent.Dir)
root := filepath.Join(parent.Root, "src")
- if !hasFilePathPrefix(dir, root) {
+ if !hasFilePathPrefix(dir, root) || parent.ImportPath != "command-line-arguments" && filepath.Join(root, parent.ImportPath) != dir {
// Look for symlinks before reporting error.
dir = expandPath(dir)
root = expandPath(root)
}
- if !hasFilePathPrefix(dir, root) || len(dir) <= len(root) || dir[len(root)] != filepath.Separator {
- fatalf("invalid vendoredImportPath: dir=%q root=%q separator=%q", dir, root, string(filepath.Separator))
+
+ if !hasFilePathPrefix(dir, root) || len(dir) <= len(root) || dir[len(root)] != filepath.Separator || parent.ImportPath != "command-line-arguments" && !parent.local && filepath.Join(root, parent.ImportPath) != dir {
+ fatalf("unexpected directory layout:\n"+
+ " import path: %s\n"+
+ " root: %s\n"+
+ " dir: %s\n"+
+ " expand root: %s\n"+
+ " expand dir: %s\n"+
+ " separator: %s",
+ parent.ImportPath,
+ filepath.Join(parent.Root, "src"),
+ filepath.Clean(parent.Dir),
+ root,
+ dir,
+ string(filepath.Separator))
}
vpath := "vendor/" + path
@@ -523,6 +581,14 @@ func disallowInternal(srcDir string, p *Package, stk *importStack) *Package {
return p
}
+ // The generated 'testmain' package is allowed to access testing/internal/...,
+ // as if it were generated into the testing directory tree
+ // (it's actually in a temporary directory outside any Go tree).
+ // This cleans up a former kludge in passing functionality to the testing package.
+ if strings.HasPrefix(p.ImportPath, "testing/internal") && len(*stk) >= 2 && (*stk)[len(*stk)-2] == "testmain" {
+ return p
+ }
+
// We can't check standard packages with gccgo.
if buildContext.Compiler == "gccgo" && p.Standard {
return p
@@ -700,24 +766,23 @@ 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/asm": toTool,
- "cmd/compile": toTool,
- "cmd/cgo": toTool,
- "cmd/cover": toTool,
- "cmd/dist": toTool,
- "cmd/doc": toTool,
- "cmd/fix": toTool,
- "cmd/link": toTool,
- "cmd/newlink": toTool,
- "cmd/nm": toTool,
- "cmd/objdump": toTool,
- "cmd/pack": toTool,
- "cmd/pprof": toTool,
- "cmd/trace": toTool,
- "cmd/vet": toTool,
- "cmd/yacc": toTool,
+ "cmd/addr2line": toTool,
+ "cmd/api": toTool,
+ "cmd/asm": toTool,
+ "cmd/compile": toTool,
+ "cmd/cgo": toTool,
+ "cmd/cover": toTool,
+ "cmd/dist": toTool,
+ "cmd/doc": toTool,
+ "cmd/fix": toTool,
+ "cmd/link": toTool,
+ "cmd/newlink": toTool,
+ "cmd/nm": toTool,
+ "cmd/objdump": toTool,
+ "cmd/pack": toTool,
+ "cmd/pprof": toTool,
+ "cmd/trace": toTool,
+ "cmd/vet": toTool,
"code.google.com/p/go.tools/cmd/cover": stalePath,
"code.google.com/p/go.tools/cmd/godoc": stalePath,
"code.google.com/p/go.tools/cmd/vet": stalePath,
@@ -792,7 +857,7 @@ func (p *Package) load(stk *importStack, bp *build.Package, err error) *Package
useBindir := p.Name == "main"
if !p.Standard {
switch buildBuildmode {
- case "c-archive", "c-shared":
+ case "c-archive", "c-shared", "plugin":
useBindir = false
}
}
@@ -867,11 +932,25 @@ func (p *Package) load(stk *importStack, bp *build.Package, err error) *Package
importPaths = append(importPaths, "syscall")
}
- // Currently build modes c-shared, pie, and -linkshared force
- // external linking mode, and external linking mode forces an
- // import of runtime/cgo.
- if p.Name == "main" && !p.Goroot && (buildBuildmode == "c-shared" || buildBuildmode == "pie" || buildLinkshared) {
- importPaths = append(importPaths, "runtime/cgo")
+ if buildContext.CgoEnabled && p.Name == "main" && !p.Goroot {
+ // Currently build modes c-shared, pie (on systems that do not
+ // support PIE with internal linking mode), plugin, and
+ // -linkshared force external linking mode, as of course does
+ // -ldflags=-linkmode=external. External linking mode forces
+ // an import of runtime/cgo.
+ pieCgo := buildBuildmode == "pie" && (buildContext.GOOS != "linux" || buildContext.GOARCH != "amd64")
+ linkmodeExternal := false
+ for i, a := range buildLdflags {
+ if a == "-linkmode=external" {
+ linkmodeExternal = true
+ }
+ if a == "-linkmode" && i+1 < len(buildLdflags) && buildLdflags[i+1] == "external" {
+ linkmodeExternal = true
+ }
+ }
+ if buildBuildmode == "c-shared" || buildBuildmode == "plugin" || pieCgo || buildLinkshared || linkmodeExternal {
+ importPaths = append(importPaths, "runtime/cgo")
+ }
}
// Everything depends on runtime, except runtime, its internal
@@ -891,6 +970,10 @@ func (p *Package) load(stk *importStack, bp *build.Package, err error) *Package
if p.Name == "main" && goarch == "arm" {
importPaths = append(importPaths, "math")
}
+ // In coverage atomic mode everything depends on sync/atomic.
+ if testCoverMode == "atomic" && (!p.Standard || (p.ImportPath != "runtime/cgo" && p.ImportPath != "runtime/race" && p.ImportPath != "sync/atomic")) {
+ importPaths = append(importPaths, "sync/atomic")
+ }
}
// Runtime and its internal packages depend on runtime/internal/sys,
@@ -953,6 +1036,16 @@ func (p *Package) load(stk *importStack, bp *build.Package, err error) *Package
// Build list of imported packages and full dependency list.
imports := make([]*Package, 0, len(p.Imports))
deps := make(map[string]*Package)
+ save := func(path string, p1 *Package) {
+ // The same import path could produce an error or not,
+ // depending on what tries to import it.
+ // Prefer to record entries with errors, so we can report them.
+ p0 := deps[path]
+ if p0 == nil || p1.Error != nil && (p0.Error == nil || len(p0.Error.ImportStack) > len(p1.Error.ImportStack)) {
+ deps[path] = p1
+ }
+ }
+
for i, path := range importPaths {
if path == "C" {
continue
@@ -961,28 +1054,6 @@ func (p *Package) load(stk *importStack, bp *build.Package, err error) *Package
if !reqStdPkgSrc && p1.Standard {
continue
}
- if p1.Name == "main" {
- p.Error = &PackageError{
- ImportStack: stk.copy(),
- Err: fmt.Sprintf("import %q is a program, not an importable package", path),
- }
- pos := p.build.ImportPos[path]
- if len(pos) > 0 {
- p.Error.Pos = pos[0].String()
- }
- }
- if p1.local {
- if !p.local && p.Error == nil {
- p.Error = &PackageError{
- ImportStack: stk.copy(),
- Err: fmt.Sprintf("local import %q in non-local package", path),
- }
- pos := p.build.ImportPos[path]
- if len(pos) > 0 {
- p.Error.Pos = pos[0].String()
- }
- }
- }
if p.Standard && p.Error == nil && !p1.Standard && p1.Error == nil {
p.Error = &PackageError{
ImportStack: stk.copy(),
@@ -999,15 +1070,11 @@ func (p *Package) load(stk *importStack, bp *build.Package, err error) *Package
if i < len(p.Imports) {
p.Imports[i] = path
}
- deps[path] = p1
+
+ save(path, p1)
imports = append(imports, p1)
for _, dep := range p1.deps {
- // The same import path could produce an error or not,
- // depending on what tries to import it.
- // Prefer to record entries with errors, so we can report them.
- if deps[dep.ImportPath] == nil || dep.Error != nil {
- deps[dep.ImportPath] = dep
- }
+ save(dep.ImportPath, dep)
}
if p1.Incomplete {
p.Incomplete = true
diff --git a/libgo/go/cmd/go/test.go b/libgo/go/cmd/go/test.go
index 1de915a2533..37f6327fffe 100644
--- a/libgo/go/cmd/go/test.go
+++ b/libgo/go/cmd/go/test.go
@@ -135,28 +135,11 @@ const testFlag2 = `
By default, no benchmarks run. To run all benchmarks,
use '-bench .' or '-bench=.'.
- -benchmem
- Print memory allocation statistics for benchmarks.
-
-benchtime t
Run enough iterations of each benchmark to take t, specified
as a time.Duration (for example, -benchtime 1h30s).
The default is 1 second (1s).
- -blockprofile block.out
- Write a goroutine blocking profile to the specified file
- when all tests are complete.
- Writes test binary as -c would.
-
- -blockprofilerate n
- Control the detail provided in goroutine blocking profiles by
- calling runtime.SetBlockProfileRate with n.
- See 'go doc runtime.SetBlockProfileRate'.
- The profiler aims to sample, on average, one blocking event every
- n nanoseconds the program spends blocked. By default,
- if -test.blockprofile is set without this flag, all blocking events
- are recorded, equivalent to -test.blockprofilerate=1.
-
-count n
Run each test and benchmark n times (default 1).
If -cpu is set, run n times for each GOMAXPROCS value.
@@ -182,33 +165,11 @@ const testFlag2 = `
Packages are specified as import paths.
Sets -cover.
- -coverprofile cover.out
- Write a coverage profile to the file after all tests have passed.
- Sets -cover.
-
-cpu 1,2,4
Specify a list of GOMAXPROCS values for which the tests or
benchmarks should be executed. The default is the current value
of GOMAXPROCS.
- -cpuprofile cpu.out
- Write a CPU profile to the specified file before exiting.
- Writes test binary as -c would.
-
- -memprofile mem.out
- Write a memory profile to the file after all tests have passed.
- Writes test binary as -c would.
-
- -memprofilerate n
- Enable more precise (and expensive) memory profiles by setting
- runtime.MemProfileRate. See 'go doc runtime.MemProfileRate'.
- To profile all memory allocations, use -test.memprofilerate=1
- and pass --alloc_space flag to the pprof tool.
-
- -outputdir directory
- Place output files from profiling in the specified directory,
- by default the directory in which "go test" is running.
-
-parallel n
Allow parallel execution of test functions that call t.Parallel.
The value of this flag is the maximum number of tests to run
@@ -234,13 +195,64 @@ const testFlag2 = `
If a test runs longer than t, panic.
The default is 10 minutes (10m).
- -trace trace.out
- Write an execution trace to the specified file before exiting.
-
-v
Verbose output: log all tests as they are run. Also print all
text from Log and Logf calls even if the test succeeds.
+The following flags are also recognized by 'go test' and can be used to
+profile the tests during execution:
+
+ -benchmem
+ Print memory allocation statistics for benchmarks.
+
+ -blockprofile block.out
+ Write a goroutine blocking profile to the specified file
+ when all tests are complete.
+ Writes test binary as -c would.
+
+ -blockprofilerate n
+ Control the detail provided in goroutine blocking profiles by
+ calling runtime.SetBlockProfileRate with n.
+ See 'go doc runtime.SetBlockProfileRate'.
+ The profiler aims to sample, on average, one blocking event every
+ n nanoseconds the program spends blocked. By default,
+ if -test.blockprofile is set without this flag, all blocking events
+ are recorded, equivalent to -test.blockprofilerate=1.
+
+ -coverprofile cover.out
+ Write a coverage profile to the file after all tests have passed.
+ Sets -cover.
+
+ -cpuprofile cpu.out
+ Write a CPU profile to the specified file before exiting.
+ Writes test binary as -c would.
+
+ -memprofile mem.out
+ Write a memory profile to the file after all tests have passed.
+ Writes test binary as -c would.
+
+ -memprofilerate n
+ Enable more precise (and expensive) memory profiles by setting
+ runtime.MemProfileRate. See 'go doc runtime.MemProfileRate'.
+ To profile all memory allocations, use -test.memprofilerate=1
+ and pass --alloc_space flag to the pprof tool.
+
+ -mutexprofile mutex.out
+ Write a mutex contention profile to the specified file
+ when all tests are complete.
+ Writes test binary as -c would.
+
+ -mutexprofilefraction n
+ Sample 1 in n stack traces of goroutines holding a
+ contended mutex.
+
+ -outputdir directory
+ Place output files from profiling in the specified directory,
+ by default the directory in which "go test" is running.
+
+ -trace trace.out
+ Write an execution trace to the specified file before exiting.
+
Each of these flags is also recognized with an optional 'test.' prefix,
as in -test.v. When invoking the generated test binary (the result of
'go test -c') directly, however, the prefix is mandatory.
@@ -322,7 +334,8 @@ If the last comment in the function starts with "Output:" then the output
is compared exactly against the comment (see examples below). If the last
comment begins with "Unordered output:" then the output is compared to the
comment, however the order of the lines is ignored. An example with no such
-comment, or with no text after "Output:" is compiled but not executed.
+comment is compiled but not executed. An example with no text after
+"Output:" is compiled, executed, and expected to produce no output.
Godoc displays the body of ExampleXXX to demonstrate the use
of the function, constant, or variable XXX. An example of a method M with
@@ -381,9 +394,9 @@ var (
var testMainDeps = map[string]bool{
// Dependencies for testmain.
- "testing": true,
- "regexp": true,
- "os": true,
+ "testing": true,
+ "testing/internal/testdeps": true,
+ "os": true,
}
func runTest(cmd *Command, args []string) {
@@ -432,6 +445,11 @@ func runTest(cmd *Command, args []string) {
testStreamOutput = len(pkgArgs) == 0 || testBench ||
(testShowPass && (len(pkgs) == 1 || buildP == 1))
+ // For 'go test -i -o x.test', we want to build x.test. Imply -c to make the logic easier.
+ if buildI && testO != "" {
+ testC = true
+ }
+
var b builder
b.init()
@@ -861,7 +879,7 @@ func (b *builder) test(p *Package) (buildAction, runAction, printAction *action,
if err != nil {
return nil, nil, nil, err
}
- if len(ptest.GoFiles) > 0 {
+ if len(ptest.GoFiles)+len(ptest.CgoFiles) > 0 {
pmain.imports = append(pmain.imports, ptest)
t.ImportTest = true
}
@@ -1089,6 +1107,8 @@ func declareCoverVars(importPath string, files ...string) map[string]*CoverVar {
return coverVars
}
+var noTestsToRun = []byte("\ntesting: warning: no tests to run\n")
+
// runTest is the action for running a test binary.
func (b *builder) runTest(a *action) error {
args := stringList(findExecCmd(), a.deps[0].target, testArgs)
@@ -1179,10 +1199,14 @@ func (b *builder) runTest(a *action) error {
out := buf.Bytes()
t := fmt.Sprintf("%.3fs", time.Since(t0).Seconds())
if err == nil {
+ norun := ""
if testShowPass {
a.testOutput.Write(out)
}
- fmt.Fprintf(a.testOutput, "ok \t%s\t%s%s\n", a.p.ImportPath, t, coveragePercentage(out))
+ if bytes.HasPrefix(out, noTestsToRun[1:]) || bytes.Contains(out, noTestsToRun) {
+ norun = " [no tests to run]"
+ }
+ fmt.Fprintf(a.testOutput, "ok \t%s\t%s%s%s\n", a.p.ImportPath, t, coveragePercentage(out), norun)
return nil
}
@@ -1406,7 +1430,7 @@ func (t *testFuncs) load(filename, pkg string, doImport, seen *bool) error {
}
}
ex := doc.Examples(f)
- sort.Sort(byOrder(ex))
+ sort.Slice(ex, func(i, j int) bool { return ex[i].Order < ex[j].Order })
for _, e := range ex {
*doImport = true // import test file whether executed or not
if e.Output == "" && !e.EmptyOutput {
@@ -1428,12 +1452,6 @@ func checkTestFunc(fn *ast.FuncDecl, arg string) error {
return nil
}
-type byOrder []*doc.Example
-
-func (x byOrder) Len() int { return len(x) }
-func (x byOrder) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
-func (x byOrder) Less(i, j int) bool { return x[i].Order < x[j].Order }
-
var testmainTmpl = template.Must(template.New("main").Parse(`
package main
@@ -1441,8 +1459,8 @@ import (
{{if not .TestMain}}
"os"
{{end}}
- "regexp"
"testing"
+ "testing/internal/testdeps"
{{if .ImportTest}}
{{if .NeedTest}}_test{{else}}_{{end}} {{.Package.ImportPath | printf "%q"}}
@@ -1477,20 +1495,6 @@ var examples = []testing.InternalExample{
{{end}}
}
-var matchPat string
-var matchRe *regexp.Regexp
-
-func matchString(pat, str string) (result bool, err error) {
- if matchRe == nil || matchPat != pat {
- matchPat = pat
- matchRe, err = regexp.Compile(matchPat)
- if err != nil {
- return
- }
- }
- return matchRe.MatchString(str), nil
-}
-
{{if .CoverEnabled}}
// Only updated by init functions, so no need for atomicity.
@@ -1539,7 +1543,7 @@ func main() {
CoveredPackages: {{printf "%q" .Covered}},
})
{{end}}
- m := testing.MainStart(matchString, tests, benchmarks, examples)
+ m := testing.MainStart(testdeps.TestDeps{}, tests, benchmarks, examples)
{{with .TestMain}}
{{.Package}}.{{.Name}}(m)
{{else}}
diff --git a/libgo/go/cmd/go/testdata/src/canonical/a/a.go b/libgo/go/cmd/go/testdata/src/canonical/a/a.go
new file mode 100644
index 00000000000..486cc4843fd
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/src/canonical/a/a.go
@@ -0,0 +1,3 @@
+package a
+
+import _ "c"
diff --git a/libgo/go/cmd/go/testdata/src/canonical/a/c/c.go b/libgo/go/cmd/go/testdata/src/canonical/a/c/c.go
new file mode 100644
index 00000000000..7f96c221c2d
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/src/canonical/a/c/c.go
@@ -0,0 +1 @@
+package c
diff --git a/libgo/go/cmd/go/testdata/src/canonical/b/b.go b/libgo/go/cmd/go/testdata/src/canonical/b/b.go
new file mode 100644
index 00000000000..ce0f4ce3035
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/src/canonical/b/b.go
@@ -0,0 +1,3 @@
+package b
+
+import _ "canonical/a/"
diff --git a/libgo/go/cmd/go/testdata/src/canonical/d/d.go b/libgo/go/cmd/go/testdata/src/canonical/d/d.go
new file mode 100644
index 00000000000..ef7dd7dd461
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/src/canonical/d/d.go
@@ -0,0 +1,3 @@
+package d
+
+import _ "canonical/b"
diff --git a/libgo/go/cmd/go/testdata/cgocover/p.go b/libgo/go/cmd/go/testdata/src/cgocover/p.go
index a6a3891cd4e..a6a3891cd4e 100644
--- a/libgo/go/cmd/go/testdata/cgocover/p.go
+++ b/libgo/go/cmd/go/testdata/src/cgocover/p.go
diff --git a/libgo/go/cmd/go/testdata/cgocover/p_test.go b/libgo/go/cmd/go/testdata/src/cgocover/p_test.go
index a8f057e3587..a8f057e3587 100644
--- a/libgo/go/cmd/go/testdata/cgocover/p_test.go
+++ b/libgo/go/cmd/go/testdata/src/cgocover/p_test.go
diff --git a/libgo/go/cmd/go/testdata/src/cgocover2/p.go b/libgo/go/cmd/go/testdata/src/cgocover2/p.go
new file mode 100644
index 00000000000..a6a3891cd4e
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/src/cgocover2/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/libgo/go/cmd/go/testdata/src/cgocover2/x_test.go b/libgo/go/cmd/go/testdata/src/cgocover2/x_test.go
new file mode 100644
index 00000000000..f4790d2367b
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/src/cgocover2/x_test.go
@@ -0,0 +1,10 @@
+package p_test
+
+import (
+ . "cgocover2"
+ "testing"
+)
+
+func TestF(t *testing.T) {
+ F()
+}
diff --git a/libgo/go/cmd/go/testdata/src/cgocover3/p.go b/libgo/go/cmd/go/testdata/src/cgocover3/p.go
new file mode 100644
index 00000000000..a6a3891cd4e
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/src/cgocover3/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/libgo/go/cmd/go/testdata/src/cgocover3/p_test.go b/libgo/go/cmd/go/testdata/src/cgocover3/p_test.go
new file mode 100644
index 00000000000..c89cd18d0fe
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/src/cgocover3/p_test.go
@@ -0,0 +1 @@
+package p
diff --git a/libgo/go/cmd/go/testdata/src/cgocover3/x_test.go b/libgo/go/cmd/go/testdata/src/cgocover3/x_test.go
new file mode 100644
index 00000000000..97d0e0f0989
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/src/cgocover3/x_test.go
@@ -0,0 +1,10 @@
+package p_test
+
+import (
+ . "cgocover3"
+ "testing"
+)
+
+func TestF(t *testing.T) {
+ F()
+}
diff --git a/libgo/go/cmd/go/testdata/src/cgocover4/notcgo.go b/libgo/go/cmd/go/testdata/src/cgocover4/notcgo.go
new file mode 100644
index 00000000000..c89cd18d0fe
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/src/cgocover4/notcgo.go
@@ -0,0 +1 @@
+package p
diff --git a/libgo/go/cmd/go/testdata/src/cgocover4/p.go b/libgo/go/cmd/go/testdata/src/cgocover4/p.go
new file mode 100644
index 00000000000..a6a3891cd4e
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/src/cgocover4/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/libgo/go/cmd/go/testdata/src/cgocover4/x_test.go b/libgo/go/cmd/go/testdata/src/cgocover4/x_test.go
new file mode 100644
index 00000000000..fd9bae743cc
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/src/cgocover4/x_test.go
@@ -0,0 +1,10 @@
+package p_test
+
+import (
+ . "cgocover4"
+ "testing"
+)
+
+func TestF(t *testing.T) {
+ F()
+}
diff --git a/libgo/go/cmd/go/testdata/src/dupload/dupload.go b/libgo/go/cmd/go/testdata/src/dupload/dupload.go
new file mode 100644
index 00000000000..2f078525b9d
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/src/dupload/dupload.go
@@ -0,0 +1,8 @@
+package main
+
+import (
+ _ "dupload/p2"
+ _ "p"
+)
+
+func main() {}
diff --git a/libgo/go/cmd/go/testdata/src/dupload/p/p.go b/libgo/go/cmd/go/testdata/src/dupload/p/p.go
new file mode 100644
index 00000000000..c89cd18d0fe
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/src/dupload/p/p.go
@@ -0,0 +1 @@
+package p
diff --git a/libgo/go/cmd/go/testdata/src/dupload/p2/p2.go b/libgo/go/cmd/go/testdata/src/dupload/p2/p2.go
new file mode 100644
index 00000000000..8a80979b4e6
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/src/dupload/p2/p2.go
@@ -0,0 +1,3 @@
+package p2
+
+import _ "dupload/vendor/p"
diff --git a/libgo/go/cmd/go/testdata/src/empty/pkg/pkg.go b/libgo/go/cmd/go/testdata/src/empty/pkg/pkg.go
new file mode 100644
index 00000000000..c89cd18d0fe
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/src/empty/pkg/pkg.go
@@ -0,0 +1 @@
+package p
diff --git a/libgo/go/cmd/go/testdata/src/empty/pkgtest/pkg.go b/libgo/go/cmd/go/testdata/src/empty/pkgtest/pkg.go
new file mode 100644
index 00000000000..c89cd18d0fe
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/src/empty/pkgtest/pkg.go
@@ -0,0 +1 @@
+package p
diff --git a/libgo/go/cmd/go/testdata/src/empty/pkgtest/test_test.go b/libgo/go/cmd/go/testdata/src/empty/pkgtest/test_test.go
new file mode 100644
index 00000000000..c89cd18d0fe
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/src/empty/pkgtest/test_test.go
@@ -0,0 +1 @@
+package p
diff --git a/libgo/go/cmd/go/testdata/src/empty/pkgtestxtest/pkg.go b/libgo/go/cmd/go/testdata/src/empty/pkgtestxtest/pkg.go
new file mode 100644
index 00000000000..c89cd18d0fe
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/src/empty/pkgtestxtest/pkg.go
@@ -0,0 +1 @@
+package p
diff --git a/libgo/go/cmd/go/testdata/src/empty/pkgtestxtest/test_test.go b/libgo/go/cmd/go/testdata/src/empty/pkgtestxtest/test_test.go
new file mode 100644
index 00000000000..c89cd18d0fe
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/src/empty/pkgtestxtest/test_test.go
@@ -0,0 +1 @@
+package p
diff --git a/libgo/go/cmd/go/testdata/src/empty/pkgtestxtest/xtest_test.go b/libgo/go/cmd/go/testdata/src/empty/pkgtestxtest/xtest_test.go
new file mode 100644
index 00000000000..9b64e8e1a26
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/src/empty/pkgtestxtest/xtest_test.go
@@ -0,0 +1 @@
+package p_test
diff --git a/libgo/go/cmd/go/testdata/src/empty/pkgxtest/pkg.go b/libgo/go/cmd/go/testdata/src/empty/pkgxtest/pkg.go
new file mode 100644
index 00000000000..c89cd18d0fe
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/src/empty/pkgxtest/pkg.go
@@ -0,0 +1 @@
+package p
diff --git a/libgo/go/cmd/go/testdata/src/empty/pkgxtest/xtest_test.go b/libgo/go/cmd/go/testdata/src/empty/pkgxtest/xtest_test.go
new file mode 100644
index 00000000000..9b64e8e1a26
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/src/empty/pkgxtest/xtest_test.go
@@ -0,0 +1 @@
+package p_test
diff --git a/libgo/go/cmd/go/testdata/src/empty/test/test_test.go b/libgo/go/cmd/go/testdata/src/empty/test/test_test.go
new file mode 100644
index 00000000000..c89cd18d0fe
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/src/empty/test/test_test.go
@@ -0,0 +1 @@
+package p
diff --git a/libgo/go/cmd/go/testdata/src/empty/testxtest/test_test.go b/libgo/go/cmd/go/testdata/src/empty/testxtest/test_test.go
new file mode 100644
index 00000000000..c89cd18d0fe
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/src/empty/testxtest/test_test.go
@@ -0,0 +1 @@
+package p
diff --git a/libgo/go/cmd/go/testdata/src/empty/testxtest/xtest_test.go b/libgo/go/cmd/go/testdata/src/empty/testxtest/xtest_test.go
new file mode 100644
index 00000000000..9b64e8e1a26
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/src/empty/testxtest/xtest_test.go
@@ -0,0 +1 @@
+package p_test
diff --git a/libgo/go/cmd/go/testdata/src/empty/xtest/xtest_test.go b/libgo/go/cmd/go/testdata/src/empty/xtest/xtest_test.go
new file mode 100644
index 00000000000..9b64e8e1a26
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/src/empty/xtest/xtest_test.go
@@ -0,0 +1 @@
+package p_test
diff --git a/libgo/go/cmd/go/testdata/src/gencycle/gencycle.go b/libgo/go/cmd/go/testdata/src/gencycle/gencycle.go
new file mode 100644
index 00000000000..600afd93e93
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/src/gencycle/gencycle.go
@@ -0,0 +1,5 @@
+//go:generate echo hello world
+
+package gencycle
+
+import _ "gencycle"
diff --git a/libgo/go/cmd/go/testdata/src/importmain/ismain/main.go b/libgo/go/cmd/go/testdata/src/importmain/ismain/main.go
new file mode 100644
index 00000000000..bf019076dd5
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/src/importmain/ismain/main.go
@@ -0,0 +1,5 @@
+package main
+
+import _ "importmain/test"
+
+func main() {}
diff --git a/libgo/go/cmd/go/testdata/src/importmain/test/test.go b/libgo/go/cmd/go/testdata/src/importmain/test/test.go
new file mode 100644
index 00000000000..56e54040790
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/src/importmain/test/test.go
@@ -0,0 +1 @@
+package test
diff --git a/libgo/go/cmd/go/testdata/src/importmain/test/test_test.go b/libgo/go/cmd/go/testdata/src/importmain/test/test_test.go
new file mode 100644
index 00000000000..2268a8267ed
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/src/importmain/test/test_test.go
@@ -0,0 +1,6 @@
+package test_test
+
+import "testing"
+import _ "importmain/ismain"
+
+func TestCase(t *testing.T) {}
diff --git a/libgo/go/cmd/go/testdata/src/my.pkg/main/main.go b/libgo/go/cmd/go/testdata/src/my.pkg/main/main.go
new file mode 100644
index 00000000000..c3e8de1276d
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/src/my.pkg/main/main.go
@@ -0,0 +1,7 @@
+package main
+
+import "my.pkg"
+
+func main() {
+ println(pkg.Text)
+}
diff --git a/libgo/go/cmd/go/testdata/src/my.pkg/pkg.go b/libgo/go/cmd/go/testdata/src/my.pkg/pkg.go
new file mode 100644
index 00000000000..17702a680bb
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/src/my.pkg/pkg.go
@@ -0,0 +1,3 @@
+package pkg
+
+var Text = "unset"
diff --git a/libgo/go/cmd/go/testdata/src/testrace/race_test.go b/libgo/go/cmd/go/testdata/src/testrace/race_test.go
new file mode 100644
index 00000000000..264dcf0d8a0
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/src/testrace/race_test.go
@@ -0,0 +1,29 @@
+package testrace
+
+import "testing"
+
+func TestRace(t *testing.T) {
+ for i := 0; i < 10; i++ {
+ c := make(chan int)
+ x := 1
+ go func() {
+ x = 2
+ c <- 1
+ }()
+ x = 3
+ <-c
+ }
+}
+
+func BenchmarkRace(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ c := make(chan int)
+ x := 1
+ go func() {
+ x = 2
+ c <- 1
+ }()
+ x = 3
+ <-c
+ }
+}
diff --git a/libgo/go/cmd/go/testdata/standalone_benchmark_test.go b/libgo/go/cmd/go/testdata/standalone_benchmark_test.go
new file mode 100644
index 00000000000..4850f98d80c
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/standalone_benchmark_test.go
@@ -0,0 +1,6 @@
+package standalone_benchmark
+
+import "testing"
+
+func Benchmark(b *testing.B) {
+}
diff --git a/libgo/go/cmd/go/testdata/standalone_fail_sub_test.go b/libgo/go/cmd/go/testdata/standalone_fail_sub_test.go
new file mode 100644
index 00000000000..ac483f9e0c4
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/standalone_fail_sub_test.go
@@ -0,0 +1,8 @@
+package standalone_fail_sub_test
+
+import "testing"
+
+func TestThatFails(t *testing.T) {
+ t.Run("Sub", func(t *testing.T) {})
+ t.Fail()
+}
diff --git a/libgo/go/cmd/go/testdata/standalone_parallel_sub_test.go b/libgo/go/cmd/go/testdata/standalone_parallel_sub_test.go
new file mode 100644
index 00000000000..d326de0a5ac
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/standalone_parallel_sub_test.go
@@ -0,0 +1,14 @@
+package standalone_parallel_sub_test
+
+import "testing"
+
+func Test(t *testing.T) {
+ ch := make(chan bool, 1)
+ t.Run("Sub", func(t *testing.T) {
+ t.Parallel()
+ <-ch
+ t.Run("Nested", func(t *testing.T) {})
+ })
+ // Ensures that Sub will finish after its t.Run call already returned.
+ ch <- true
+}
diff --git a/libgo/go/cmd/go/testdata/standalone_sub_test.go b/libgo/go/cmd/go/testdata/standalone_sub_test.go
new file mode 100644
index 00000000000..f6c31db9c81
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/standalone_sub_test.go
@@ -0,0 +1,7 @@
+package standalone_sub_test
+
+import "testing"
+
+func Test(t *testing.T) {
+ t.Run("Sub", func(t *testing.T) {})
+}
diff --git a/libgo/go/cmd/go/testdata/testterminal18153/terminal_test.go b/libgo/go/cmd/go/testdata/testterminal18153/terminal_test.go
new file mode 100644
index 00000000000..d662e55ee55
--- /dev/null
+++ b/libgo/go/cmd/go/testdata/testterminal18153/terminal_test.go
@@ -0,0 +1,39 @@
+// Copyright 2016 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.
+
+// +build linux
+
+// This test is run by src/cmd/dist/test.go (cmd_go_test_terminal),
+// and not by cmd/go's tests. This is because this test requires that
+// that it be called with its stdout and stderr being a terminal.
+// dist doesn't run `cmd/go test` against this test directory if
+// dist's stdout/stderr aren't terminals.
+//
+// See issue 18153.
+
+package p
+
+import (
+ "syscall"
+ "testing"
+ "unsafe"
+)
+
+const ioctlReadTermios = syscall.TCGETS
+
+// isTerminal reports whether fd is a terminal.
+func isTerminal(fd uintptr) bool {
+ var termios syscall.Termios
+ _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, fd, ioctlReadTermios, uintptr(unsafe.Pointer(&termios)), 0, 0, 0)
+ return err == 0
+}
+
+func TestIsTerminal(t *testing.T) {
+ if !isTerminal(1) {
+ t.Errorf("stdout is not a terminal")
+ }
+ if !isTerminal(2) {
+ t.Errorf("stderr is not a terminal")
+ }
+}
diff --git a/libgo/go/cmd/go/testflag.go b/libgo/go/cmd/go/testflag.go
index a65ed1f3840..fa53bfcdf09 100644
--- a/libgo/go/cmd/go/testflag.go
+++ b/libgo/go/cmd/go/testflag.go
@@ -50,6 +50,8 @@ var testFlagDefn = []*testFlagSpec{
{name: "memprofilerate", passToTest: true},
{name: "blockprofile", passToTest: true},
{name: "blockprofilerate", passToTest: true},
+ {name: "mutexprofile", passToTest: true},
+ {name: "mutexprofilefraction", passToTest: true},
{name: "outputdir", passToTest: true},
{name: "parallel", passToTest: true},
{name: "run", passToTest: true},
@@ -149,7 +151,7 @@ func testFlags(args []string) (packageNames, passToTest []string) {
testBench = true
case "timeout":
testTimeout = value
- case "blockprofile", "cpuprofile", "memprofile":
+ case "blockprofile", "cpuprofile", "memprofile", "mutexprofile":
testProfile = true
testNeedBinary = true
case "trace":
diff --git a/libgo/go/cmd/go/tool.go b/libgo/go/cmd/go/tool.go
index 65bf1ff33b0..6e2c68fbf53 100644
--- a/libgo/go/cmd/go/tool.go
+++ b/libgo/go/cmd/go/tool.go
@@ -66,7 +66,7 @@ func tool(toolName string) string {
} else {
fmt.Fprintf(os.Stderr, "go tool: no such tool %q\n", toolName)
}
- setExitStatus(3)
+ setExitStatus(2)
exit()
}
return toolPath
diff --git a/libgo/go/cmd/go/vcs.go b/libgo/go/cmd/go/vcs.go
index 53ddbe694ee..fcdce220a7c 100644
--- a/libgo/go/cmd/go/vcs.go
+++ b/libgo/go/cmd/go/vcs.go
@@ -41,7 +41,7 @@ type vcsCmd struct {
resolveRepo func(v *vcsCmd, rootDir, remoteRepo string) (realRepo string, err error)
}
-var isSecureScheme = map[string]bool{
+var defaultSecureScheme = map[string]bool{
"https": true,
"git+ssh": true,
"bzr+ssh": true,
@@ -55,7 +55,25 @@ func (v *vcsCmd) isSecure(repo string) bool {
// If repo is not a URL, it's not secure.
return false
}
- return isSecureScheme[u.Scheme]
+ return v.isSecureScheme(u.Scheme)
+}
+
+func (v *vcsCmd) isSecureScheme(scheme string) bool {
+ switch v.cmd {
+ case "git":
+ // GIT_ALLOW_PROTOCOL is an environment variable defined by Git. It is a
+ // colon-separated list of schemes that are allowed to be used with git
+ // fetch/clone. Any scheme not mentioned will be considered insecure.
+ if allow := os.Getenv("GIT_ALLOW_PROTOCOL"); allow != "" {
+ for _, s := range strings.Split(allow, ":") {
+ if s == scheme {
+ return true
+ }
+ }
+ return false
+ }
+ }
+ return defaultSecureScheme[scheme]
}
// A tagCmd describes a command to list available tags
@@ -482,7 +500,7 @@ func vcsFromDir(dir, srcRoot string) (vcs *vcsCmd, root string, err error) {
origDir := dir
for len(dir) > len(srcRoot) {
for _, vcs := range vcsList {
- if fi, err := os.Stat(filepath.Join(dir, "."+vcs.cmd)); err == nil && fi.IsDir() {
+ if _, err := os.Stat(filepath.Join(dir, "."+vcs.cmd)); err == nil {
return vcs, filepath.ToSlash(dir[len(srcRoot)+1:]), nil
}
}
@@ -510,6 +528,9 @@ type repoRoot struct {
// root is the import path corresponding to the root of the
// repository
root string
+
+ // isCustom is true for custom import paths (those defined by HTML meta tags)
+ isCustom bool
}
var httpPrefixRE = regexp.MustCompile(`^https?:`)
@@ -612,7 +633,7 @@ func repoRootFromVCSPaths(importPath, scheme string, security securityMode, vcsP
match["repo"] = scheme + "://" + match["repo"]
} else {
for _, scheme := range vcs.scheme {
- if security == secure && !isSecureScheme[scheme] {
+ if security == secure && !vcs.isSecureScheme(scheme) {
continue
}
if vcs.ping(scheme, match["repo"]) == nil {
@@ -661,10 +682,10 @@ func repoRootForImportDynamic(importPath string, security securityMode) (*repoRo
// Find the matched meta import.
mmi, err := matchGoImport(imports, importPath)
if err != nil {
- if err != errNoMatch {
+ if _, ok := err.(ImportMismatchError); !ok {
return nil, fmt.Errorf("parse %s: %v", urlStr, err)
}
- return nil, fmt.Errorf("parse %s: no go-import meta tags", urlStr)
+ return nil, fmt.Errorf("parse %s: no go-import meta tags (%s)", urlStr, err)
}
if buildV {
log.Printf("get %q: found meta tag %#v at %s", importPath, mmi, urlStr)
@@ -695,9 +716,10 @@ func repoRootForImportDynamic(importPath string, security securityMode) (*repoRo
return nil, fmt.Errorf("%s: invalid repo root %q; no scheme", urlStr, mmi.RepoRoot)
}
rr := &repoRoot{
- vcs: vcsByCmd(mmi.VCS),
- repo: mmi.RepoRoot,
- root: mmi.Prefix,
+ vcs: vcsByCmd(mmi.VCS),
+ repo: mmi.RepoRoot,
+ root: mmi.Prefix,
+ isCustom: true,
}
if rr.vcs == nil {
return nil, fmt.Errorf("%s: unknown vcs %q", urlStr, mmi.VCS)
@@ -764,9 +786,6 @@ type metaImport struct {
Prefix, VCS, RepoRoot string
}
-// errNoMatch is returned from matchGoImport when there's no applicable match.
-var errNoMatch = errors.New("no import match")
-
func splitPathHasPrefix(path, prefix []string) bool {
if len(path) < len(prefix) {
return false
@@ -779,28 +798,45 @@ func splitPathHasPrefix(path, prefix []string) bool {
return true
}
+// A ImportMismatchError is returned where metaImport/s are present
+// but none match our import path.
+type ImportMismatchError struct {
+ importPath string
+ mismatches []string // the meta imports that were discarded for not matching our importPath
+}
+
+func (m ImportMismatchError) Error() string {
+ formattedStrings := make([]string, len(m.mismatches))
+ for i, pre := range m.mismatches {
+ formattedStrings[i] = fmt.Sprintf("meta tag %s did not match import path %s", pre, m.importPath)
+ }
+ return strings.Join(formattedStrings, ", ")
+}
+
// matchGoImport returns the metaImport from imports matching importPath.
// An error is returned if there are multiple matches.
// errNoMatch is returned if none match.
-func matchGoImport(imports []metaImport, importPath string) (_ metaImport, err error) {
+func matchGoImport(imports []metaImport, importPath string) (metaImport, error) {
match := -1
imp := strings.Split(importPath, "/")
+
+ errImportMismatch := ImportMismatchError{importPath: importPath}
for i, im := range imports {
pre := strings.Split(im.Prefix, "/")
if !splitPathHasPrefix(imp, pre) {
+ errImportMismatch.mismatches = append(errImportMismatch.mismatches, im.Prefix)
continue
}
if match != -1 {
- err = fmt.Errorf("multiple meta tags match import path %q", importPath)
- return
+ return metaImport{}, fmt.Errorf("multiple meta tags match import path %q", importPath)
}
match = i
}
+
if match == -1 {
- err = errNoMatch
- return
+ return metaImport{}, errImportMismatch
}
return imports[match], nil
}
diff --git a/libgo/go/cmd/go/vcs_test.go b/libgo/go/cmd/go/vcs_test.go
index 25e3866df06..c73f5d0e85b 100644
--- a/libgo/go/cmd/go/vcs_test.go
+++ b/libgo/go/cmd/go/vcs_test.go
@@ -102,7 +102,7 @@ func TestRepoRootForImportPath(t *testing.T) {
"git.openstack.org/openstack/swift.git",
&repoRoot{
vcs: vcsGit,
- repo: "https://git.openstack.org/openstack/swift",
+ repo: "https://git.openstack.org/openstack/swift.git",
},
},
{
@@ -174,11 +174,23 @@ func TestFromDir(t *testing.T) {
}
defer os.RemoveAll(tempDir)
- for _, vcs := range vcsList {
+ for j, vcs := range vcsList {
dir := filepath.Join(tempDir, "example.com", vcs.name, "."+vcs.cmd)
- err := os.MkdirAll(dir, 0755)
- if err != nil {
- t.Fatal(err)
+ if j&1 == 0 {
+ err := os.MkdirAll(dir, 0755)
+ if err != nil {
+ t.Fatal(err)
+ }
+ } else {
+ err := os.MkdirAll(filepath.Dir(dir), 0755)
+ if err != nil {
+ t.Fatal(err)
+ }
+ f, err := os.Create(dir)
+ if err != nil {
+ t.Fatal(err)
+ }
+ f.Close()
}
want := repoRoot{
@@ -229,6 +241,46 @@ func TestIsSecure(t *testing.T) {
}
}
+func TestIsSecureGitAllowProtocol(t *testing.T) {
+ tests := []struct {
+ vcs *vcsCmd
+ url string
+ secure bool
+ }{
+ // Same as TestIsSecure to verify same behavior.
+ {vcsGit, "http://example.com/foo.git", false},
+ {vcsGit, "https://example.com/foo.git", true},
+ {vcsBzr, "http://example.com/foo.bzr", false},
+ {vcsBzr, "https://example.com/foo.bzr", true},
+ {vcsSvn, "http://example.com/svn", false},
+ {vcsSvn, "https://example.com/svn", true},
+ {vcsHg, "http://example.com/foo.hg", false},
+ {vcsHg, "https://example.com/foo.hg", true},
+ {vcsGit, "user@server:path/to/repo.git", false},
+ {vcsGit, "user@server:", false},
+ {vcsGit, "server:repo.git", false},
+ {vcsGit, "server:path/to/repo.git", false},
+ {vcsGit, "example.com:path/to/repo.git", false},
+ {vcsGit, "path/that/contains/a:colon/repo.git", false},
+ {vcsHg, "ssh://user@example.com/path/to/repo.hg", true},
+ // New behavior.
+ {vcsGit, "ssh://user@example.com/foo.git", false},
+ {vcsGit, "foo://example.com/bar.git", true},
+ {vcsHg, "foo://example.com/bar.hg", false},
+ {vcsSvn, "foo://example.com/svn", false},
+ {vcsBzr, "foo://example.com/bar.bzr", false},
+ }
+
+ defer os.Unsetenv("GIT_ALLOW_PROTOCOL")
+ os.Setenv("GIT_ALLOW_PROTOCOL", "https:foo")
+ for _, test := range tests {
+ secure := test.vcs.isSecure(test.url)
+ if secure != test.secure {
+ t.Errorf("%s isSecure(%q) = %t; want %t", test.vcs, test.url, secure, test.secure)
+ }
+ }
+}
+
func TestMatchGoImport(t *testing.T) {
tests := []struct {
imports []metaImport
@@ -306,6 +358,13 @@ func TestMatchGoImport(t *testing.T) {
path: "example.com",
err: errors.New("pathologically short path"),
},
+ {
+ imports: []metaImport{
+ {Prefix: "example.com/user/foo", VCS: "git", RepoRoot: "https://example.com/repo/target"},
+ },
+ path: "different.example.com/user/foo",
+ err: errors.New("meta tags do not match import path"),
+ },
}
for _, test := range tests {
diff --git a/libgo/go/cmd/go/vendor_test.go b/libgo/go/cmd/go/vendor_test.go
index 226b5377b98..deec02e3413 100644
--- a/libgo/go/cmd/go/vendor_test.go
+++ b/libgo/go/cmd/go/vendor_test.go
@@ -188,6 +188,42 @@ func TestVendorGetUpdate(t *testing.T) {
tg.run("get", "-u", "github.com/rsc/go-get-issue-11864")
}
+func TestVendorGetU(t *testing.T) {
+ testenv.MustHaveExternalNetwork(t)
+
+ tg := testgo(t)
+ defer tg.cleanup()
+ tg.makeTempdir()
+ tg.setenv("GOPATH", tg.path("."))
+ tg.run("get", "-u", "github.com/rsc/go-get-issue-11864")
+}
+
+func TestVendorGetTU(t *testing.T) {
+ testenv.MustHaveExternalNetwork(t)
+
+ tg := testgo(t)
+ defer tg.cleanup()
+ tg.makeTempdir()
+ tg.setenv("GOPATH", tg.path("."))
+ tg.run("get", "-t", "-u", "github.com/rsc/go-get-issue-11864/...")
+}
+
+func TestVendorGetBadVendor(t *testing.T) {
+ testenv.MustHaveExternalNetwork(t)
+
+ for _, suffix := range []string{"bad/imp", "bad/imp2", "bad/imp3", "..."} {
+ t.Run(suffix, func(t *testing.T) {
+ tg := testgo(t)
+ defer tg.cleanup()
+ tg.makeTempdir()
+ tg.setenv("GOPATH", tg.path("."))
+ tg.runFail("get", "-t", "-u", "github.com/rsc/go-get-issue-18219/"+suffix)
+ tg.grepStderr("must be imported as", "did not find error about vendor import")
+ tg.mustNotExist(tg.path("src/github.com/rsc/vendor"))
+ })
+ }
+}
+
func TestGetSubmodules(t *testing.T) {
testenv.MustHaveExternalNetwork(t)
diff --git a/libgo/go/cmd/gofmt/doc.go b/libgo/go/cmd/gofmt/doc.go
index 9d0cd328623..8b22f03f653 100644
--- a/libgo/go/cmd/gofmt/doc.go
+++ b/libgo/go/cmd/gofmt/doc.go
@@ -32,7 +32,8 @@ The flags are:
-w
Do not print reformatted sources to standard output.
If a file's formatting is different from gofmt's, overwrite it
- with gofmt's version.
+ with gofmt's version. If an error occurred during overwriting,
+ the original file is restored from an automatic backup.
Debugging support:
-cpuprofile filename
@@ -98,3 +99,5 @@ This may result in changes that are incompatible with earlier versions of Go.
package main
// BUG(rsc): The implementation of -r is a bit slow.
+// BUG(gri): If -w fails, the restored original file may not have some of the
+// original file attributes.
diff --git a/libgo/go/cmd/gofmt/gofmt.go b/libgo/go/cmd/gofmt/gofmt.go
index f29b6cb83d9..e1ef0ddb837 100644
--- a/libgo/go/cmd/gofmt/gofmt.go
+++ b/libgo/go/cmd/gofmt/gofmt.go
@@ -18,6 +18,7 @@ import (
"os"
"os/exec"
"path/filepath"
+ "runtime"
"runtime/pprof"
"strings"
)
@@ -72,13 +73,19 @@ func isGoFile(f os.FileInfo) bool {
// If in == nil, the source is the contents of the file with the given filename.
func processFile(filename string, in io.Reader, out io.Writer, stdin bool) error {
+ var perm os.FileMode = 0644
if in == nil {
f, err := os.Open(filename)
if err != nil {
return err
}
defer f.Close()
+ fi, err := f.Stat()
+ if err != nil {
+ return err
+ }
in = f
+ perm = fi.Mode().Perm()
}
src, err := ioutil.ReadAll(in)
@@ -116,7 +123,17 @@ func processFile(filename string, in io.Reader, out io.Writer, stdin bool) error
fmt.Fprintln(out, filename)
}
if *write {
- err = ioutil.WriteFile(filename, res, 0644)
+ // make a temporary backup before overwriting original
+ bakname, err := backupFile(filename+".", src, perm)
+ if err != nil {
+ return err
+ }
+ err = ioutil.WriteFile(filename, res, perm)
+ if err != nil {
+ os.Rename(bakname, filename)
+ return err
+ }
+ err = os.Remove(bakname)
if err != nil {
return err
}
@@ -235,3 +252,36 @@ func diff(b1, b2 []byte) (data []byte, err error) {
return
}
+
+const chmodSupported = runtime.GOOS != "windows"
+
+// backupFile writes data to a new file named filename<number> with permissions perm,
+// with <number randomly chosen such that the file name is unique. backupFile returns
+// the chosen file name.
+func backupFile(filename string, data []byte, perm os.FileMode) (string, error) {
+ // create backup file
+ f, err := ioutil.TempFile(filepath.Dir(filename), filepath.Base(filename))
+ if err != nil {
+ return "", err
+ }
+ bakname := f.Name()
+ if chmodSupported {
+ err = f.Chmod(perm)
+ if err != nil {
+ f.Close()
+ os.Remove(bakname)
+ return bakname, err
+ }
+ }
+
+ // write data to backup file
+ n, err := f.Write(data)
+ if err == nil && n < len(data) {
+ err = io.ErrShortWrite
+ }
+ if err1 := f.Close(); err == nil {
+ err = err1
+ }
+
+ return bakname, err
+}
diff --git a/libgo/go/cmd/gofmt/gofmt_test.go b/libgo/go/cmd/gofmt/gofmt_test.go
index dea012764b3..b7ca9e8d119 100644
--- a/libgo/go/cmd/gofmt/gofmt_test.go
+++ b/libgo/go/cmd/gofmt/gofmt_test.go
@@ -171,3 +171,16 @@ func TestCRLF(t *testing.T) {
t.Errorf("%s contains CR's", golden)
}
}
+
+func TestBackupFile(t *testing.T) {
+ dir, err := ioutil.TempDir("", "gofmt_test")
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer os.RemoveAll(dir)
+ name, err := backupFile(filepath.Join(dir, "foo.go"), []byte(" package main"), 0644)
+ if err != nil {
+ t.Fatal(err)
+ }
+ t.Logf("Created: %s", name)
+}
diff --git a/libgo/go/cmd/gofmt/simplify.go b/libgo/go/cmd/gofmt/simplify.go
index 2ebf4cde0be..1a0e8174afa 100644
--- a/libgo/go/cmd/gofmt/simplify.go
+++ b/libgo/go/cmd/gofmt/simplify.go
@@ -17,47 +17,33 @@ func (s simplifier) Visit(node ast.Node) ast.Visitor {
case *ast.CompositeLit:
// array, slice, and map composite literals may be simplified
outer := n
- var eltType ast.Expr
+ var keyType, eltType ast.Expr
switch typ := outer.Type.(type) {
case *ast.ArrayType:
eltType = typ.Elt
case *ast.MapType:
+ keyType = typ.Key
eltType = typ.Value
}
if eltType != nil {
+ var ktyp reflect.Value
+ if keyType != nil {
+ ktyp = reflect.ValueOf(keyType)
+ }
typ := reflect.ValueOf(eltType)
for i, x := range outer.Elts {
px := &outer.Elts[i]
// look at value of indexed/named elements
if t, ok := x.(*ast.KeyValueExpr); ok {
+ if keyType != nil {
+ s.simplifyLiteral(ktyp, keyType, t.Key, &t.Key)
+ }
x = t.Value
px = &t.Value
}
- ast.Walk(s, x) // simplify x
- // if the element is a composite literal and its literal type
- // matches the outer literal's element type exactly, the inner
- // literal type may be omitted
- if inner, ok := x.(*ast.CompositeLit); ok {
- if match(nil, typ, reflect.ValueOf(inner.Type)) {
- inner.Type = nil
- }
- }
- // if the outer literal's element type is a pointer type *T
- // and the element is & of a composite literal of type T,
- // the inner &T may be omitted.
- if ptr, ok := eltType.(*ast.StarExpr); ok {
- if addr, ok := x.(*ast.UnaryExpr); ok && addr.Op == token.AND {
- if inner, ok := addr.X.(*ast.CompositeLit); ok {
- if match(nil, reflect.ValueOf(ptr.X), reflect.ValueOf(inner.Type)) {
- inner.Type = nil // drop T
- *px = inner // drop &
- }
- }
- }
- }
+ s.simplifyLiteral(typ, eltType, x, px)
}
-
// node was simplified - stop walk (there are no subnodes to simplify)
return nil
}
@@ -113,6 +99,32 @@ func (s simplifier) Visit(node ast.Node) ast.Visitor {
return s
}
+func (s simplifier) simplifyLiteral(typ reflect.Value, astType, x ast.Expr, px *ast.Expr) {
+ ast.Walk(s, x) // simplify x
+
+ // if the element is a composite literal and its literal type
+ // matches the outer literal's element type exactly, the inner
+ // literal type may be omitted
+ if inner, ok := x.(*ast.CompositeLit); ok {
+ if match(nil, typ, reflect.ValueOf(inner.Type)) {
+ inner.Type = nil
+ }
+ }
+ // if the outer literal's element type is a pointer type *T
+ // and the element is & of a composite literal of type T,
+ // the inner &T may be omitted.
+ if ptr, ok := astType.(*ast.StarExpr); ok {
+ if addr, ok := x.(*ast.UnaryExpr); ok && addr.Op == token.AND {
+ if inner, ok := addr.X.(*ast.CompositeLit); ok {
+ if match(nil, reflect.ValueOf(ptr.X), reflect.ValueOf(inner.Type)) {
+ inner.Type = nil // drop T
+ *px = inner // drop &
+ }
+ }
+ }
+ }
+}
+
func isBlank(x ast.Expr) bool {
ident, ok := x.(*ast.Ident)
return ok && ident.Name == "_"
diff --git a/libgo/go/cmd/gofmt/testdata/composites.golden b/libgo/go/cmd/gofmt/testdata/composites.golden
index fc9c98e625b..a06a69d0965 100644
--- a/libgo/go/cmd/gofmt/testdata/composites.golden
+++ b/libgo/go/cmd/gofmt/testdata/composites.golden
@@ -6,6 +6,10 @@ type T struct {
x, y int
}
+type T2 struct {
+ w, z int
+}
+
var _ = [42]T{
{},
{1, 2},
@@ -202,3 +206,13 @@ var pieces4 = []*Piece{
{2, 0, Point{4, 1}, []Point{{0, 0}, {1, 0}, {1, 0}, {1, 0}}, nil, nil},
{3, 0, Point{1, 4}, []Point{{0, 0}, {0, 1}, {0, 1}, {0, 1}}, nil, nil},
}
+
+var _ = map[T]T2{
+ {1, 2}: {3, 4},
+ {5, 6}: {7, 8},
+}
+
+var _ = map[*T]*T2{
+ {1, 2}: {3, 4},
+ {5, 6}: {7, 8},
+}
diff --git a/libgo/go/cmd/gofmt/testdata/composites.input b/libgo/go/cmd/gofmt/testdata/composites.input
index fc7598af99e..9d28ac7ed31 100644
--- a/libgo/go/cmd/gofmt/testdata/composites.input
+++ b/libgo/go/cmd/gofmt/testdata/composites.input
@@ -6,6 +6,10 @@ type T struct {
x, y int
}
+type T2 struct {
+ w, z int
+}
+
var _ = [42]T{
T{},
T{1, 2},
@@ -202,3 +206,13 @@ var pieces4 = []*Piece{
&Piece{2, 0, Point{4, 1}, []Point{Point{0, 0}, Point{1, 0}, Point{1, 0}, Point{1, 0}}, nil, nil},
&Piece{3, 0, Point{1, 4}, []Point{Point{0, 0}, Point{0, 1}, Point{0, 1}, Point{0, 1}}, nil, nil},
}
+
+var _ = map[T]T2{
+ T{1, 2}: T2{3, 4},
+ T{5, 6}: T2{7, 8},
+}
+
+var _ = map[*T]*T2{
+ &T{1, 2}: &T2{3, 4},
+ &T{5, 6}: &T2{7, 8},
+}
diff --git a/libgo/go/cmd/internal/browser/browser.go b/libgo/go/cmd/internal/browser/browser.go
new file mode 100644
index 00000000000..897086f4717
--- /dev/null
+++ b/libgo/go/cmd/internal/browser/browser.go
@@ -0,0 +1,46 @@
+// Copyright 2016 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 browser provides utilities for interacting with users' browsers.
+package browser
+
+import (
+ "os"
+ "os/exec"
+ "runtime"
+)
+
+// Commands returns a list of possible commands to use to open a url.
+func Commands() [][]string {
+ var cmds [][]string
+ if exe := os.Getenv("BROWSER"); exe != "" {
+ cmds = append(cmds, []string{exe})
+ }
+ switch runtime.GOOS {
+ case "darwin":
+ cmds = append(cmds, []string{"/usr/bin/open"})
+ case "windows":
+ cmds = append(cmds, []string{"cmd", "/c", "start"})
+ default:
+ cmds = append(cmds, []string{"xdg-open"})
+ }
+ cmds = append(cmds,
+ []string{"chrome"},
+ []string{"google-chrome"},
+ []string{"chromium"},
+ []string{"firefox"},
+ )
+ return cmds
+}
+
+// Open tries to open url in a browser and reports whether it succeeded.
+func Open(url string) bool {
+ for _, args := range Commands() {
+ cmd := exec.Command(args[0], append(args[1:], url)...)
+ if cmd.Start() == nil {
+ return true
+ }
+ }
+ return false
+}