Commit 7d7d64c1 by Ian Lance Taylor

libgo: Add sources for go, cgo, and gofmt commands.

The new commands are not yet built.  That will be done
separately.

Also include a few changes to go/build to support them.

From-SVN: r219272
parent efcdb22f
...@@ -26,6 +26,7 @@ STAMP = echo timestamp > ...@@ -26,6 +26,7 @@ STAMP = echo timestamp >
toolexecdir = $(glibgo_toolexecdir) toolexecdir = $(glibgo_toolexecdir)
toolexeclibdir = $(glibgo_toolexeclibdir) toolexeclibdir = $(glibgo_toolexeclibdir)
toolexeclibgodir = $(nover_glibgo_toolexeclibdir)/go/$(gcc_version)/$(target_alias) toolexeclibgodir = $(nover_glibgo_toolexeclibdir)/go/$(gcc_version)/$(target_alias)
libexecsubdir = $(libexecdir)/gcc/$(target_alias)/$(gcc_version)
LIBFFI = @LIBFFI@ LIBFFI = @LIBFFI@
LIBFFIINCS = @LIBFFIINCS@ LIBFFIINCS = @LIBFFIINCS@
...@@ -1007,6 +1008,7 @@ s-version: Makefile ...@@ -1007,6 +1008,7 @@ s-version: Makefile
echo 'const theVersion = "'`$(GOC) --version | sed 1q`'"' >> version.go.tmp echo 'const theVersion = "'`$(GOC) --version | sed 1q`'"' >> version.go.tmp
echo 'const theGoarch = "'$(GOARCH)'"' >> version.go.tmp echo 'const theGoarch = "'$(GOARCH)'"' >> version.go.tmp
echo 'const theGoos = "'$(GOOS)'"' >> version.go.tmp echo 'const theGoos = "'$(GOOS)'"' >> version.go.tmp
echo 'const theGccgoToolDir = "$(libexecsubdir)"' >> version.go.tmp
$(SHELL) $(srcdir)/mvifdiff.sh version.go.tmp version.go $(SHELL) $(srcdir)/mvifdiff.sh version.go.tmp version.go
$(STAMP) $@ $(STAMP) $@
......
...@@ -454,6 +454,7 @@ STAMP = echo timestamp > ...@@ -454,6 +454,7 @@ STAMP = echo timestamp >
toolexecdir = $(glibgo_toolexecdir) toolexecdir = $(glibgo_toolexecdir)
toolexeclibdir = $(glibgo_toolexeclibdir) toolexeclibdir = $(glibgo_toolexeclibdir)
toolexeclibgodir = $(nover_glibgo_toolexeclibdir)/go/$(gcc_version)/$(target_alias) toolexeclibgodir = $(nover_glibgo_toolexeclibdir)/go/$(gcc_version)/$(target_alias)
libexecsubdir = $(libexecdir)/gcc/$(target_alias)/$(gcc_version)
WARN_CFLAGS = $(WARN_FLAGS) $(WERROR) WARN_CFLAGS = $(WARN_FLAGS) $(WERROR)
# -I/-D flags to pass when compiling. # -I/-D flags to pass when compiling.
...@@ -4392,6 +4393,7 @@ s-version: Makefile ...@@ -4392,6 +4393,7 @@ s-version: Makefile
echo 'const theVersion = "'`$(GOC) --version | sed 1q`'"' >> version.go.tmp echo 'const theVersion = "'`$(GOC) --version | sed 1q`'"' >> version.go.tmp
echo 'const theGoarch = "'$(GOARCH)'"' >> version.go.tmp echo 'const theGoarch = "'$(GOARCH)'"' >> version.go.tmp
echo 'const theGoos = "'$(GOOS)'"' >> version.go.tmp echo 'const theGoos = "'$(GOOS)'"' >> version.go.tmp
echo 'const theGccgoToolDir = "$(libexecsubdir)"' >> version.go.tmp
$(SHELL) $(srcdir)/mvifdiff.sh version.go.tmp version.go $(SHELL) $(srcdir)/mvifdiff.sh version.go.tmp version.go
$(STAMP) $@ $(STAMP) $@
......
// Copyright 2009 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.
// Parse input AST and prepare Prog structure.
package main
import (
"fmt"
"go/ast"
"go/parser"
"go/scanner"
"go/token"
"os"
"path/filepath"
"strings"
)
func parse(name string, flags parser.Mode) *ast.File {
ast1, err := parser.ParseFile(fset, name, nil, flags)
if err != nil {
if list, ok := err.(scanner.ErrorList); ok {
// If err is a scanner.ErrorList, its String will print just
// the first error and then (+n more errors).
// Instead, turn it into a new Error that will return
// details for all the errors.
for _, e := range list {
fmt.Fprintln(os.Stderr, e)
}
os.Exit(2)
}
fatalf("parsing %s: %s", name, err)
}
return ast1
}
func sourceLine(n ast.Node) int {
return fset.Position(n.Pos()).Line
}
// ReadGo populates f with information learned from reading the
// Go source file with the given file name. It gathers the C preamble
// attached to the import "C" comment, a list of references to C.xxx,
// a list of exported functions, and the actual AST, to be rewritten and
// printed.
func (f *File) ReadGo(name string) {
// Create absolute path for file, so that it will be used in error
// messages and recorded in debug line number information.
// This matches the rest of the toolchain. See golang.org/issue/5122.
if aname, err := filepath.Abs(name); err == nil {
name = aname
}
// Two different parses: once with comments, once without.
// The printer is not good enough at printing comments in the
// right place when we start editing the AST behind its back,
// so we use ast1 to look for the doc comments on import "C"
// and on exported functions, and we use ast2 for translating
// and reprinting.
ast1 := parse(name, parser.ParseComments)
ast2 := parse(name, 0)
f.Package = ast1.Name.Name
f.Name = make(map[string]*Name)
// In ast1, find the import "C" line and get any extra C preamble.
sawC := false
for _, decl := range ast1.Decls {
d, ok := decl.(*ast.GenDecl)
if !ok {
continue
}
for _, spec := range d.Specs {
s, ok := spec.(*ast.ImportSpec)
if !ok || string(s.Path.Value) != `"C"` {
continue
}
sawC = true
if s.Name != nil {
error_(s.Path.Pos(), `cannot rename import "C"`)
}
cg := s.Doc
if cg == nil && len(d.Specs) == 1 {
cg = d.Doc
}
if cg != nil {
f.Preamble += fmt.Sprintf("#line %d %q\n", sourceLine(cg), name)
f.Preamble += commentText(cg) + "\n"
}
}
}
if !sawC {
error_(token.NoPos, `cannot find import "C"`)
}
// In ast2, strip the import "C" line.
w := 0
for _, decl := range ast2.Decls {
d, ok := decl.(*ast.GenDecl)
if !ok {
ast2.Decls[w] = decl
w++
continue
}
ws := 0
for _, spec := range d.Specs {
s, ok := spec.(*ast.ImportSpec)
if !ok || string(s.Path.Value) != `"C"` {
d.Specs[ws] = spec
ws++
}
}
if ws == 0 {
continue
}
d.Specs = d.Specs[0:ws]
ast2.Decls[w] = d
w++
}
ast2.Decls = ast2.Decls[0:w]
// Accumulate pointers to uses of C.x.
if f.Ref == nil {
f.Ref = make([]*Ref, 0, 8)
}
f.walk(ast2, "prog", (*File).saveRef)
// Accumulate exported functions.
// The comments are only on ast1 but we need to
// save the function bodies from ast2.
// The first walk fills in ExpFunc, and the
// second walk changes the entries to
// refer to ast2 instead.
f.walk(ast1, "prog", (*File).saveExport)
f.walk(ast2, "prog", (*File).saveExport2)
f.Comments = ast1.Comments
f.AST = ast2
}
// Like ast.CommentGroup's Text method but preserves
// leading blank lines, so that line numbers line up.
func commentText(g *ast.CommentGroup) string {
if g == nil {
return ""
}
var pieces []string
for _, com := range g.List {
c := string(com.Text)
// Remove comment markers.
// The parser has given us exactly the comment text.
switch c[1] {
case '/':
//-style comment (no newline at the end)
c = c[2:] + "\n"
case '*':
/*-style comment */
c = c[2 : len(c)-2]
}
pieces = append(pieces, c)
}
return strings.Join(pieces, "")
}
// Save references to C.xxx for later processing.
func (f *File) saveRef(x interface{}, context string) {
n, ok := x.(*ast.Expr)
if !ok {
return
}
if sel, ok := (*n).(*ast.SelectorExpr); ok {
// For now, assume that the only instance of capital C is
// when used as the imported package identifier.
// The parser should take care of scoping in the future,
// so that we will be able to distinguish a "top-level C"
// from a local C.
if l, ok := sel.X.(*ast.Ident); ok && l.Name == "C" {
if context == "as2" {
context = "expr"
}
if context == "embed-type" {
error_(sel.Pos(), "cannot embed C type")
}
goname := sel.Sel.Name
if goname == "errno" {
error_(sel.Pos(), "cannot refer to errno directly; see documentation")
return
}
if goname == "_CMalloc" {
error_(sel.Pos(), "cannot refer to C._CMalloc; use C.malloc")
return
}
if goname == "malloc" {
goname = "_CMalloc"
}
name := f.Name[goname]
if name == nil {
name = &Name{
Go: goname,
}
f.Name[goname] = name
}
f.Ref = append(f.Ref, &Ref{
Name: name,
Expr: n,
Context: context,
})
return
}
}
}
// If a function should be exported add it to ExpFunc.
func (f *File) saveExport(x interface{}, context string) {
n, ok := x.(*ast.FuncDecl)
if !ok {
return
}
if n.Doc == nil {
return
}
for _, c := range n.Doc.List {
if !strings.HasPrefix(string(c.Text), "//export ") {
continue
}
name := strings.TrimSpace(string(c.Text[9:]))
if name == "" {
error_(c.Pos(), "export missing name")
}
if name != n.Name.Name {
error_(c.Pos(), "export comment has wrong name %q, want %q", name, n.Name.Name)
}
f.ExpFunc = append(f.ExpFunc, &ExpFunc{
Func: n,
ExpName: name,
})
break
}
}
// Make f.ExpFunc[i] point at the Func from this AST instead of the other one.
func (f *File) saveExport2(x interface{}, context string) {
n, ok := x.(*ast.FuncDecl)
if !ok {
return
}
for _, exp := range f.ExpFunc {
if exp.Func.Name.Name == n.Name.Name {
exp.Func = n
break
}
}
}
// walk walks the AST x, calling visit(f, x, context) for each node.
func (f *File) walk(x interface{}, context string, visit func(*File, interface{}, string)) {
visit(f, x, context)
switch n := x.(type) {
case *ast.Expr:
f.walk(*n, context, visit)
// everything else just recurs
default:
error_(token.NoPos, "unexpected type %T in walk", x, visit)
panic("unexpected type")
case nil:
// These are ordered and grouped to match ../../pkg/go/ast/ast.go
case *ast.Field:
if len(n.Names) == 0 && context == "field" {
f.walk(&n.Type, "embed-type", visit)
} else {
f.walk(&n.Type, "type", visit)
}
case *ast.FieldList:
for _, field := range n.List {
f.walk(field, context, visit)
}
case *ast.BadExpr:
case *ast.Ident:
case *ast.Ellipsis:
case *ast.BasicLit:
case *ast.FuncLit:
f.walk(n.Type, "type", visit)
f.walk(n.Body, "stmt", visit)
case *ast.CompositeLit:
f.walk(&n.Type, "type", visit)
f.walk(n.Elts, "expr", visit)
case *ast.ParenExpr:
f.walk(&n.X, context, visit)
case *ast.SelectorExpr:
f.walk(&n.X, "selector", visit)
case *ast.IndexExpr:
f.walk(&n.X, "expr", visit)
f.walk(&n.Index, "expr", visit)
case *ast.SliceExpr:
f.walk(&n.X, "expr", visit)
if n.Low != nil {
f.walk(&n.Low, "expr", visit)
}
if n.High != nil {
f.walk(&n.High, "expr", visit)
}
case *ast.TypeAssertExpr:
f.walk(&n.X, "expr", visit)
f.walk(&n.Type, "type", visit)
case *ast.CallExpr:
if context == "as2" {
f.walk(&n.Fun, "call2", visit)
} else {
f.walk(&n.Fun, "call", visit)
}
f.walk(n.Args, "expr", visit)
case *ast.StarExpr:
f.walk(&n.X, context, visit)
case *ast.UnaryExpr:
f.walk(&n.X, "expr", visit)
case *ast.BinaryExpr:
f.walk(&n.X, "expr", visit)
f.walk(&n.Y, "expr", visit)
case *ast.KeyValueExpr:
f.walk(&n.Key, "expr", visit)
f.walk(&n.Value, "expr", visit)
case *ast.ArrayType:
f.walk(&n.Len, "expr", visit)
f.walk(&n.Elt, "type", visit)
case *ast.StructType:
f.walk(n.Fields, "field", visit)
case *ast.FuncType:
f.walk(n.Params, "param", visit)
if n.Results != nil {
f.walk(n.Results, "param", visit)
}
case *ast.InterfaceType:
f.walk(n.Methods, "field", visit)
case *ast.MapType:
f.walk(&n.Key, "type", visit)
f.walk(&n.Value, "type", visit)
case *ast.ChanType:
f.walk(&n.Value, "type", visit)
case *ast.BadStmt:
case *ast.DeclStmt:
f.walk(n.Decl, "decl", visit)
case *ast.EmptyStmt:
case *ast.LabeledStmt:
f.walk(n.Stmt, "stmt", visit)
case *ast.ExprStmt:
f.walk(&n.X, "expr", visit)
case *ast.SendStmt:
f.walk(&n.Chan, "expr", visit)
f.walk(&n.Value, "expr", visit)
case *ast.IncDecStmt:
f.walk(&n.X, "expr", visit)
case *ast.AssignStmt:
f.walk(n.Lhs, "expr", visit)
if len(n.Lhs) == 2 && len(n.Rhs) == 1 {
f.walk(n.Rhs, "as2", visit)
} else {
f.walk(n.Rhs, "expr", visit)
}
case *ast.GoStmt:
f.walk(n.Call, "expr", visit)
case *ast.DeferStmt:
f.walk(n.Call, "expr", visit)
case *ast.ReturnStmt:
f.walk(n.Results, "expr", visit)
case *ast.BranchStmt:
case *ast.BlockStmt:
f.walk(n.List, context, visit)
case *ast.IfStmt:
f.walk(n.Init, "stmt", visit)
f.walk(&n.Cond, "expr", visit)
f.walk(n.Body, "stmt", visit)
f.walk(n.Else, "stmt", visit)
case *ast.CaseClause:
if context == "typeswitch" {
context = "type"
} else {
context = "expr"
}
f.walk(n.List, context, visit)
f.walk(n.Body, "stmt", visit)
case *ast.SwitchStmt:
f.walk(n.Init, "stmt", visit)
f.walk(&n.Tag, "expr", visit)
f.walk(n.Body, "switch", visit)
case *ast.TypeSwitchStmt:
f.walk(n.Init, "stmt", visit)
f.walk(n.Assign, "stmt", visit)
f.walk(n.Body, "typeswitch", visit)
case *ast.CommClause:
f.walk(n.Comm, "stmt", visit)
f.walk(n.Body, "stmt", visit)
case *ast.SelectStmt:
f.walk(n.Body, "stmt", visit)
case *ast.ForStmt:
f.walk(n.Init, "stmt", visit)
f.walk(&n.Cond, "expr", visit)
f.walk(n.Post, "stmt", visit)
f.walk(n.Body, "stmt", visit)
case *ast.RangeStmt:
f.walk(&n.Key, "expr", visit)
f.walk(&n.Value, "expr", visit)
f.walk(&n.X, "expr", visit)
f.walk(n.Body, "stmt", visit)
case *ast.ImportSpec:
case *ast.ValueSpec:
f.walk(&n.Type, "type", visit)
f.walk(n.Values, "expr", visit)
case *ast.TypeSpec:
f.walk(&n.Type, "type", visit)
case *ast.BadDecl:
case *ast.GenDecl:
f.walk(n.Specs, "spec", visit)
case *ast.FuncDecl:
if n.Recv != nil {
f.walk(n.Recv, "param", visit)
}
f.walk(n.Type, "type", visit)
if n.Body != nil {
f.walk(n.Body, "stmt", visit)
}
case *ast.File:
f.walk(n.Decls, "decl", visit)
case *ast.Package:
for _, file := range n.Files {
f.walk(file, "file", visit)
}
case []ast.Decl:
for _, d := range n {
f.walk(d, context, visit)
}
case []ast.Expr:
for i := range n {
f.walk(&n[i], context, visit)
}
case []ast.Stmt:
for _, s := range n {
f.walk(s, context, visit)
}
case []ast.Spec:
for _, s := range n {
f.walk(s, context, visit)
}
}
}
// Copyright 2009 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.
/*
Cgo enables the creation of Go packages that call C code.
Using cgo with the go command
To use cgo write normal Go code that imports a pseudo-package "C".
The Go code can then refer to types such as C.size_t, variables such
as C.stdout, or functions such as C.putchar.
If the import of "C" is immediately preceded by a comment, that
comment, called the preamble, is used as a header when compiling
the C parts of the package. For example:
// #include <stdio.h>
// #include <errno.h>
import "C"
See $GOROOT/misc/cgo/stdio and $GOROOT/misc/cgo/gmp for examples. See
"C? Go? Cgo!" for an introduction to using cgo:
http://golang.org/doc/articles/c_go_cgo.html.
CFLAGS, CPPFLAGS, CXXFLAGS and LDFLAGS may be defined with pseudo #cgo
directives within these comments to tweak the behavior of the C or C++
compiler. Values defined in multiple directives are concatenated
together. The directive can include a list of build constraints limiting its
effect to systems satisfying one of the constraints
(see http://golang.org/pkg/go/build/#hdr-Build_Constraints for details about the constraint syntax).
For example:
// #cgo CFLAGS: -DPNG_DEBUG=1
// #cgo amd64 386 CFLAGS: -DX86=1
// #cgo LDFLAGS: -lpng
// #include <png.h>
import "C"
Alternatively, CPPFLAGS and LDFLAGS may be obtained via the pkg-config
tool using a '#cgo pkg-config:' directive followed by the package names.
For example:
// #cgo pkg-config: png cairo
// #include <png.h>
import "C"
When building, the CGO_CFLAGS, CGO_CPPFLAGS, CGO_CXXFLAGS and
CGO_LDFLAGS environment variables are added to the flags derived from
these directives. Package-specific flags should be set using the
directives, not the environment variables, so that builds work in
unmodified environments.
All the cgo CPPFLAGS and CFLAGS directives in a package are concatenated and
used to compile C files in that package. All the CPPFLAGS and CXXFLAGS
directives in a package are concatenated and used to compile C++ files in that
package. All the LDFLAGS directives in any package in the program are
concatenated and used at link time. All the pkg-config directives are
concatenated and sent to pkg-config simultaneously to add to each appropriate
set of command-line flags.
When the Go tool sees that one or more Go files use the special import
"C", it will look for other non-Go files in the directory and compile
them as part of the Go package. Any .c, .s, or .S files will be
compiled with the C compiler. Any .cc, .cpp, or .cxx files will be
compiled with the C++ compiler. Any .h, .hh, .hpp, or .hxx files will
not be compiled separately, but, if these header files are changed,
the C and C++ files will be recompiled. The default C and C++
compilers may be changed by the CC and CXX environment variables,
respectively; those environment variables may include command line
options.
To enable cgo during cross compiling builds, set the CGO_ENABLED
environment variable to 1 when building the Go tools with make.bash.
Also, set CC_FOR_TARGET to the C cross compiler for the target. CC will
be used for compiling for the host.
After the Go tools are built, when running the go command, CC_FOR_TARGET is
ignored. The value of CC_FOR_TARGET when running make.bash is the default
compiler. However, you can set the environment variable CC, not CC_FOR_TARGET,
to control the compiler when running the go tool.
CXX_FOR_TARGET works in a similar way for C++ code.
Go references to C
Within the Go file, C's struct field names that are keywords in Go
can be accessed by prefixing them with an underscore: if x points at a C
struct with a field named "type", x._type accesses the field.
C struct fields that cannot be expressed in Go, such as bit fields
or misaligned data, are omitted in the Go struct, replaced by
appropriate padding to reach the next field or the end of the struct.
The standard C numeric types are available under the names
C.char, C.schar (signed char), C.uchar (unsigned char),
C.short, C.ushort (unsigned short), C.int, C.uint (unsigned int),
C.long, C.ulong (unsigned long), C.longlong (long long),
C.ulonglong (unsigned long long), C.float, C.double.
The C type void* is represented by Go's unsafe.Pointer.
To access a struct, union, or enum type directly, prefix it with
struct_, union_, or enum_, as in C.struct_stat.
As Go doesn't have support for C's union type in the general case,
C's union types are represented as a Go byte array with the same length.
Go structs cannot embed fields with C types.
Cgo translates C types into equivalent unexported Go types.
Because the translations are unexported, a Go package should not
expose C types in its exported API: a C type used in one Go package
is different from the same C type used in another.
Any C function (even void functions) may be called in a multiple
assignment context to retrieve both the return value (if any) and the
C errno variable as an error (use _ to skip the result value if the
function returns void). For example:
n, err := C.sqrt(-1)
_, err := C.voidFunc()
Calling C function pointers is currently not supported, however you can
declare Go variables which hold C function pointers and pass them
back and forth between Go and C. C code may call function pointers
received from Go. For example:
package main
// typedef int (*intFunc) ();
//
// int
// bridge_int_func(intFunc f)
// {
// return f();
// }
//
// int fortytwo()
// {
// return 42;
// }
import "C"
import "fmt"
func main() {
f := C.intFunc(C.fortytwo)
fmt.Println(int(C.bridge_int_func(f)))
// Output: 42
}
In C, a function argument written as a fixed size array
actually requires a pointer to the first element of the array.
C compilers are aware of this calling convention and adjust
the call accordingly, but Go cannot. In Go, you must pass
the pointer to the first element explicitly: C.f(&x[0]).
A few special functions convert between Go and C types
by making copies of the data. In pseudo-Go definitions:
// Go string to C string
// The C string is allocated in the C heap using malloc.
// It is the caller's responsibility to arrange for it to be
// freed, such as by calling C.free (be sure to include stdlib.h
// if C.free is needed).
func C.CString(string) *C.char
// C string to Go string
func C.GoString(*C.char) string
// C string, length to Go string
func C.GoStringN(*C.char, C.int) string
// C pointer, length to Go []byte
func C.GoBytes(unsafe.Pointer, C.int) []byte
C references to Go
Go functions can be exported for use by C code in the following way:
//export MyFunction
func MyFunction(arg1, arg2 int, arg3 string) int64 {...}
//export MyFunction2
func MyFunction2(arg1, arg2 int, arg3 string) (int64, *C.char) {...}
They will be available in the C code as:
extern int64 MyFunction(int arg1, int arg2, GoString arg3);
extern struct MyFunction2_return MyFunction2(int arg1, int arg2, GoString arg3);
found in the _cgo_export.h generated header, after any preambles
copied from the cgo input files. Functions with multiple
return values are mapped to functions returning a struct.
Not all Go types can be mapped to C types in a useful way.
Using //export in a file places a restriction on the preamble:
since it is copied into two different C output files, it must not
contain any definitions, only declarations. Definitions must be
placed in preambles in other files, or in C source files.
Using cgo directly
Usage:
go tool cgo [cgo options] [-- compiler options] file.go
Cgo transforms the input file.go into four output files: two Go source
files, a C file for 6c (or 8c or 5c), and a C file for gcc.
The compiler options are passed through uninterpreted when
invoking the C compiler to compile the C parts of the package.
The following options are available when running cgo directly:
-dynimport file
Write list of symbols imported by file. Write to
-dynout argument or to standard output. Used by go
build when building a cgo package.
-dynout file
Write -dynimport output to file.
-dynlinker
Write dynamic linker as part of -dynimport output.
-godefs
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.
-cdefs
Like -godefs, but write file in C syntax.
Used to generate files in the runtime package when
bootstrapping a new target.
-objdir directory
Put all generated files in directory.
-gccgo
Generate output for the gccgo compiler rather than the
gc compiler.
-gccgoprefix prefix
The -fgo-prefix option to be used with gccgo.
-gccgopkgpath path
The -fgo-pkgpath option to be used with gccgo.
-import_runtime_cgo
If set (which it is by default) import runtime/cgo in
generated output.
-import_syscall
If set (which it is by default) import syscall in
generated output.
-debug-define
Debugging option. Print #defines.
-debug-gcc
Debugging option. Trace C compiler execution and output.
*/
package main
/*
Implementation details.
Cgo provides a way for Go programs to call C code linked into the same
address space. This comment explains the operation of cgo.
Cgo reads a set of Go source files and looks for statements saying
import "C". If the import has a doc comment, that comment is
taken as literal C code to be used as a preamble to any C code
generated by cgo. A typical preamble #includes necessary definitions:
// #include <stdio.h>
import "C"
For more details about the usage of cgo, see the documentation
comment at the top of this file.
Understanding C
Cgo scans the Go source files that import "C" for uses of that
package, such as C.puts. It collects all such identifiers. The next
step is to determine each kind of name. In C.xxx the xxx might refer
to a type, a function, a constant, or a global variable. Cgo must
decide which.
The obvious thing for cgo to do is to process the preamble, expanding
#includes and processing the corresponding C code. That would require
a full C parser and type checker that was also aware of any extensions
known to the system compiler (for example, all the GNU C extensions) as
well as the system-specific header locations and system-specific
pre-#defined macros. This is certainly possible to do, but it is an
enormous amount of work.
Cgo takes a different approach. It determines the meaning of C
identifiers not by parsing C code but by feeding carefully constructed
programs into the system C compiler and interpreting the generated
error messages, debug information, and object files. In practice,
parsing these is significantly less work and more robust than parsing
C source.
Cgo first invokes gcc -E -dM on the preamble, in order to find out
about simple #defines for constants and the like. These are recorded
for later use.
Next, cgo needs to identify the kinds for each identifier. For the
identifiers C.foo and C.bar, cgo generates this C program:
<preamble>
#line 1 "not-declared"
void __cgo_f_xxx_1(void) { __typeof__(foo) *__cgo_undefined__; }
#line 1 "not-type"
void __cgo_f_xxx_2(void) { foo *__cgo_undefined__; }
#line 1 "not-const"
void __cgo_f_xxx_3(void) { enum { __cgo_undefined__ = (foo)*1 }; }
#line 2 "not-declared"
void __cgo_f_xxx_1(void) { __typeof__(bar) *__cgo_undefined__; }
#line 2 "not-type"
void __cgo_f_xxx_2(void) { bar *__cgo_undefined__; }
#line 2 "not-const"
void __cgo_f_xxx_3(void) { enum { __cgo_undefined__ = (bar)*1 }; }
This program will not compile, but cgo can use the presence or absence
of an error message on a given line to deduce the information it
needs. The program is syntactically valid regardless of whether each
name is a type or an ordinary identifier, so there will be no syntax
errors that might stop parsing early.
An error on not-declared:1 indicates that foo is undeclared.
An error on not-type:1 indicates that foo is not a type (if declared at all, it is an identifier).
An error on not-const:1 indicates that foo is not an integer constant.
The line number specifies the name involved. In the example, 1 is foo and 2 is bar.
Next, cgo must learn the details of each type, variable, function, or
constant. It can do this by reading object files. If cgo has decided
that t1 is a type, v2 and v3 are variables or functions, and c4, c5,
and c6 are constants, it generates:
<preamble>
__typeof__(t1) *__cgo__1;
__typeof__(v2) *__cgo__2;
__typeof__(v3) *__cgo__3;
__typeof__(c4) *__cgo__4;
enum { __cgo_enum__4 = c4 };
__typeof__(c5) *__cgo__5;
enum { __cgo_enum__5 = c5 };
__typeof__(c6) *__cgo__6;
enum { __cgo_enum__6 = c6 };
long long __cgo_debug_data[] = {
0, // t1
0, // v2
0, // v3
c4,
c5,
c6,
1
};
and again invokes the system C compiler, to produce an object file
containing debug information. Cgo parses the DWARF debug information
for __cgo__N to learn the type of each identifier. (The types also
distinguish functions from global variables.) If using a standard gcc,
cgo can parse the DWARF debug information for the __cgo_enum__N to
learn the identifier's value. The LLVM-based gcc on OS X emits
incomplete DWARF information for enums; in that case cgo reads the
constant values from the __cgo_debug_data from the object file's data
segment.
At this point cgo knows the meaning of each C.xxx well enough to start
the translation process.
Translating Go
[The rest of this comment refers to 6g and 6c, the Go and C compilers
that are part of the amd64 port of the gc Go toolchain. Everything here
applies to another architecture's compilers as well.]
Given the input Go files x.go and y.go, cgo generates these source
files:
x.cgo1.go # for 6g
y.cgo1.go # for 6g
_cgo_gotypes.go # for 6g
_cgo_defun.c # for 6c
x.cgo2.c # for gcc
y.cgo2.c # for gcc
_cgo_export.c # for gcc
_cgo_main.c # for gcc
The file x.cgo1.go is a copy of x.go with the import "C" removed and
references to C.xxx replaced with names like _Cfunc_xxx or _Ctype_xxx.
The definitions of those identifiers, written as Go functions, types,
or variables, are provided in _cgo_gotypes.go.
Here is a _cgo_gotypes.go containing definitions for C.flush (provided
in the preamble) and C.puts (from stdio):
type _Ctype_char int8
type _Ctype_int int32
type _Ctype_void [0]byte
func _Cfunc_CString(string) *_Ctype_char
func _Cfunc_flush() _Ctype_void
func _Cfunc_puts(*_Ctype_char) _Ctype_int
For functions, cgo only writes an external declaration in the Go
output. The implementation is in a combination of C for 6c (meaning
any gc-toolchain compiler) and C for gcc.
The 6c file contains the definitions of the functions. They all have
similar bodies that invoke runtime·cgocall to make a switch from the
Go runtime world to the system C (GCC-based) world.
For example, here is the definition of _Cfunc_puts:
void _cgo_be59f0f25121_Cfunc_puts(void*);
void
·_Cfunc_puts(struct{uint8 x[1];}p)
{
runtime·cgocall(_cgo_be59f0f25121_Cfunc_puts, &p);
}
The hexadecimal number is a hash of cgo's input, chosen to be
deterministic yet unlikely to collide with other uses. The actual
function _cgo_be59f0f25121_Cfunc_puts is implemented in a C source
file compiled by gcc, the file x.cgo2.c:
void
_cgo_be59f0f25121_Cfunc_puts(void *v)
{
struct {
char* p0;
int r;
char __pad12[4];
} __attribute__((__packed__, __gcc_struct__)) *a = v;
a->r = puts((void*)a->p0);
}
It extracts the arguments from the pointer to _Cfunc_puts's argument
frame, invokes the system C function (in this case, puts), stores the
result in the frame, and returns.
Linking
Once the _cgo_export.c and *.cgo2.c files have been compiled with gcc,
they need to be linked into the final binary, along with the libraries
they might depend on (in the case of puts, stdio). 6l has been
extended to understand basic ELF files, but it does not understand ELF
in the full complexity that modern C libraries embrace, so it cannot
in general generate direct references to the system libraries.
Instead, the build process generates an object file using dynamic
linkage to the desired libraries. The main function is provided by
_cgo_main.c:
int main() { return 0; }
void crosscall2(void(*fn)(void*, int), void *a, int c) { }
void _cgo_allocate(void *a, int c) { }
void _cgo_panic(void *a, int c) { }
The extra functions here are stubs to satisfy the references in the C
code generated for gcc. The build process links this stub, along with
_cgo_export.c and *.cgo2.c, into a dynamic executable and then lets
cgo examine the executable. Cgo records the list of shared library
references and resolved names and writes them into a new file
_cgo_import.c, which looks like:
#pragma cgo_dynamic_linker "/lib64/ld-linux-x86-64.so.2"
#pragma cgo_import_dynamic puts puts#GLIBC_2.2.5 "libc.so.6"
#pragma cgo_import_dynamic __libc_start_main __libc_start_main#GLIBC_2.2.5 "libc.so.6"
#pragma cgo_import_dynamic stdout stdout#GLIBC_2.2.5 "libc.so.6"
#pragma cgo_import_dynamic fflush fflush#GLIBC_2.2.5 "libc.so.6"
#pragma cgo_import_dynamic _ _ "libpthread.so.0"
#pragma cgo_import_dynamic _ _ "libc.so.6"
In the end, the compiled Go package, which will eventually be
presented to 6l as part of a larger program, contains:
_go_.6 # 6g-compiled object for _cgo_gotypes.go *.cgo1.go
_cgo_defun.6 # 6c-compiled object for _cgo_defun.c
_all.o # gcc-compiled object for _cgo_export.c, *.cgo2.c
_cgo_import.6 # 6c-compiled object for _cgo_import.c
The final program will be a dynamic executable, so that 6l can avoid
needing to process arbitrary .o files. It only needs to process the .o
files generated from C files that cgo writes, and those are much more
limited in the ELF or other features that they use.
In essence, the _cgo_import.6 file includes the extra linking
directives that 6l is not sophisticated enough to derive from _all.o
on its own. Similarly, the _all.o uses dynamic references to real
system object code because 6l is not sophisticated enough to process
the real code.
The main benefits of this system are that 6l remains relatively simple
(it does not need to implement a complete ELF and Mach-O linker) and
that gcc is not needed after the package is compiled. For example,
package net uses cgo for access to name resolution functions provided
by libc. Although gcc is needed to compile package net, gcc is not
needed to link programs that import package net.
Runtime
When using cgo, Go must not assume that it owns all details of the
process. In particular it needs to coordinate with C in the use of
threads and thread-local storage. The runtime package, in its own
(6c-compiled) C code, declares a few uninitialized (default bss)
variables:
bool runtime·iscgo;
void (*libcgo_thread_start)(void*);
void (*initcgo)(G*);
Any package using cgo imports "runtime/cgo", which provides
initializations for these variables. It sets iscgo to 1, initcgo to a
gcc-compiled function that can be called early during program startup,
and libcgo_thread_start to a gcc-compiled function that can be used to
create a new thread, in place of the runtime's usual direct system
calls.
Internal and External Linking
The text above describes "internal" linking, in which 6l parses and
links host object files (ELF, Mach-O, PE, and so on) into the final
executable itself. Keeping 6l simple means we cannot possibly
implement the full semantics of the host linker, so the kinds of
objects that can be linked directly into the binary is limited (other
code can only be used as a dynamic library). On the other hand, when
using internal linking, 6l can generate Go binaries by itself.
In order to allow linking arbitrary object files without requiring
dynamic libraries, cgo will soon support an "external" linking mode
too. In external linking mode, 6l does not process any host object
files. Instead, it collects all the Go code and writes a single go.o
object file containing it. Then it invokes the host linker (usually
gcc) to combine the go.o object file and any supporting non-Go code
into a final executable. External linking avoids the dynamic library
requirement but introduces a requirement that the host linker be
present to create such a binary.
Most builds both compile source code and invoke the linker to create a
binary. When cgo is involved, the compile step already requires gcc, so
it is not problematic for the link step to require gcc too.
An important exception is builds using a pre-compiled copy of the
standard library. In particular, package net uses cgo on most systems,
and we want to preserve the ability to compile pure Go code that
imports net without requiring gcc to be present at link time. (In this
case, the dynamic library requirement is less significant, because the
only library involved is libc.so, which can usually be assumed
present.)
This conflict between functionality and the gcc requirement means we
must support both internal and external linking, depending on the
circumstances: if net is the only cgo-using package, then internal
linking is probably fine, but if other packages are involved, so that there
are dependencies on libraries beyond libc, external linking is likely
to work better. The compilation of a package records the relevant
information to support both linking modes, leaving the decision
to be made when linking the final binary.
Linking Directives
In either linking mode, package-specific directives must be passed
through to 6l. These are communicated by writing #pragma directives
in a C source file compiled by 6c. The directives are copied into the .6 object file
and then processed by the linker.
The directives are:
#pragma cgo_import_dynamic <local> [<remote> ["<library>"]]
In internal linking mode, allow an unresolved reference to
<local>, assuming it will be resolved by a dynamic library
symbol. The optional <remote> specifies the symbol's name and
possibly version in the dynamic library, and the optional "<library>"
names the specific library where the symbol should be found.
In the <remote>, # or @ can be used to introduce a symbol version.
Examples:
#pragma cgo_import_dynamic puts
#pragma cgo_import_dynamic puts puts#GLIBC_2.2.5
#pragma cgo_import_dynamic puts puts#GLIBC_2.2.5 "libc.so.6"
A side effect of the cgo_import_dynamic directive with a
library is to make the final binary depend on that dynamic
library. To get the dependency without importing any specific
symbols, use _ for local and remote.
Example:
#pragma cgo_import_dynamic _ _ "libc.so.6"
For compatibility with current versions of SWIG,
#pragma dynimport is an alias for #pragma cgo_import_dynamic.
#pragma cgo_dynamic_linker "<path>"
In internal linking mode, use "<path>" as the dynamic linker
in the final binary. This directive is only needed from one
package when constructing a binary; by convention it is
supplied by runtime/cgo.
Example:
#pragma cgo_dynamic_linker "/lib/ld-linux.so.2"
#pragma cgo_export_dynamic <local> <remote>
In internal linking mode, put the Go symbol
named <local> into the program's exported symbol table as
<remote>, so that C code can refer to it by that name. This
mechanism makes it possible for C code to call back into Go or
to share Go's data.
For compatibility with current versions of SWIG,
#pragma dynexport is an alias for #pragma cgo_export_dynamic.
#pragma cgo_import_static <local>
In external linking mode, allow unresolved references to
<local> in the go.o object file prepared for the host linker,
under the assumption that <local> will be supplied by the
other object files that will be linked with go.o.
Example:
#pragma cgo_import_static puts_wrapper
#pragma cgo_export_static <local> <remote>
In external linking mode, put the Go symbol
named <local> into the program's exported symbol table as
<remote>, so that C code can refer to it by that name. This
mechanism makes it possible for C code to call back into Go or
to share Go's data.
#pragma cgo_ldflag "<arg>"
In external linking mode, invoke the host linker (usually gcc)
with "<arg>" as a command-line argument following the .o files.
Note that the arguments are for "gcc", not "ld".
Example:
#pragma cgo_ldflag "-lpthread"
#pragma cgo_ldflag "-L/usr/local/sqlite3/lib"
A package compiled with cgo will include directives for both
internal and external linking; the linker will select the appropriate
subset for the chosen linking mode.
Example
As a simple example, consider a package that uses cgo to call C.sin.
The following code will be generated by cgo:
// compiled by 6g
type _Ctype_double float64
func _Cfunc_sin(_Ctype_double) _Ctype_double
// compiled by 6c
#pragma cgo_import_dynamic sin sin#GLIBC_2.2.5 "libm.so.6"
#pragma cgo_import_static _cgo_gcc_Cfunc_sin
#pragma cgo_ldflag "-lm"
void _cgo_gcc_Cfunc_sin(void*);
void
·_Cfunc_sin(struct{uint8 x[16];}p)
{
runtime·cgocall(_cgo_gcc_Cfunc_sin, &p);
}
// compiled by gcc, into foo.cgo2.o
void
_cgo_gcc_Cfunc_sin(void *v)
{
struct {
double p0;
double r;
} __attribute__((__packed__)) *a = v;
a->r = sin(a->p0);
}
What happens at link time depends on whether the final binary is linked
using the internal or external mode. If other packages are compiled in
"external only" mode, then the final link will be an external one.
Otherwise the link will be an internal one.
The directives in the 6c-compiled file are used according to the kind
of final link used.
In internal mode, 6l itself processes all the host object files, in
particular foo.cgo2.o. To do so, it uses the cgo_import_dynamic and
cgo_dynamic_linker directives to learn that the otherwise undefined
reference to sin in foo.cgo2.o should be rewritten to refer to the
symbol sin with version GLIBC_2.2.5 from the dynamic library
"libm.so.6", and the binary should request "/lib/ld-linux.so.2" as its
runtime dynamic linker.
In external mode, 6l does not process any host object files, in
particular foo.cgo2.o. It links together the 6g- and 6c-generated
object files, along with any other Go code, into a go.o file. While
doing that, 6l will discover that there is no definition for
_cgo_gcc_Cfunc_sin, referred to by the 6c-compiled source file. This
is okay, because 6l also processes the cgo_import_static directive and
knows that _cgo_gcc_Cfunc_sin is expected to be supplied by a host
object file, so 6l does not treat the missing symbol as an error when
creating go.o. Indeed, the definition for _cgo_gcc_Cfunc_sin will be
provided to the host linker by foo2.cgo.o, which in turn will need the
symbol 'sin'. 6l also processes the cgo_ldflag directives, so that it
knows that the eventual host link command must include the -lm
argument, so that the host linker will be able to find 'sin' in the
math library.
6l Command Line Interface
The go command and any other Go-aware build systems invoke 6l
to link a collection of packages into a single binary. By default, 6l will
present the same interface it does today:
6l main.a
produces a file named 6.out, even if 6l does so by invoking the host
linker in external linking mode.
By default, 6l will decide the linking mode as follows: if the only
packages using cgo are those on a whitelist of standard library
packages (net, os/user, runtime/cgo), 6l will use internal linking
mode. Otherwise, there are non-standard cgo packages involved, and 6l
will use external linking mode. The first rule means that a build of
the godoc binary, which uses net but no other cgo, can run without
needing gcc available. The second rule means that a build of a
cgo-wrapped library like sqlite3 can generate a standalone executable
instead of needing to refer to a dynamic library. The specific choice
can be overridden using a command line flag: 6l -linkmode=internal or
6l -linkmode=external.
In an external link, 6l will create a temporary directory, write any
host object files found in package archives to that directory (renamed
to avoid conflicts), write the go.o file to that directory, and invoke
the host linker. The default value for the host linker is $CC, split
into fields, or else "gcc". The specific host linker command line can
be overridden using command line flags: 6l -extld=clang
-extldflags='-ggdb -O3'. If any package in a build includes a .cc or
other file compiled by the C++ compiler, the go tool will use the
-extld option to set the host linker to the C++ compiler.
These defaults mean that Go-aware build systems can ignore the linking
changes and keep running plain '6l' and get reasonable results, but
they can also control the linking details if desired.
*/
// Copyright 2009 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.
// Annotate Ref in Prog with C types by parsing gcc debug output.
// Conversion of debug output to Go types.
package main
import (
"bytes"
"debug/dwarf"
"debug/elf"
"debug/macho"
"debug/pe"
"encoding/binary"
"errors"
"flag"
"fmt"
"go/ast"
"go/parser"
"go/token"
"os"
"strconv"
"strings"
"unicode"
"unicode/utf8"
)
var debugDefine = flag.Bool("debug-define", false, "print relevant #defines")
var debugGcc = flag.Bool("debug-gcc", false, "print gcc invocations")
var nameToC = map[string]string{
"schar": "signed char",
"uchar": "unsigned char",
"ushort": "unsigned short",
"uint": "unsigned int",
"ulong": "unsigned long",
"longlong": "long long",
"ulonglong": "unsigned long long",
"complexfloat": "float complex",
"complexdouble": "double complex",
}
// cname returns the C name to use for C.s.
// The expansions are listed in nameToC and also
// struct_foo becomes "struct foo", and similarly for
// union and enum.
func cname(s string) string {
if t, ok := nameToC[s]; ok {
return t
}
if strings.HasPrefix(s, "struct_") {
return "struct " + s[len("struct_"):]
}
if strings.HasPrefix(s, "union_") {
return "union " + s[len("union_"):]
}
if strings.HasPrefix(s, "enum_") {
return "enum " + s[len("enum_"):]
}
if strings.HasPrefix(s, "sizeof_") {
return "sizeof(" + cname(s[len("sizeof_"):]) + ")"
}
return s
}
// DiscardCgoDirectives processes the import C preamble, and discards
// all #cgo CFLAGS and LDFLAGS directives, so they don't make their
// way into _cgo_export.h.
func (f *File) DiscardCgoDirectives() {
linesIn := strings.Split(f.Preamble, "\n")
linesOut := make([]string, 0, len(linesIn))
for _, line := range linesIn {
l := strings.TrimSpace(line)
if len(l) < 5 || l[:4] != "#cgo" || !unicode.IsSpace(rune(l[4])) {
linesOut = append(linesOut, line)
} else {
linesOut = append(linesOut, "")
}
}
f.Preamble = strings.Join(linesOut, "\n")
}
// addToFlag appends args to flag. All flags are later written out onto the
// _cgo_flags file for the build system to use.
func (p *Package) addToFlag(flag string, args []string) {
p.CgoFlags[flag] = append(p.CgoFlags[flag], args...)
if flag == "CFLAGS" {
// We'll also need these when preprocessing for dwarf information.
p.GccOptions = append(p.GccOptions, args...)
}
}
// splitQuoted splits the string s around each instance of one or more consecutive
// white space characters while taking into account quotes and escaping, and
// returns an array of substrings of s or an empty list if s contains only white space.
// Single quotes and double quotes are recognized to prevent splitting within the
// quoted region, and are removed from the resulting substrings. If a quote in s
// isn't closed err will be set and r will have the unclosed argument as the
// last element. The backslash is used for escaping.
//
// For example, the following string:
//
// `a b:"c d" 'e''f' "g\""`
//
// Would be parsed as:
//
// []string{"a", "b:c d", "ef", `g"`}
//
func splitQuoted(s string) (r []string, err error) {
var args []string
arg := make([]rune, len(s))
escaped := false
quoted := false
quote := '\x00'
i := 0
for _, r := range s {
switch {
case escaped:
escaped = false
case r == '\\':
escaped = true
continue
case quote != 0:
if r == quote {
quote = 0
continue
}
case r == '"' || r == '\'':
quoted = true
quote = r
continue
case unicode.IsSpace(r):
if quoted || i > 0 {
quoted = false
args = append(args, string(arg[:i]))
i = 0
}
continue
}
arg[i] = r
i++
}
if quoted || i > 0 {
args = append(args, string(arg[:i]))
}
if quote != 0 {
err = errors.New("unclosed quote")
} else if escaped {
err = errors.New("unfinished escaping")
}
return args, err
}
var safeBytes = []byte(`+-.,/0123456789:=ABCDEFGHIJKLMNOPQRSTUVWXYZ\_abcdefghijklmnopqrstuvwxyz`)
func safeName(s string) bool {
if s == "" {
return false
}
for i := 0; i < len(s); i++ {
if c := s[i]; c < 0x80 && bytes.IndexByte(safeBytes, c) < 0 {
return false
}
}
return true
}
// Translate rewrites f.AST, the original Go input, to remove
// references to the imported package C, replacing them with
// references to the equivalent Go types, functions, and variables.
func (p *Package) Translate(f *File) {
for _, cref := range f.Ref {
// Convert C.ulong to C.unsigned long, etc.
cref.Name.C = cname(cref.Name.Go)
}
p.loadDefines(f)
needType := p.guessKinds(f)
if len(needType) > 0 {
p.loadDWARF(f, needType)
}
p.rewriteRef(f)
}
// loadDefines coerces gcc into spitting out the #defines in use
// in the file f and saves relevant renamings in f.Name[name].Define.
func (p *Package) loadDefines(f *File) {
var b bytes.Buffer
b.WriteString(f.Preamble)
b.WriteString(builtinProlog)
stdout := p.gccDefines(b.Bytes())
for _, line := range strings.Split(stdout, "\n") {
if len(line) < 9 || line[0:7] != "#define" {
continue
}
line = strings.TrimSpace(line[8:])
var key, val string
spaceIndex := strings.Index(line, " ")
tabIndex := strings.Index(line, "\t")
if spaceIndex == -1 && tabIndex == -1 {
continue
} else if tabIndex == -1 || (spaceIndex != -1 && spaceIndex < tabIndex) {
key = line[0:spaceIndex]
val = strings.TrimSpace(line[spaceIndex:])
} else {
key = line[0:tabIndex]
val = strings.TrimSpace(line[tabIndex:])
}
if n := f.Name[key]; n != nil {
if *debugDefine {
fmt.Fprintf(os.Stderr, "#define %s %s\n", key, val)
}
n.Define = val
}
}
}
// guessKinds tricks gcc into revealing the kind of each
// name xxx for the references C.xxx in the Go input.
// The kind is either a constant, type, or variable.
func (p *Package) guessKinds(f *File) []*Name {
// Determine kinds for names we already know about,
// like #defines or 'struct foo', before bothering with gcc.
var names, needType []*Name
for _, n := range f.Name {
// If we've already found this name as a #define
// and we can translate it as a constant value, do so.
if n.Define != "" {
isConst := false
if _, err := strconv.Atoi(n.Define); err == nil {
isConst = true
} else if n.Define[0] == '"' || n.Define[0] == '\'' {
if _, err := parser.ParseExpr(n.Define); err == nil {
isConst = true
}
}
if isConst {
n.Kind = "const"
// Turn decimal into hex, just for consistency
// with enum-derived constants. Otherwise
// in the cgo -godefs output half the constants
// are in hex and half are in whatever the #define used.
i, err := strconv.ParseInt(n.Define, 0, 64)
if err == nil {
n.Const = fmt.Sprintf("%#x", i)
} else {
n.Const = n.Define
}
continue
}
if isName(n.Define) {
n.C = n.Define
}
}
needType = append(needType, n)
// If this is a struct, union, or enum type name, no need to guess the kind.
if strings.HasPrefix(n.C, "struct ") || strings.HasPrefix(n.C, "union ") || strings.HasPrefix(n.C, "enum ") {
n.Kind = "type"
continue
}
// Otherwise, we'll need to find out from gcc.
names = append(names, n)
}
// Bypass gcc if there's nothing left to find out.
if len(names) == 0 {
return needType
}
// Coerce gcc into telling us whether each name is a type, a value, or undeclared.
// For names, find out whether they are integer constants.
// We used to look at specific warning or error messages here, but that tied the
// behavior too closely to specific versions of the compilers.
// Instead, arrange that we can infer what we need from only the presence or absence
// of an error on a specific line.
//
// For each name, we generate these lines, where xxx is the index in toSniff plus one.
//
// #line xxx "not-declared"
// void __cgo_f_xxx_1(void) { __typeof__(name) *__cgo_undefined__; }
// #line xxx "not-type"
// void __cgo_f_xxx_2(void) { name *__cgo_undefined__; }
// #line xxx "not-const"
// void __cgo_f_xxx_3(void) { enum { __cgo_undefined__ = (name)*1 }; }
//
// If we see an error at not-declared:xxx, the corresponding name is not declared.
// If we see an error at not-type:xxx, the corresponding name is a type.
// If we see an error at not-const:xxx, the corresponding name is not an integer constant.
// If we see no errors, we assume the name is an expression but not a constant
// (so a variable or a function).
//
// The specific input forms are chosen so that they are valid C syntax regardless of
// whether name denotes a type or an expression.
var b bytes.Buffer
b.WriteString(f.Preamble)
b.WriteString(builtinProlog)
for i, n := range names {
fmt.Fprintf(&b, "#line %d \"not-declared\"\n"+
"void __cgo_f_%d_1(void) { __typeof__(%s) *__cgo_undefined__; }\n"+
"#line %d \"not-type\"\n"+
"void __cgo_f_%d_2(void) { %s *__cgo_undefined__; }\n"+
"#line %d \"not-const\"\n"+
"void __cgo_f_%d_3(void) { enum { __cgo__undefined__ = (%s)*1 }; }\n",
i+1, i+1, n.C,
i+1, i+1, n.C,
i+1, i+1, n.C)
}
fmt.Fprintf(&b, "#line 1 \"completed\"\n"+
"int __cgo__1 = __cgo__2;\n")
stderr := p.gccErrors(b.Bytes())
if stderr == "" {
fatalf("%s produced no output\non input:\n%s", p.gccBaseCmd()[0], b.Bytes())
}
completed := false
sniff := make([]int, len(names))
const (
notType = 1 << iota
notConst
)
for _, line := range strings.Split(stderr, "\n") {
if !strings.Contains(line, ": error:") {
// we only care about errors.
// we tried to turn off warnings on the command line, but one never knows.
continue
}
c1 := strings.Index(line, ":")
if c1 < 0 {
continue
}
c2 := strings.Index(line[c1+1:], ":")
if c2 < 0 {
continue
}
c2 += c1 + 1
filename := line[:c1]
i, _ := strconv.Atoi(line[c1+1 : c2])
i--
if i < 0 || i >= len(names) {
continue
}
switch filename {
case "completed":
// Strictly speaking, there is no guarantee that seeing the error at completed:1
// (at the end of the file) means we've seen all the errors from earlier in the file,
// but usually it does. Certainly if we don't see the completed:1 error, we did
// not get all the errors we expected.
completed = true
case "not-declared":
error_(token.NoPos, "%s", strings.TrimSpace(line[c2+1:]))
case "not-type":
sniff[i] |= notType
case "not-const":
sniff[i] |= notConst
}
}
if !completed {
fatalf("%s did not produce error at completed:1\non input:\n%s", p.gccBaseCmd()[0], b.Bytes())
}
for i, n := range names {
switch sniff[i] {
case 0:
error_(token.NoPos, "could not determine kind of name for C.%s", fixGo(n.Go))
case notType:
n.Kind = "const"
case notConst:
n.Kind = "type"
case notConst | notType:
n.Kind = "not-type"
}
}
if nerrors > 0 {
fatalf("unresolved names")
}
needType = append(needType, names...)
return needType
}
// loadDWARF parses the DWARF debug information generated
// by gcc to learn the details of the constants, variables, and types
// being referred to as C.xxx.
func (p *Package) loadDWARF(f *File, names []*Name) {
// Extract the types from the DWARF section of an object
// from a well-formed C program. Gcc only generates DWARF info
// for symbols in the object file, so it is not enough to print the
// preamble and hope the symbols we care about will be there.
// Instead, emit
// __typeof__(names[i]) *__cgo__i;
// for each entry in names and then dereference the type we
// learn for __cgo__i.
var b bytes.Buffer
b.WriteString(f.Preamble)
b.WriteString(builtinProlog)
for i, n := range names {
fmt.Fprintf(&b, "__typeof__(%s) *__cgo__%d;\n", n.C, i)
if n.Kind == "const" {
fmt.Fprintf(&b, "enum { __cgo_enum__%d = %s };\n", i, n.C)
}
}
// Apple's LLVM-based gcc does not include the enumeration
// names and values in its DWARF debug output. In case we're
// using such a gcc, create a data block initialized with the values.
// We can read them out of the object file.
fmt.Fprintf(&b, "long long __cgodebug_data[] = {\n")
for _, n := range names {
if n.Kind == "const" {
fmt.Fprintf(&b, "\t%s,\n", n.C)
} else {
fmt.Fprintf(&b, "\t0,\n")
}
}
// for the last entry, we can not use 0, otherwise
// in case all __cgodebug_data is zero initialized,
// LLVM-based gcc will place the it in the __DATA.__common
// zero-filled section (our debug/macho doesn't support
// this)
fmt.Fprintf(&b, "\t1\n")
fmt.Fprintf(&b, "};\n")
d, bo, debugData := p.gccDebug(b.Bytes())
enumVal := make([]int64, len(debugData)/8)
for i := range enumVal {
enumVal[i] = int64(bo.Uint64(debugData[i*8:]))
}
// Scan DWARF info for top-level TagVariable entries with AttrName __cgo__i.
types := make([]dwarf.Type, len(names))
enums := make([]dwarf.Offset, len(names))
nameToIndex := make(map[*Name]int)
for i, n := range names {
nameToIndex[n] = i
}
nameToRef := make(map[*Name]*Ref)
for _, ref := range f.Ref {
nameToRef[ref.Name] = ref
}
r := d.Reader()
for {
e, err := r.Next()
if err != nil {
fatalf("reading DWARF entry: %s", err)
}
if e == nil {
break
}
switch e.Tag {
case dwarf.TagEnumerationType:
offset := e.Offset
for {
e, err := r.Next()
if err != nil {
fatalf("reading DWARF entry: %s", err)
}
if e.Tag == 0 {
break
}
if e.Tag == dwarf.TagEnumerator {
entryName := e.Val(dwarf.AttrName).(string)
if strings.HasPrefix(entryName, "__cgo_enum__") {
n, _ := strconv.Atoi(entryName[len("__cgo_enum__"):])
if 0 <= n && n < len(names) {
enums[n] = offset
}
}
}
}
case dwarf.TagVariable:
name, _ := e.Val(dwarf.AttrName).(string)
typOff, _ := e.Val(dwarf.AttrType).(dwarf.Offset)
if name == "" || typOff == 0 {
fatalf("malformed DWARF TagVariable entry")
}
if !strings.HasPrefix(name, "__cgo__") {
break
}
typ, err := d.Type(typOff)
if err != nil {
fatalf("loading DWARF type: %s", err)
}
t, ok := typ.(*dwarf.PtrType)
if !ok || t == nil {
fatalf("internal error: %s has non-pointer type", name)
}
i, err := strconv.Atoi(name[7:])
if err != nil {
fatalf("malformed __cgo__ name: %s", name)
}
if enums[i] != 0 {
t, err := d.Type(enums[i])
if err != nil {
fatalf("loading DWARF type: %s", err)
}
types[i] = t
} else {
types[i] = t.Type
}
}
if e.Tag != dwarf.TagCompileUnit {
r.SkipChildren()
}
}
// Record types and typedef information.
var conv typeConv
conv.Init(p.PtrSize, p.IntSize)
for i, n := range names {
if types[i] == nil {
continue
}
pos := token.NoPos
if ref, ok := nameToRef[n]; ok {
pos = ref.Pos()
}
f, fok := types[i].(*dwarf.FuncType)
if n.Kind != "type" && fok {
n.Kind = "func"
n.FuncType = conv.FuncType(f, pos)
} else {
n.Type = conv.Type(types[i], pos)
if enums[i] != 0 && n.Type.EnumValues != nil {
k := fmt.Sprintf("__cgo_enum__%d", i)
n.Kind = "const"
n.Const = fmt.Sprintf("%#x", n.Type.EnumValues[k])
// Remove injected enum to ensure the value will deep-compare
// equally in future loads of the same constant.
delete(n.Type.EnumValues, k)
}
// Prefer debug data over DWARF debug output, if we have it.
if n.Kind == "const" && i < len(enumVal) {
n.Const = fmt.Sprintf("%#x", enumVal[i])
}
}
conv.FinishType(pos)
}
}
// mangleName does name mangling to translate names
// from the original Go source files to the names
// used in the final Go files generated by cgo.
func (p *Package) mangleName(n *Name) {
// When using gccgo variables have to be
// exported so that they become global symbols
// that the C code can refer to.
prefix := "_C"
if *gccgo && n.IsVar() {
prefix = "C"
}
n.Mangle = prefix + n.Kind + "_" + n.Go
}
// rewriteRef rewrites all the C.xxx references in f.AST to refer to the
// Go equivalents, now that we have figured out the meaning of all
// the xxx. In *godefs or *cdefs mode, rewriteRef replaces the names
// with full definitions instead of mangled names.
func (p *Package) rewriteRef(f *File) {
// Keep a list of all the functions, to remove the ones
// only used as expressions and avoid generating bridge
// code for them.
functions := make(map[string]bool)
// Assign mangled names.
for _, n := range f.Name {
if n.Kind == "not-type" {
n.Kind = "var"
}
if n.Mangle == "" {
p.mangleName(n)
}
if n.Kind == "func" {
functions[n.Go] = false
}
}
// Now that we have all the name types filled in,
// scan through the Refs to identify the ones that
// are trying to do a ,err call. Also check that
// functions are only used in calls.
for _, r := range f.Ref {
if r.Name.Kind == "const" && r.Name.Const == "" {
error_(r.Pos(), "unable to find value of constant C.%s", fixGo(r.Name.Go))
}
var expr ast.Expr = ast.NewIdent(r.Name.Mangle) // default
switch r.Context {
case "call", "call2":
if r.Name.Kind != "func" {
if r.Name.Kind == "type" {
r.Context = "type"
expr = r.Name.Type.Go
break
}
error_(r.Pos(), "call of non-function C.%s", fixGo(r.Name.Go))
break
}
functions[r.Name.Go] = true
if r.Context == "call2" {
if r.Name.Go == "_CMalloc" {
error_(r.Pos(), "no two-result form for C.malloc")
break
}
// Invent new Name for the two-result function.
n := f.Name["2"+r.Name.Go]
if n == nil {
n = new(Name)
*n = *r.Name
n.AddError = true
n.Mangle = "_C2func_" + n.Go
f.Name["2"+r.Name.Go] = n
}
expr = ast.NewIdent(n.Mangle)
r.Name = n
break
}
case "expr":
if r.Name.Kind == "func" {
// Function is being used in an expression, to e.g. pass around a C function pointer.
// Create a new Name for this Ref which causes the variable to be declared in Go land.
fpName := "fp_" + r.Name.Go
name := f.Name[fpName]
if name == nil {
name = &Name{
Go: fpName,
C: r.Name.C,
Kind: "fpvar",
Type: &Type{Size: p.PtrSize, Align: p.PtrSize, C: c("void*"), Go: ast.NewIdent("unsafe.Pointer")},
}
p.mangleName(name)
f.Name[fpName] = name
}
r.Name = name
expr = ast.NewIdent(name.Mangle)
} else if r.Name.Kind == "type" {
// Okay - might be new(T)
expr = r.Name.Type.Go
} else if r.Name.Kind == "var" {
expr = &ast.StarExpr{Star: (*r.Expr).Pos(), X: expr}
}
case "type":
if r.Name.Kind != "type" {
error_(r.Pos(), "expression C.%s used as type", fixGo(r.Name.Go))
} else if r.Name.Type == nil {
// Use of C.enum_x, C.struct_x or C.union_x without C definition.
// GCC won't raise an error when using pointers to such unknown types.
error_(r.Pos(), "type C.%s: undefined C type '%s'", fixGo(r.Name.Go), r.Name.C)
} else {
expr = r.Name.Type.Go
}
default:
if r.Name.Kind == "func" {
error_(r.Pos(), "must call C.%s", fixGo(r.Name.Go))
}
}
if *godefs || *cdefs {
// Substitute definition for mangled type name.
if id, ok := expr.(*ast.Ident); ok {
if t := typedef[id.Name]; t != nil {
expr = t.Go
}
if id.Name == r.Name.Mangle && r.Name.Const != "" {
expr = ast.NewIdent(r.Name.Const)
}
}
}
// Copy position information from old expr into new expr,
// in case expression being replaced is first on line.
// See golang.org/issue/6563.
pos := (*r.Expr).Pos()
switch x := expr.(type) {
case *ast.Ident:
expr = &ast.Ident{NamePos: pos, Name: x.Name}
}
*r.Expr = expr
}
// Remove functions only used as expressions, so their respective
// bridge functions are not generated.
for name, used := range functions {
if !used {
delete(f.Name, name)
}
}
}
// gccBaseCmd returns the start of the compiler command line.
// It uses $CC if set, or else $GCC, or else the compiler recorded
// during the initial build as defaultCC.
// defaultCC is defined in zdefaultcc.go, written by cmd/dist.
func (p *Package) gccBaseCmd() []string {
// Use $CC if set, since that's what the build uses.
if ret := strings.Fields(os.Getenv("CC")); len(ret) > 0 {
return ret
}
// Try $GCC if set, since that's what we used to use.
if ret := strings.Fields(os.Getenv("GCC")); len(ret) > 0 {
return ret
}
return strings.Fields(defaultCC)
}
// gccMachine returns the gcc -m flag to use, either "-m32", "-m64" or "-marm".
func (p *Package) gccMachine() []string {
switch goarch {
case "amd64":
return []string{"-m64"}
case "386":
return []string{"-m32"}
case "arm":
return []string{"-marm"} // not thumb
}
return nil
}
func gccTmp() string {
return *objDir + "_cgo_.o"
}
// gccCmd returns the gcc command line to use for compiling
// the input.
func (p *Package) gccCmd() []string {
c := append(p.gccBaseCmd(),
"-w", // no warnings
"-Wno-error", // warnings are not errors
"-o"+gccTmp(), // write object to tmp
"-gdwarf-2", // generate DWARF v2 debugging symbols
"-c", // do not link
"-xc", // input language is C
)
if strings.Contains(c[0], "clang") {
c = append(c,
"-ferror-limit=0",
// Apple clang version 1.7 (tags/Apple/clang-77) (based on LLVM 2.9svn)
// doesn't have -Wno-unneeded-internal-declaration, so we need yet another
// flag to disable the warning. Yes, really good diagnostics, clang.
"-Wno-unknown-warning-option",
"-Wno-unneeded-internal-declaration",
"-Wno-unused-function",
"-Qunused-arguments",
// Clang embeds prototypes for some builtin functions,
// like malloc and calloc, but all size_t parameters are
// incorrectly typed unsigned long. We work around that
// by disabling the builtin functions (this is safe as
// it won't affect the actual compilation of the C code).
// See: http://golang.org/issue/6506.
"-fno-builtin",
)
}
c = append(c, p.GccOptions...)
c = append(c, p.gccMachine()...)
c = append(c, "-") //read input from standard input
return c
}
// gccDebug runs gcc -gdwarf-2 over the C program stdin and
// returns the corresponding DWARF data and, if present, debug data block.
func (p *Package) gccDebug(stdin []byte) (*dwarf.Data, binary.ByteOrder, []byte) {
runGcc(stdin, p.gccCmd())
isDebugData := func(s string) bool {
// Some systems use leading _ to denote non-assembly symbols.
return s == "__cgodebug_data" || s == "___cgodebug_data"
}
if f, err := macho.Open(gccTmp()); err == nil {
defer f.Close()
d, err := f.DWARF()
if err != nil {
fatalf("cannot load DWARF output from %s: %v", gccTmp(), err)
}
var data []byte
if f.Symtab != nil {
for i := range f.Symtab.Syms {
s := &f.Symtab.Syms[i]
if isDebugData(s.Name) {
// Found it. Now find data section.
if i := int(s.Sect) - 1; 0 <= i && i < len(f.Sections) {
sect := f.Sections[i]
if sect.Addr <= s.Value && s.Value < sect.Addr+sect.Size {
if sdat, err := sect.Data(); err == nil {
data = sdat[s.Value-sect.Addr:]
}
}
}
}
}
}
return d, f.ByteOrder, data
}
if f, err := elf.Open(gccTmp()); err == nil {
defer f.Close()
d, err := f.DWARF()
if err != nil {
fatalf("cannot load DWARF output from %s: %v", gccTmp(), err)
}
var data []byte
symtab, err := f.Symbols()
if err == nil {
for i := range symtab {
s := &symtab[i]
if isDebugData(s.Name) {
// Found it. Now find data section.
if i := int(s.Section); 0 <= i && i < len(f.Sections) {
sect := f.Sections[i]
if sect.Addr <= s.Value && s.Value < sect.Addr+sect.Size {
if sdat, err := sect.Data(); err == nil {
data = sdat[s.Value-sect.Addr:]
}
}
}
}
}
}
return d, f.ByteOrder, data
}
if f, err := pe.Open(gccTmp()); err == nil {
defer f.Close()
d, err := f.DWARF()
if err != nil {
fatalf("cannot load DWARF output from %s: %v", gccTmp(), err)
}
var data []byte
for _, s := range f.Symbols {
if isDebugData(s.Name) {
if i := int(s.SectionNumber) - 1; 0 <= i && i < len(f.Sections) {
sect := f.Sections[i]
if s.Value < sect.Size {
if sdat, err := sect.Data(); err == nil {
data = sdat[s.Value:]
}
}
}
}
}
return d, binary.LittleEndian, data
}
fatalf("cannot parse gcc output %s as ELF, Mach-O, PE object", gccTmp())
panic("not reached")
}
// gccDefines runs gcc -E -dM -xc - over the C program stdin
// and returns the corresponding standard output, which is the
// #defines that gcc encountered while processing the input
// and its included files.
func (p *Package) gccDefines(stdin []byte) string {
base := append(p.gccBaseCmd(), "-E", "-dM", "-xc")
base = append(base, p.gccMachine()...)
stdout, _ := runGcc(stdin, append(append(base, p.GccOptions...), "-"))
return stdout
}
// gccErrors runs gcc over the C program stdin and returns
// the errors that gcc prints. That is, this function expects
// gcc to fail.
func (p *Package) gccErrors(stdin []byte) string {
// TODO(rsc): require failure
args := p.gccCmd()
if *debugGcc {
fmt.Fprintf(os.Stderr, "$ %s <<EOF\n", strings.Join(args, " "))
os.Stderr.Write(stdin)
fmt.Fprint(os.Stderr, "EOF\n")
}
stdout, stderr, _ := run(stdin, args)
if *debugGcc {
os.Stderr.Write(stdout)
os.Stderr.Write(stderr)
}
return string(stderr)
}
// runGcc runs the gcc command line args with stdin on standard input.
// If the command exits with a non-zero exit status, runGcc prints
// details about what was run and exits.
// Otherwise runGcc returns the data written to standard output and standard error.
// Note that for some of the uses we expect useful data back
// on standard error, but for those uses gcc must still exit 0.
func runGcc(stdin []byte, args []string) (string, string) {
if *debugGcc {
fmt.Fprintf(os.Stderr, "$ %s <<EOF\n", strings.Join(args, " "))
os.Stderr.Write(stdin)
fmt.Fprint(os.Stderr, "EOF\n")
}
stdout, stderr, ok := run(stdin, args)
if *debugGcc {
os.Stderr.Write(stdout)
os.Stderr.Write(stderr)
}
if !ok {
os.Stderr.Write(stderr)
os.Exit(2)
}
return string(stdout), string(stderr)
}
// A typeConv is a translator from dwarf types to Go types
// with equivalent memory layout.
type typeConv struct {
// Cache of already-translated or in-progress types.
m map[dwarf.Type]*Type
typedef map[string]ast.Expr
// Map from types to incomplete pointers to those types.
ptrs map[dwarf.Type][]*Type
// Fields to be processed by godefsField after completing pointers.
todoFlds [][]*ast.Field
// Predeclared types.
bool ast.Expr
byte ast.Expr // denotes padding
int8, int16, int32, int64 ast.Expr
uint8, uint16, uint32, uint64, uintptr ast.Expr
float32, float64 ast.Expr
complex64, complex128 ast.Expr
void ast.Expr
unsafePointer ast.Expr
string ast.Expr
goVoid ast.Expr // _Ctype_void, denotes C's void
ptrSize int64
intSize int64
}
var tagGen int
var typedef = make(map[string]*Type)
var goIdent = make(map[string]*ast.Ident)
func (c *typeConv) Init(ptrSize, intSize int64) {
c.ptrSize = ptrSize
c.intSize = intSize
c.m = make(map[dwarf.Type]*Type)
c.ptrs = make(map[dwarf.Type][]*Type)
c.bool = c.Ident("bool")
c.byte = c.Ident("byte")
c.int8 = c.Ident("int8")
c.int16 = c.Ident("int16")
c.int32 = c.Ident("int32")
c.int64 = c.Ident("int64")
c.uint8 = c.Ident("uint8")
c.uint16 = c.Ident("uint16")
c.uint32 = c.Ident("uint32")
c.uint64 = c.Ident("uint64")
c.uintptr = c.Ident("uintptr")
c.float32 = c.Ident("float32")
c.float64 = c.Ident("float64")
c.complex64 = c.Ident("complex64")
c.complex128 = c.Ident("complex128")
c.unsafePointer = c.Ident("unsafe.Pointer")
c.void = c.Ident("void")
c.string = c.Ident("string")
c.goVoid = c.Ident("_Ctype_void")
}
// base strips away qualifiers and typedefs to get the underlying type
func base(dt dwarf.Type) dwarf.Type {
for {
if d, ok := dt.(*dwarf.QualType); ok {
dt = d.Type
continue
}
if d, ok := dt.(*dwarf.TypedefType); ok {
dt = d.Type
continue
}
break
}
return dt
}
// Map from dwarf text names to aliases we use in package "C".
var dwarfToName = map[string]string{
"long int": "long",
"long unsigned int": "ulong",
"unsigned int": "uint",
"short unsigned int": "ushort",
"short int": "short",
"long long int": "longlong",
"long long unsigned int": "ulonglong",
"signed char": "schar",
"float complex": "complexfloat",
"double complex": "complexdouble",
}
const signedDelta = 64
// String returns the current type representation. Format arguments
// are assembled within this method so that any changes in mutable
// values are taken into account.
func (tr *TypeRepr) String() string {
if len(tr.Repr) == 0 {
return ""
}
if len(tr.FormatArgs) == 0 {
return tr.Repr
}
return fmt.Sprintf(tr.Repr, tr.FormatArgs...)
}
// Empty returns true if the result of String would be "".
func (tr *TypeRepr) Empty() bool {
return len(tr.Repr) == 0
}
// Set modifies the type representation.
// If fargs are provided, repr is used as a format for fmt.Sprintf.
// Otherwise, repr is used unprocessed as the type representation.
func (tr *TypeRepr) Set(repr string, fargs ...interface{}) {
tr.Repr = repr
tr.FormatArgs = fargs
}
// FinishType completes any outstanding type mapping work.
// In particular, it resolves incomplete pointer types and also runs
// godefsFields on any new struct types.
func (c *typeConv) FinishType(pos token.Pos) {
// Completing one pointer type might produce more to complete.
// Keep looping until they're all done.
for len(c.ptrs) > 0 {
for dtype := range c.ptrs {
// Note Type might invalidate c.ptrs[dtype].
t := c.Type(dtype, pos)
for _, ptr := range c.ptrs[dtype] {
ptr.Go.(*ast.StarExpr).X = t.Go
ptr.C.Set("%s*", t.C)
}
delete(c.ptrs, dtype)
}
}
// Now that pointer types are completed, we can invoke godefsFields
// to rewrite struct definitions.
for _, fld := range c.todoFlds {
godefsFields(fld)
}
c.todoFlds = nil
}
// Type returns a *Type with the same memory layout as
// dtype when used as the type of a variable or a struct field.
func (c *typeConv) Type(dtype dwarf.Type, pos token.Pos) *Type {
if t, ok := c.m[dtype]; ok {
if t.Go == nil {
fatalf("%s: type conversion loop at %s", lineno(pos), dtype)
}
return t
}
// clang won't generate DW_AT_byte_size for pointer types,
// so we have to fix it here.
if dt, ok := base(dtype).(*dwarf.PtrType); ok && dt.ByteSize == -1 {
dt.ByteSize = c.ptrSize
}
t := new(Type)
t.Size = dtype.Size() // note: wrong for array of pointers, corrected below
t.Align = -1
t.C = &TypeRepr{Repr: dtype.Common().Name}
c.m[dtype] = t
switch dt := dtype.(type) {
default:
fatalf("%s: unexpected type: %s", lineno(pos), dtype)
case *dwarf.AddrType:
if t.Size != c.ptrSize {
fatalf("%s: unexpected: %d-byte address type - %s", lineno(pos), t.Size, dtype)
}
t.Go = c.uintptr
t.Align = t.Size
case *dwarf.ArrayType:
if dt.StrideBitSize > 0 {
// Cannot represent bit-sized elements in Go.
t.Go = c.Opaque(t.Size)
break
}
sub := c.Type(dt.Type, pos)
t.Align = sub.Align
t.Go = &ast.ArrayType{
Len: c.intExpr(dt.Count),
Elt: sub.Go,
}
t.C.Set("__typeof__(%s[%d])", sub.C, dt.Count)
case *dwarf.BoolType:
t.Go = c.bool
t.Align = 1
case *dwarf.CharType:
if t.Size != 1 {
fatalf("%s: unexpected: %d-byte char type - %s", lineno(pos), t.Size, dtype)
}
t.Go = c.int8
t.Align = 1
case *dwarf.EnumType:
if t.Align = t.Size; t.Align >= c.ptrSize {
t.Align = c.ptrSize
}
t.C.Set("enum " + dt.EnumName)
signed := 0
t.EnumValues = make(map[string]int64)
for _, ev := range dt.Val {
t.EnumValues[ev.Name] = ev.Val
if ev.Val < 0 {
signed = signedDelta
}
}
switch t.Size + int64(signed) {
default:
fatalf("%s: unexpected: %d-byte enum type - %s", lineno(pos), t.Size, dtype)
case 1:
t.Go = c.uint8
case 2:
t.Go = c.uint16
case 4:
t.Go = c.uint32
case 8:
t.Go = c.uint64
case 1 + signedDelta:
t.Go = c.int8
case 2 + signedDelta:
t.Go = c.int16
case 4 + signedDelta:
t.Go = c.int32
case 8 + signedDelta:
t.Go = c.int64
}
case *dwarf.FloatType:
switch t.Size {
default:
fatalf("%s: unexpected: %d-byte float type - %s", lineno(pos), t.Size, dtype)
case 4:
t.Go = c.float32
case 8:
t.Go = c.float64
}
if t.Align = t.Size; t.Align >= c.ptrSize {
t.Align = c.ptrSize
}
case *dwarf.ComplexType:
switch t.Size {
default:
fatalf("%s: unexpected: %d-byte complex type - %s", lineno(pos), t.Size, dtype)
case 8:
t.Go = c.complex64
case 16:
t.Go = c.complex128
}
if t.Align = t.Size; t.Align >= c.ptrSize {
t.Align = c.ptrSize
}
case *dwarf.FuncType:
// No attempt at translation: would enable calls
// directly between worlds, but we need to moderate those.
t.Go = c.uintptr
t.Align = c.ptrSize
case *dwarf.IntType:
if dt.BitSize > 0 {
fatalf("%s: unexpected: %d-bit int type - %s", lineno(pos), dt.BitSize, dtype)
}
switch t.Size {
default:
fatalf("%s: unexpected: %d-byte int type - %s", lineno(pos), t.Size, dtype)
case 1:
t.Go = c.int8
case 2:
t.Go = c.int16
case 4:
t.Go = c.int32
case 8:
t.Go = c.int64
}
if t.Align = t.Size; t.Align >= c.ptrSize {
t.Align = c.ptrSize
}
case *dwarf.PtrType:
t.Align = c.ptrSize
// Translate void* as unsafe.Pointer
if _, ok := base(dt.Type).(*dwarf.VoidType); ok {
t.Go = c.unsafePointer
t.C.Set("void*")
break
}
// Placeholder initialization; completed in FinishType.
t.Go = &ast.StarExpr{}
t.C.Set("<incomplete>*")
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
return t
case *dwarf.StructType:
// Convert to Go struct, being careful about alignment.
// Have to give it a name to simulate C "struct foo" references.
tag := dt.StructName
if dt.ByteSize < 0 && tag == "" { // opaque unnamed struct - should not be possible
break
}
if tag == "" {
tag = "__" + strconv.Itoa(tagGen)
tagGen++
} else if t.C.Empty() {
t.C.Set(dt.Kind + " " + tag)
}
name := c.Ident("_Ctype_" + dt.Kind + "_" + tag)
t.Go = name // publish before recursive calls
goIdent[name.Name] = name
if dt.ByteSize < 0 {
// Size calculation in c.Struct/c.Opaque will die with size=-1 (unknown),
// so execute the basic things that the struct case would do
// other than try to determine a Go representation.
tt := *t
tt.C = &TypeRepr{"%s %s", []interface{}{dt.Kind, tag}}
tt.Go = c.Ident("struct{}")
typedef[name.Name] = &tt
break
}
switch dt.Kind {
case "class", "union":
t.Go = c.Opaque(t.Size)
if t.C.Empty() {
t.C.Set("__typeof__(unsigned char[%d])", t.Size)
}
t.Align = 1 // TODO: should probably base this on field alignment.
typedef[name.Name] = t
case "struct":
g, csyntax, align := c.Struct(dt, pos)
if t.C.Empty() {
t.C.Set(csyntax)
}
t.Align = align
tt := *t
if tag != "" {
tt.C = &TypeRepr{"struct %s", []interface{}{tag}}
}
tt.Go = g
typedef[name.Name] = &tt
}
case *dwarf.TypedefType:
// Record typedef for printing.
if dt.Name == "_GoString_" {
// Special C name for Go string type.
// Knows string layout used by compilers: pointer plus length,
// which rounds up to 2 pointers after alignment.
t.Go = c.string
t.Size = c.ptrSize * 2
t.Align = c.ptrSize
break
}
if dt.Name == "_GoBytes_" {
// Special C name for Go []byte type.
// Knows slice layout used by compilers: pointer, length, cap.
t.Go = c.Ident("[]byte")
t.Size = c.ptrSize + 4 + 4
t.Align = c.ptrSize
break
}
name := c.Ident("_Ctype_" + dt.Name)
goIdent[name.Name] = name
sub := c.Type(dt.Type, pos)
t.Go = name
t.Size = sub.Size
t.Align = sub.Align
oldType := typedef[name.Name]
if oldType == nil {
tt := *t
tt.Go = sub.Go
typedef[name.Name] = &tt
}
// If sub.Go.Name is "_Ctype_struct_foo" or "_Ctype_union_foo" or "_Ctype_class_foo",
// use that as the Go form for this typedef too, so that the typedef will be interchangeable
// with the base type.
// In -godefs and -cdefs mode, do this for all typedefs.
if isStructUnionClass(sub.Go) || *godefs || *cdefs {
t.Go = sub.Go
if isStructUnionClass(sub.Go) {
// Use the typedef name for C code.
typedef[sub.Go.(*ast.Ident).Name].C = t.C
}
// If we've seen this typedef before, and it
// was an anonymous struct/union/class before
// too, use the old definition.
// TODO: it would be safer to only do this if
// we verify that the types are the same.
if oldType != nil && isStructUnionClass(oldType.Go) {
t.Go = oldType.Go
}
}
case *dwarf.UcharType:
if t.Size != 1 {
fatalf("%s: unexpected: %d-byte uchar type - %s", lineno(pos), t.Size, dtype)
}
t.Go = c.uint8
t.Align = 1
case *dwarf.UintType:
if dt.BitSize > 0 {
fatalf("%s: unexpected: %d-bit uint type - %s", lineno(pos), dt.BitSize, dtype)
}
switch t.Size {
default:
fatalf("%s: unexpected: %d-byte uint type - %s", lineno(pos), t.Size, dtype)
case 1:
t.Go = c.uint8
case 2:
t.Go = c.uint16
case 4:
t.Go = c.uint32
case 8:
t.Go = c.uint64
}
if t.Align = t.Size; t.Align >= c.ptrSize {
t.Align = c.ptrSize
}
case *dwarf.VoidType:
t.Go = c.goVoid
t.C.Set("void")
t.Align = 1
}
switch dtype.(type) {
case *dwarf.AddrType, *dwarf.BoolType, *dwarf.CharType, *dwarf.IntType, *dwarf.FloatType, *dwarf.UcharType, *dwarf.UintType:
s := dtype.Common().Name
if s != "" {
if ss, ok := dwarfToName[s]; ok {
s = ss
}
s = strings.Join(strings.Split(s, " "), "") // strip spaces
name := c.Ident("_Ctype_" + s)
tt := *t
typedef[name.Name] = &tt
if !*godefs && !*cdefs {
t.Go = name
}
}
}
if t.Size <= 0 {
// Clang does not record the size of a pointer in its DWARF entry,
// so if dtype is an array, the call to dtype.Size at the top of the function
// computed the size as the array length * 0 = 0.
// The type switch called Type (this function) recursively on the pointer
// entry, and the code near the top of the function updated the size to
// be correct, so calling dtype.Size again will produce the correct value.
t.Size = dtype.Size()
if t.Size < 0 {
// Unsized types are [0]byte, unless they're typedefs of other types
// or structs with tags.
// if so, use the name we've already defined.
t.Size = 0
switch dt := dtype.(type) {
case *dwarf.TypedefType:
// ok
case *dwarf.StructType:
if dt.StructName != "" {
break
}
t.Go = c.Opaque(0)
default:
t.Go = c.Opaque(0)
}
if t.C.Empty() {
t.C.Set("void")
}
return t
}
}
if t.C.Empty() {
fatalf("%s: internal error: did not create C name for %s", lineno(pos), dtype)
}
return t
}
// isStructUnionClass reports whether the type described by the Go syntax x
// is a struct, union, or class with a tag.
func isStructUnionClass(x ast.Expr) bool {
id, ok := x.(*ast.Ident)
if !ok {
return false
}
name := id.Name
return strings.HasPrefix(name, "_Ctype_struct_") ||
strings.HasPrefix(name, "_Ctype_union_") ||
strings.HasPrefix(name, "_Ctype_class_")
}
// 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)
switch dt := dtype.(type) {
case *dwarf.ArrayType:
// Arrays are passed implicitly as pointers in C.
// In Go, we must be explicit.
tr := &TypeRepr{}
tr.Set("%s*", t.C)
return &Type{
Size: c.ptrSize,
Align: c.ptrSize,
Go: &ast.StarExpr{X: t.Go},
C: tr,
}
case *dwarf.TypedefType:
// C has much more relaxed rules than Go for
// implicit type conversions. When the parameter
// is type T defined as *X, simulate a little of the
// laxness of C by making the argument *X instead of T.
if ptr, ok := base(dt.Type).(*dwarf.PtrType); ok {
// Unless the typedef happens to point to void* since
// Go has special rules around using unsafe.Pointer.
if _, void := base(ptr.Type).(*dwarf.VoidType); void {
break
}
t = c.Type(ptr, pos)
if t == nil {
return nil
}
// Remember the C spelling, in case the struct
// has __attribute__((unavailable)) on it. See issue 2888.
t.Typedef = dt.Name
}
}
return t
}
// FuncType returns the Go type analogous to dtype.
// There is no guarantee about matching memory layout.
func (c *typeConv) FuncType(dtype *dwarf.FuncType, pos token.Pos) *FuncType {
p := make([]*Type, len(dtype.ParamType))
gp := make([]*ast.Field, len(dtype.ParamType))
for i, f := range dtype.ParamType {
// gcc's DWARF generator outputs a single DotDotDotType parameter for
// function pointers that specify no parameters (e.g. void
// (*__cgo_0)()). Treat this special case as void. This case is
// invalid according to ISO C anyway (i.e. void (*__cgo_1)(...) is not
// legal).
if _, ok := f.(*dwarf.DotDotDotType); ok && i == 0 {
p, gp = nil, nil
break
}
p[i] = c.FuncArg(f, pos)
gp[i] = &ast.Field{Type: p[i].Go}
}
var r *Type
var gr []*ast.Field
if _, ok := dtype.ReturnType.(*dwarf.VoidType); ok {
gr = []*ast.Field{{Type: c.goVoid}}
} else if dtype.ReturnType != nil {
r = c.Type(dtype.ReturnType, pos)
gr = []*ast.Field{{Type: r.Go}}
}
return &FuncType{
Params: p,
Result: r,
Go: &ast.FuncType{
Params: &ast.FieldList{List: gp},
Results: &ast.FieldList{List: gr},
},
}
}
// Identifier
func (c *typeConv) Ident(s string) *ast.Ident {
return ast.NewIdent(s)
}
// Opaque type of n bytes.
func (c *typeConv) Opaque(n int64) ast.Expr {
return &ast.ArrayType{
Len: c.intExpr(n),
Elt: c.byte,
}
}
// Expr for integer n.
func (c *typeConv) intExpr(n int64) ast.Expr {
return &ast.BasicLit{
Kind: token.INT,
Value: strconv.FormatInt(n, 10),
}
}
// Add padding of given size to fld.
func (c *typeConv) pad(fld []*ast.Field, size int64) []*ast.Field {
n := len(fld)
fld = fld[0 : n+1]
fld[n] = &ast.Field{Names: []*ast.Ident{c.Ident("_")}, Type: c.Opaque(size)}
return fld
}
// Struct conversion: return Go and (6g) C syntax for type.
func (c *typeConv) Struct(dt *dwarf.StructType, pos token.Pos) (expr *ast.StructType, csyntax string, align int64) {
var buf bytes.Buffer
buf.WriteString("struct {")
fld := make([]*ast.Field, 0, 2*len(dt.Field)+1) // enough for padding around every field
off := int64(0)
// Rename struct fields that happen to be named Go keywords into
// _{keyword}. Create a map from C ident -> Go ident. The Go ident will
// be mangled. Any existing identifier that already has the same name on
// the C-side will cause the Go-mangled version to be prefixed with _.
// (e.g. in a struct with fields '_type' and 'type', the latter would be
// rendered as '__type' in Go).
ident := make(map[string]string)
used := make(map[string]bool)
for _, f := range dt.Field {
ident[f.Name] = f.Name
used[f.Name] = true
}
if !*godefs && !*cdefs {
for cid, goid := range ident {
if token.Lookup(goid).IsKeyword() {
// Avoid keyword
goid = "_" + goid
// Also avoid existing fields
for _, exist := used[goid]; exist; _, exist = used[goid] {
goid = "_" + goid
}
used[goid] = true
ident[cid] = goid
}
}
}
anon := 0
for _, f := range dt.Field {
if f.ByteOffset > off {
fld = c.pad(fld, f.ByteOffset-off)
off = f.ByteOffset
}
t := c.Type(f.Type, pos)
tgo := t.Go
size := t.Size
talign := t.Align
if f.BitSize > 0 {
if f.BitSize%8 != 0 {
continue
}
size = f.BitSize / 8
name := tgo.(*ast.Ident).String()
if strings.HasPrefix(name, "int") {
name = "int"
} else {
name = "uint"
}
tgo = ast.NewIdent(name + fmt.Sprint(f.BitSize))
talign = size
}
if talign > 0 && f.ByteOffset%talign != 0 {
// Drop misaligned fields, the same way we drop integer bit fields.
// The goal is to make available what can be made available.
// Otherwise one bad and unneeded field in an otherwise okay struct
// makes the whole program not compile. Much of the time these
// structs are in system headers that cannot be corrected.
continue
}
n := len(fld)
fld = fld[0 : n+1]
name := f.Name
if name == "" {
name = fmt.Sprintf("anon%d", anon)
anon++
ident[name] = name
}
fld[n] = &ast.Field{Names: []*ast.Ident{c.Ident(ident[name])}, Type: tgo}
off += size
buf.WriteString(t.C.String())
buf.WriteString(" ")
buf.WriteString(name)
buf.WriteString("; ")
if talign > align {
align = talign
}
}
if off < dt.ByteSize {
fld = c.pad(fld, dt.ByteSize-off)
off = dt.ByteSize
}
if off != dt.ByteSize {
fatalf("%s: struct size calculation error off=%d bytesize=%d", lineno(pos), off, dt.ByteSize)
}
buf.WriteString("}")
csyntax = buf.String()
if *godefs || *cdefs {
c.todoFlds = append(c.todoFlds, fld)
}
expr = &ast.StructType{Fields: &ast.FieldList{List: fld}}
return
}
func upper(s string) string {
if s == "" {
return ""
}
r, size := utf8.DecodeRuneInString(s)
if r == '_' {
return "X" + s
}
return string(unicode.ToUpper(r)) + s[size:]
}
// godefsFields rewrites field names for use in Go or C definitions.
// It strips leading common prefixes (like tv_ in tv_sec, tv_usec)
// converts names to upper case, and rewrites _ into Pad_godefs_n,
// so that all fields are exported.
func godefsFields(fld []*ast.Field) {
prefix := fieldPrefix(fld)
npad := 0
for _, f := range fld {
for _, n := range f.Names {
if n.Name != prefix {
n.Name = strings.TrimPrefix(n.Name, prefix)
}
if n.Name == "_" {
// Use exported name instead.
n.Name = "Pad_cgo_" + strconv.Itoa(npad)
npad++
}
if !*cdefs {
n.Name = upper(n.Name)
}
}
p := &f.Type
t := *p
if star, ok := t.(*ast.StarExpr); ok {
star = &ast.StarExpr{X: star.X}
*p = star
p = &star.X
t = *p
}
if id, ok := t.(*ast.Ident); ok {
if id.Name == "unsafe.Pointer" {
*p = ast.NewIdent("*byte")
}
}
}
}
// fieldPrefix returns the prefix that should be removed from all the
// field names when generating the C or Go code. For generated
// C, we leave the names as is (tv_sec, tv_usec), since that's what
// people are used to seeing in C. For generated Go code, such as
// package syscall's data structures, we drop a common prefix
// (so sec, usec, which will get turned into Sec, Usec for exporting).
func fieldPrefix(fld []*ast.Field) string {
if *cdefs {
return ""
}
prefix := ""
for _, f := range fld {
for _, n := range f.Names {
// Ignore field names that don't have the prefix we're
// looking for. It is common in C headers to have fields
// named, say, _pad in an otherwise prefixed header.
// If the struct has 3 fields tv_sec, tv_usec, _pad1, then we
// still want to remove the tv_ prefix.
// The check for "orig_" here handles orig_eax in the
// x86 ptrace register sets, which otherwise have all fields
// with reg_ prefixes.
if strings.HasPrefix(n.Name, "orig_") || strings.HasPrefix(n.Name, "_") {
continue
}
i := strings.Index(n.Name, "_")
if i < 0 {
continue
}
if prefix == "" {
prefix = n.Name[:i+1]
} else if prefix != n.Name[:i+1] {
return ""
}
}
}
return prefix
}
// Copyright 2011 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"
"go/ast"
"go/printer"
"go/token"
"os"
"strings"
)
// godefs returns the output for -godefs mode.
func (p *Package) godefs(f *File, srcfile string) string {
var buf bytes.Buffer
fmt.Fprintf(&buf, "// Created by cgo -godefs - DO NOT EDIT\n")
fmt.Fprintf(&buf, "// %s\n", strings.Join(os.Args, " "))
fmt.Fprintf(&buf, "\n")
override := make(map[string]string)
// Allow source file to specify override mappings.
// For example, the socket data structures refer
// to in_addr and in_addr6 structs but we want to be
// able to treat them as byte arrays, so the godefs
// inputs in package syscall say
//
// // +godefs map struct_in_addr [4]byte
// // +godefs map struct_in_addr6 [16]byte
//
for _, g := range f.Comments {
for _, c := range g.List {
i := strings.Index(c.Text, "+godefs map")
if i < 0 {
continue
}
s := strings.TrimSpace(c.Text[i+len("+godefs map"):])
i = strings.Index(s, " ")
if i < 0 {
fmt.Fprintf(os.Stderr, "invalid +godefs map comment: %s\n", c.Text)
continue
}
override["_Ctype_"+strings.TrimSpace(s[:i])] = strings.TrimSpace(s[i:])
}
}
for _, n := range f.Name {
if s := override[n.Go]; s != "" {
override[n.Mangle] = s
}
}
// Otherwise, if the source file says type T C.whatever,
// use "T" as the mangling of C.whatever,
// except in the definition (handled at end of function).
refName := make(map[*ast.Expr]*Name)
for _, r := range f.Ref {
refName[r.Expr] = r.Name
}
for _, d := range f.AST.Decls {
d, ok := d.(*ast.GenDecl)
if !ok || d.Tok != token.TYPE {
continue
}
for _, s := range d.Specs {
s := s.(*ast.TypeSpec)
n := refName[&s.Type]
if n != nil && n.Mangle != "" {
override[n.Mangle] = s.Name.Name
}
}
}
// Extend overrides using typedefs:
// If we know that C.xxx should format as T
// and xxx is a typedef for yyy, make C.yyy format as T.
for typ, def := range typedef {
if new := override[typ]; new != "" {
if id, ok := def.Go.(*ast.Ident); ok {
override[id.Name] = new
}
}
}
// Apply overrides.
for old, new := range override {
if id := goIdent[old]; id != nil {
id.Name = new
}
}
// Any names still using the _C syntax are not going to compile,
// although in general we don't know whether they all made it
// into the file, so we can't warn here.
//
// The most common case is union types, which begin with
// _Ctype_union and for which typedef[name] is a Go byte
// array of the appropriate size (such as [4]byte).
// Substitute those union types with byte arrays.
for name, id := range goIdent {
if id.Name == name && strings.Contains(name, "_Ctype_union") {
if def := typedef[name]; def != nil {
id.Name = gofmt(def)
}
}
}
conf.Fprint(&buf, fset, f.AST)
return buf.String()
}
// cdefs returns the output for -cdefs mode.
// The easiest way to do this is to translate the godefs Go to C.
func (p *Package) cdefs(f *File, srcfile string) string {
godefsOutput := p.godefs(f, srcfile)
lines := strings.Split(godefsOutput, "\n")
lines[0] = "// Created by cgo -cdefs - DO NOT EDIT"
for i, line := range lines {
lines[i] = strings.TrimSpace(line)
}
var out bytes.Buffer
printf := func(format string, args ...interface{}) { fmt.Fprintf(&out, format, args...) }
didTypedef := false
for i := 0; i < len(lines); i++ {
line := lines[i]
// Delete
// package x
if strings.HasPrefix(line, "package ") {
continue
}
// Convert
// const (
// A = 1
// B = 2
// )
//
// to
//
// enum {
// A = 1,
// B = 2,
// };
if line == "const (" {
printf("enum {\n")
for i++; i < len(lines) && lines[i] != ")"; i++ {
line = lines[i]
if line != "" {
printf("\t%s,", line)
}
printf("\n")
}
printf("};\n")
continue
}
// Convert
// const A = 1
// to
// enum { A = 1 };
if strings.HasPrefix(line, "const ") {
printf("enum { %s };\n", line[len("const "):])
continue
}
// On first type definition, typedef all the structs
// in case there are dependencies between them.
if !didTypedef && strings.HasPrefix(line, "type ") {
didTypedef = true
for _, line := range lines {
line = strings.TrimSpace(line)
if strings.HasPrefix(line, "type ") && strings.HasSuffix(line, " struct {") {
s := strings.TrimSuffix(strings.TrimPrefix(line, "type "), " struct {")
printf("typedef struct %s %s;\n", s, s)
}
}
printf("\n")
printf("#pragma pack on\n")
printf("\n")
}
// Convert
// type T struct {
// X int64
// Y *int32
// Z [4]byte
// }
//
// to
//
// struct T {
// int64 X;
// int32 *Y;
// byte Z[4];
// }
if strings.HasPrefix(line, "type ") && strings.HasSuffix(line, " struct {") {
if len(lines) > i+1 && lines[i+1] == "}" {
// do not output empty struct
i++
continue
}
s := line[len("type ") : len(line)-len(" struct {")]
printf("struct %s {\n", s)
for i++; i < len(lines) && lines[i] != "}"; i++ {
line := lines[i]
if line != "" {
f := strings.Fields(line)
if len(f) != 2 {
fmt.Fprintf(os.Stderr, "cgo: cannot parse struct field: %s\n", line)
nerrors++
continue
}
printf("\t%s;", cdecl(f[0], f[1]))
}
printf("\n")
}
printf("};\n")
continue
}
// Convert
// type T int
// to
// typedef int T;
if strings.HasPrefix(line, "type ") {
f := strings.Fields(line[len("type "):])
if len(f) != 2 {
fmt.Fprintf(os.Stderr, "cgo: cannot parse type definition: %s\n", line)
nerrors++
continue
}
printf("typedef\t%s;\n", cdecl(f[0], f[1]))
continue
}
printf("%s\n", line)
}
if didTypedef {
printf("\n")
printf("#pragma pack off\n")
}
return out.String()
}
// cdecl returns the C declaration for the given Go name and type.
// It only handles the specific cases necessary for converting godefs output.
func cdecl(name, typ string) string {
// X *[0]byte -> X *void
if strings.HasPrefix(typ, "*[0]") {
typ = "*void"
}
// X [4]byte -> X[4] byte
for strings.HasPrefix(typ, "[") {
i := strings.Index(typ, "]") + 1
name = name + typ[:i]
typ = typ[i:]
}
// X *byte -> *X byte
for strings.HasPrefix(typ, "*") {
name = "*" + name
typ = typ[1:]
}
// X T -> T X
// Handle the special case: 'unsafe.Pointer' is 'void *'
if typ == "unsafe.Pointer" {
typ = "void"
name = "*" + name
}
return typ + "\t" + name
}
var gofmtBuf bytes.Buffer
// gofmt returns the gofmt-formatted string for an AST node.
func gofmt(n interface{}) string {
gofmtBuf.Reset()
err := printer.Fprint(&gofmtBuf, fset, n)
if err != nil {
return "<" + err.Error() + ">"
}
return gofmtBuf.String()
}
// Copyright 2009 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.
// Cgo; see gmp.go for an overview.
// TODO(rsc):
// Emit correct line number annotations.
// Make 6g understand the annotations.
package main
import (
"crypto/md5"
"flag"
"fmt"
"go/ast"
"go/printer"
"go/token"
"io"
"os"
"path/filepath"
"reflect"
"runtime"
"sort"
"strings"
)
// A Package collects information about the package we're going to write.
type Package struct {
PackageName string // name of package
PackagePath string
PtrSize int64
IntSize int64
GccOptions []string
CgoFlags map[string][]string // #cgo flags (CFLAGS, LDFLAGS)
Written map[string]bool
Name map[string]*Name // accumulated Name from Files
ExpFunc []*ExpFunc // accumulated ExpFunc from Files
Decl []ast.Decl
GoFiles []string // list of Go files
GccFiles []string // list of gcc output files
Preamble string // collected preamble for _cgo_export.h
}
// A File collects information about a single Go input file.
type File struct {
AST *ast.File // parsed AST
Comments []*ast.CommentGroup // comments from file
Package string // Package name
Preamble string // C preamble (doc comment on import "C")
Ref []*Ref // all references to C.xxx in AST
ExpFunc []*ExpFunc // exported functions for this file
Name map[string]*Name // map from Go name to Name
}
func nameKeys(m map[string]*Name) []string {
var ks []string
for k := range m {
ks = append(ks, k)
}
sort.Strings(ks)
return ks
}
// A Ref refers to an expression of the form C.xxx in the AST.
type Ref struct {
Name *Name
Expr *ast.Expr
Context string // "type", "expr", "call", or "call2"
}
func (r *Ref) Pos() token.Pos {
return (*r.Expr).Pos()
}
// A Name collects information about C.xxx.
type Name struct {
Go string // name used in Go referring to package C
Mangle string // name used in generated Go
C string // name used in C
Define string // #define expansion
Kind string // "const", "type", "var", "fpvar", "func", "not-type"
Type *Type // the type of xxx
FuncType *FuncType
AddError bool
Const string // constant definition
}
// IsVar returns true if Kind is either "var" or "fpvar"
func (n *Name) IsVar() bool {
return n.Kind == "var" || n.Kind == "fpvar"
}
// A ExpFunc is an exported function, callable from C.
// Such functions are identified in the Go input file
// by doc comments containing the line //export ExpName
type ExpFunc struct {
Func *ast.FuncDecl
ExpName string // name to use from C
}
// A TypeRepr contains the string representation of a type.
type TypeRepr struct {
Repr string
FormatArgs []interface{}
}
// A Type collects information about a type in both the C and Go worlds.
type Type struct {
Size int64
Align int64
C *TypeRepr
Go ast.Expr
EnumValues map[string]int64
Typedef string
}
// A FuncType collects information about a function type in both the C and Go worlds.
type FuncType struct {
Params []*Type
Result *Type
Go *ast.FuncType
}
func usage() {
fmt.Fprint(os.Stderr, "usage: cgo -- [compiler options] file.go ...\n")
flag.PrintDefaults()
os.Exit(2)
}
var ptrSizeMap = map[string]int64{
"386": 4,
"amd64": 8,
"arm": 4,
"ppc64": 8,
"ppc64le": 8,
"s390x": 8,
}
var intSizeMap = map[string]int64{
"386": 4,
"amd64": 8,
"arm": 4,
"ppc64": 8,
"ppc64le": 8,
"s390x": 8,
}
var cPrefix string
var fset = token.NewFileSet()
var dynobj = flag.String("dynimport", "", "if non-empty, print dynamic import data for that file")
var dynout = flag.String("dynout", "", "write -dynobj output to this file")
var dynlinker = flag.Bool("dynlinker", false, "record dynamic linker information in dynimport mode")
// These flags are for bootstrapping a new Go implementation,
// to generate Go and C headers that match the data layout and
// 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 cdefs = flag.Bool("cdefs", false, "for bootstrap: write C definitions for C file to standard output")
var objDir = flag.String("objdir", "", "object directory")
var gccgo = flag.Bool("gccgo", false, "generate files for use with gccgo")
var gccgoprefix = flag.String("gccgoprefix", "", "-fgo-prefix option used with gccgo")
var gccgopkgpath = flag.String("gccgopkgpath", "", "-fgo-pkgpath option used with gccgo")
var importRuntimeCgo = flag.Bool("import_runtime_cgo", true, "import runtime/cgo in generated code")
var importSyscall = flag.Bool("import_syscall", true, "import syscall in generated code")
var goarch, goos string
func main() {
flag.Usage = usage
flag.Parse()
if *dynobj != "" {
// cgo -dynimport is essentially a separate helper command
// built into the cgo binary. It scans a gcc-produced executable
// and dumps information about the imported symbols and the
// imported libraries. The 'go build' rules for cgo prepare an
// appropriate executable and then use its import information
// instead of needing to make the linkers duplicate all the
// specialized knowledge gcc has about where to look for imported
// symbols and which ones to use.
dynimport(*dynobj)
return
}
if *godefs && *cdefs {
fmt.Fprintf(os.Stderr, "cgo: cannot use -cdefs and -godefs together\n")
os.Exit(2)
}
if *godefs || *cdefs {
// Generating definitions pulled from header files,
// to be checked into Go repositories.
// Line numbers are just noise.
conf.Mode &^= printer.SourcePos
}
args := flag.Args()
if len(args) < 1 {
usage()
}
// Find first arg that looks like a go file and assume everything before
// that are options to pass to gcc.
var i int
for i = len(args); i > 0; i-- {
if !strings.HasSuffix(args[i-1], ".go") {
break
}
}
if i == len(args) {
usage()
}
goFiles := args[i:]
p := newPackage(args[:i])
// Record CGO_LDFLAGS from the environment for external linking.
if ldflags := os.Getenv("CGO_LDFLAGS"); ldflags != "" {
args, err := splitQuoted(ldflags)
if err != nil {
fatalf("bad CGO_LDFLAGS: %q (%s)", ldflags, err)
}
p.addToFlag("LDFLAGS", args)
}
// Need a unique prefix for the global C symbols that
// we use to coordinate between gcc and ourselves.
// We already put _cgo_ at the beginning, so the main
// concern is other cgo wrappers for the same functions.
// Use the beginning of the md5 of the input to disambiguate.
h := md5.New()
for _, input := range goFiles {
f, err := os.Open(input)
if err != nil {
fatalf("%s", err)
}
io.Copy(h, f)
f.Close()
}
cPrefix = fmt.Sprintf("_%x", h.Sum(nil)[0:6])
fs := make([]*File, len(goFiles))
for i, input := range goFiles {
f := new(File)
f.ReadGo(input)
f.DiscardCgoDirectives()
fs[i] = f
}
if *objDir == "" {
// make sure that _obj directory exists, so that we can write
// all the output files there.
os.Mkdir("_obj", 0777)
*objDir = "_obj"
}
*objDir += string(filepath.Separator)
for i, input := range goFiles {
f := fs[i]
p.Translate(f)
for _, cref := range f.Ref {
switch cref.Context {
case "call", "call2":
if cref.Name.Kind != "type" {
break
}
*cref.Expr = cref.Name.Type.Go
}
}
if nerrors > 0 {
os.Exit(2)
}
pkg := f.Package
if dir := os.Getenv("CGOPKGPATH"); dir != "" {
pkg = filepath.Join(dir, pkg)
}
p.PackagePath = pkg
p.Record(f)
if *godefs {
os.Stdout.WriteString(p.godefs(f, input))
} else if *cdefs {
os.Stdout.WriteString(p.cdefs(f, input))
} else {
p.writeOutput(f, input)
}
}
if !*godefs && !*cdefs {
p.writeDefs()
}
if nerrors > 0 {
os.Exit(2)
}
}
// newPackage returns a new Package that will invoke
// gcc with the additional arguments specified in args.
func newPackage(args []string) *Package {
goarch = runtime.GOARCH
if s := os.Getenv("GOARCH"); s != "" {
goarch = s
}
goos = runtime.GOOS
if s := os.Getenv("GOOS"); s != "" {
goos = s
}
ptrSize := ptrSizeMap[goarch]
if ptrSize == 0 {
fatalf("unknown ptrSize for $GOARCH %q", goarch)
}
intSize := intSizeMap[goarch]
if intSize == 0 {
fatalf("unknown intSize for $GOARCH %q", goarch)
}
// Reset locale variables so gcc emits English errors [sic].
os.Setenv("LANG", "en_US.UTF-8")
os.Setenv("LC_ALL", "C")
p := &Package{
PtrSize: ptrSize,
IntSize: intSize,
CgoFlags: make(map[string][]string),
Written: make(map[string]bool),
}
p.addToFlag("CFLAGS", args)
return p
}
// Record what needs to be recorded about f.
func (p *Package) Record(f *File) {
if p.PackageName == "" {
p.PackageName = f.Package
} else if p.PackageName != f.Package {
error_(token.NoPos, "inconsistent package names: %s, %s", p.PackageName, f.Package)
}
if p.Name == nil {
p.Name = f.Name
} else {
for k, v := range f.Name {
if p.Name[k] == nil {
p.Name[k] = v
} else if !reflect.DeepEqual(p.Name[k], v) {
error_(token.NoPos, "inconsistent definitions for C.%s", fixGo(k))
}
}
}
if f.ExpFunc != nil {
p.ExpFunc = append(p.ExpFunc, f.ExpFunc...)
p.Preamble += "\n" + f.Preamble
}
p.Decl = append(p.Decl, f.AST.Decls...)
}
// Copyright 2009 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"
"debug/elf"
"debug/macho"
"debug/pe"
"fmt"
"go/ast"
"go/printer"
"go/token"
"os"
"sort"
"strings"
)
var conf = printer.Config{Mode: printer.SourcePos, Tabwidth: 8}
// writeDefs creates output files to be compiled by 6g, 6c, and gcc.
// (The comments here say 6g and 6c but the code applies to the 8 and 5 tools too.)
func (p *Package) writeDefs() {
fgo2 := creat(*objDir + "_cgo_gotypes.go")
fc := creat(*objDir + "_cgo_defun.c")
fm := creat(*objDir + "_cgo_main.c")
var gccgoInit bytes.Buffer
fflg := creat(*objDir + "_cgo_flags")
for k, v := range p.CgoFlags {
fmt.Fprintf(fflg, "_CGO_%s=%s\n", k, strings.Join(v, " "))
if k == "LDFLAGS" && !*gccgo {
for _, arg := range v {
fmt.Fprintf(fc, "#pragma cgo_ldflag %q\n", arg)
}
}
}
fflg.Close()
// Write C main file for using gcc to resolve imports.
fmt.Fprintf(fm, "int main() { return 0; }\n")
if *importRuntimeCgo {
fmt.Fprintf(fm, "void crosscall2(void(*fn)(void*, int), void *a, int c) { }\n")
} else {
// If we're not importing runtime/cgo, we *are* runtime/cgo,
// which provides crosscall2. We just need a prototype.
fmt.Fprintf(fm, "void crosscall2(void(*fn)(void*, int), void *a, int c);\n")
}
fmt.Fprintf(fm, "void _cgo_allocate(void *a, int c) { }\n")
fmt.Fprintf(fm, "void _cgo_panic(void *a, int c) { }\n")
// Write second Go output: definitions of _C_xxx.
// In a separate file so that the import of "unsafe" does not
// pollute the original file.
fmt.Fprintf(fgo2, "// Created by cgo - DO NOT EDIT\n\n")
fmt.Fprintf(fgo2, "package %s\n\n", p.PackageName)
fmt.Fprintf(fgo2, "import \"unsafe\"\n\n")
if *importSyscall {
fmt.Fprintf(fgo2, "import \"syscall\"\n\n")
}
if !*gccgo && *importRuntimeCgo {
fmt.Fprintf(fgo2, "import _ \"runtime/cgo\"\n\n")
}
fmt.Fprintf(fgo2, "type _ unsafe.Pointer\n\n")
if *importSyscall {
fmt.Fprintf(fgo2, "func _Cerrno(dst *error, x int32) { *dst = syscall.Errno(x) }\n")
}
typedefNames := make([]string, 0, len(typedef))
for name := range typedef {
typedefNames = append(typedefNames, name)
}
sort.Strings(typedefNames)
for _, name := range typedefNames {
def := typedef[name]
fmt.Fprintf(fgo2, "type %s ", name)
conf.Fprint(fgo2, fset, def.Go)
fmt.Fprintf(fgo2, "\n\n")
}
if *gccgo {
fmt.Fprintf(fgo2, "type _Ctype_void byte\n")
} else {
fmt.Fprintf(fgo2, "type _Ctype_void [0]byte\n")
}
if *gccgo {
fmt.Fprintf(fc, p.cPrologGccgo())
} else {
fmt.Fprintf(fc, cProlog)
}
gccgoSymbolPrefix := p.gccgoSymbolPrefix()
cVars := make(map[string]bool)
for _, key := range nameKeys(p.Name) {
n := p.Name[key]
if !n.IsVar() {
continue
}
if !cVars[n.C] {
fmt.Fprintf(fm, "extern char %s[];\n", n.C)
fmt.Fprintf(fm, "void *_cgohack_%s = %s;\n\n", n.C, n.C)
if !*gccgo {
fmt.Fprintf(fc, "#pragma cgo_import_static %s\n", n.C)
}
fmt.Fprintf(fc, "extern byte *%s;\n", n.C)
cVars[n.C] = true
}
var amp string
var node ast.Node
if n.Kind == "var" {
amp = "&"
node = &ast.StarExpr{X: n.Type.Go}
} else if n.Kind == "fpvar" {
node = n.Type.Go
if *gccgo {
amp = "&"
}
} else {
panic(fmt.Errorf("invalid var kind %q", n.Kind))
}
if *gccgo {
fmt.Fprintf(fc, `extern void *%s __asm__("%s.%s");`, n.Mangle, gccgoSymbolPrefix, n.Mangle)
fmt.Fprintf(&gccgoInit, "\t%s = %s%s;\n", n.Mangle, amp, n.C)
} else {
fmt.Fprintf(fc, "void *·%s = %s%s;\n", n.Mangle, amp, n.C)
}
fmt.Fprintf(fc, "\n")
fmt.Fprintf(fgo2, "var %s ", n.Mangle)
conf.Fprint(fgo2, fset, node)
fmt.Fprintf(fgo2, "\n")
}
fmt.Fprintf(fc, "\n")
for _, key := range nameKeys(p.Name) {
n := p.Name[key]
if n.Const != "" {
fmt.Fprintf(fgo2, "const _Cconst_%s = %s\n", n.Go, n.Const)
}
}
fmt.Fprintf(fgo2, "\n")
for _, key := range nameKeys(p.Name) {
n := p.Name[key]
if n.FuncType != nil {
p.writeDefsFunc(fc, fgo2, n)
}
}
if *gccgo {
p.writeGccgoExports(fgo2, fc, fm)
} else {
p.writeExports(fgo2, fc, fm)
}
init := gccgoInit.String()
if init != "" {
fmt.Fprintln(fc, "static void init(void) __attribute__ ((constructor));")
fmt.Fprintln(fc, "static void init(void) {")
fmt.Fprint(fc, init)
fmt.Fprintln(fc, "}")
}
fgo2.Close()
fc.Close()
}
func dynimport(obj string) {
stdout := os.Stdout
if *dynout != "" {
f, err := os.Create(*dynout)
if err != nil {
fatalf("%s", err)
}
stdout = f
}
if f, err := elf.Open(obj); err == nil {
if *dynlinker {
// Emit the cgo_dynamic_linker line.
if sec := f.Section(".interp"); sec != nil {
if data, err := sec.Data(); err == nil && len(data) > 1 {
// skip trailing \0 in data
fmt.Fprintf(stdout, "#pragma cgo_dynamic_linker %q\n", string(data[:len(data)-1]))
}
}
}
sym, err := f.ImportedSymbols()
if err != nil {
fatalf("cannot load imported symbols from ELF file %s: %v", obj, err)
}
for _, s := range sym {
targ := s.Name
if s.Version != "" {
targ += "#" + s.Version
}
fmt.Fprintf(stdout, "#pragma cgo_import_dynamic %s %s %q\n", s.Name, targ, s.Library)
}
lib, err := f.ImportedLibraries()
if err != nil {
fatalf("cannot load imported libraries from ELF file %s: %v", obj, err)
}
for _, l := range lib {
fmt.Fprintf(stdout, "#pragma cgo_import_dynamic _ _ %q\n", l)
}
return
}
if f, err := macho.Open(obj); err == nil {
sym, err := f.ImportedSymbols()
if err != nil {
fatalf("cannot load imported symbols from Mach-O file %s: %v", obj, err)
}
for _, s := range sym {
if len(s) > 0 && s[0] == '_' {
s = s[1:]
}
fmt.Fprintf(stdout, "#pragma cgo_import_dynamic %s %s %q\n", s, s, "")
}
lib, err := f.ImportedLibraries()
if err != nil {
fatalf("cannot load imported libraries from Mach-O file %s: %v", obj, err)
}
for _, l := range lib {
fmt.Fprintf(stdout, "#pragma cgo_import_dynamic _ _ %q\n", l)
}
return
}
if f, err := pe.Open(obj); err == nil {
sym, err := f.ImportedSymbols()
if err != nil {
fatalf("cannot load imported symbols from PE file %s: %v", obj, err)
}
for _, s := range sym {
ss := strings.Split(s, ":")
name := strings.Split(ss[0], "@")[0]
fmt.Fprintf(stdout, "#pragma cgo_import_dynamic %s %s %q\n", name, ss[0], strings.ToLower(ss[1]))
}
return
}
fatalf("cannot parse %s as ELF, Mach-O or PE", obj)
}
// Construct a gcc struct matching the 6c argument frame.
// Assumes that in gcc, char is 1 byte, short 2 bytes, int 4 bytes, long long 8 bytes.
// These assumptions are checked by the gccProlog.
// Also assumes that 6c convention is to word-align the
// input and output parameters.
func (p *Package) structType(n *Name) (string, int64) {
var buf bytes.Buffer
fmt.Fprint(&buf, "struct {\n")
off := int64(0)
for i, t := range n.FuncType.Params {
if off%t.Align != 0 {
pad := t.Align - off%t.Align
fmt.Fprintf(&buf, "\t\tchar __pad%d[%d];\n", off, pad)
off += pad
}
c := t.Typedef
if c == "" {
c = t.C.String()
}
fmt.Fprintf(&buf, "\t\t%s p%d;\n", c, i)
off += t.Size
}
if off%p.PtrSize != 0 {
pad := p.PtrSize - off%p.PtrSize
fmt.Fprintf(&buf, "\t\tchar __pad%d[%d];\n", off, pad)
off += pad
}
if t := n.FuncType.Result; t != nil {
if off%t.Align != 0 {
pad := t.Align - off%t.Align
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)
off += t.Size
}
if off%p.PtrSize != 0 {
pad := p.PtrSize - off%p.PtrSize
fmt.Fprintf(&buf, "\t\tchar __pad%d[%d];\n", off, pad)
off += pad
}
if n.AddError {
fmt.Fprint(&buf, "\t\tint e[2*sizeof(void *)/sizeof(int)]; /* error */\n")
off += 2 * p.PtrSize
}
if off == 0 {
fmt.Fprintf(&buf, "\t\tchar unused;\n") // avoid empty struct
}
fmt.Fprintf(&buf, "\t}")
return buf.String(), off
}
func (p *Package) writeDefsFunc(fc, fgo2 *os.File, n *Name) {
name := n.Go
gtype := n.FuncType.Go
void := gtype.Results == nil || len(gtype.Results.List) == 0
if n.AddError {
// Add "error" to return type list.
// Type list is known to be 0 or 1 element - it's a C function.
err := &ast.Field{Type: ast.NewIdent("error")}
l := gtype.Results.List
if len(l) == 0 {
l = []*ast.Field{err}
} else {
l = []*ast.Field{l[0], err}
}
t := new(ast.FuncType)
*t = *gtype
t.Results = &ast.FieldList{List: l}
gtype = t
}
// Go func declaration.
d := &ast.FuncDecl{
Name: ast.NewIdent(n.Mangle),
Type: gtype,
}
// Builtins defined in the C prolog.
inProlog := name == "CString" || name == "GoString" || name == "GoStringN" || name == "GoBytes" || name == "_CMalloc"
if *gccgo {
// Gccgo style hooks.
fmt.Fprint(fgo2, "\n")
cname := fmt.Sprintf("_cgo%s%s", cPrefix, n.Mangle)
paramnames := []string(nil)
for i, param := range d.Type.Params.List {
paramName := fmt.Sprintf("p%d", i)
param.Names = []*ast.Ident{ast.NewIdent(paramName)}
paramnames = append(paramnames, paramName)
}
conf.Fprint(fgo2, fset, d)
fmt.Fprint(fgo2, " {\n")
if !inProlog {
fmt.Fprint(fgo2, "\tdefer syscall.CgocallDone()\n")
fmt.Fprint(fgo2, "\tsyscall.Cgocall()\n")
}
if n.AddError {
fmt.Fprint(fgo2, "\tsyscall.SetErrno(0)\n")
}
fmt.Fprint(fgo2, "\t")
if !void {
fmt.Fprint(fgo2, "r := ")
}
fmt.Fprintf(fgo2, "%s(%s)\n", cname, strings.Join(paramnames, ", "))
if n.AddError {
fmt.Fprint(fgo2, "\te := syscall.GetErrno()\n")
fmt.Fprint(fgo2, "\tif e != 0 {\n")
fmt.Fprint(fgo2, "\t\treturn ")
if !void {
fmt.Fprint(fgo2, "r, ")
}
fmt.Fprint(fgo2, "e\n")
fmt.Fprint(fgo2, "\t}\n")
fmt.Fprint(fgo2, "\treturn ")
if !void {
fmt.Fprint(fgo2, "r, ")
}
fmt.Fprint(fgo2, "nil\n")
} else if !void {
fmt.Fprint(fgo2, "\treturn r\n")
}
fmt.Fprint(fgo2, "}\n")
// declare the C function.
fmt.Fprintf(fgo2, "//extern _cgo%s%s\n", cPrefix, n.Mangle)
d.Name = ast.NewIdent(cname)
if n.AddError {
l := d.Type.Results.List
d.Type.Results.List = l[:len(l)-1]
}
conf.Fprint(fgo2, fset, d)
fmt.Fprint(fgo2, "\n")
return
}
conf.Fprint(fgo2, fset, d)
fmt.Fprint(fgo2, "\n")
if inProlog {
return
}
var argSize int64
_, argSize = p.structType(n)
// C wrapper calls into gcc, passing a pointer to the argument frame.
fmt.Fprintf(fc, "#pragma cgo_import_static _cgo%s%s\n", cPrefix, n.Mangle)
fmt.Fprintf(fc, "void _cgo%s%s(void*);\n", cPrefix, n.Mangle)
fmt.Fprintf(fc, "\n")
fmt.Fprintf(fc, "void\n")
if argSize == 0 {
argSize++
}
// TODO(rsc): The struct here should declare pointers only where
// there are pointers in the actual argument frame.
// This is a workaround for golang.org/issue/6397.
fmt.Fprintf(fc, "·%s(struct{", n.Mangle)
if n := argSize / p.PtrSize; n > 0 {
fmt.Fprintf(fc, "void *y[%d];", n)
}
if n := argSize % p.PtrSize; n > 0 {
fmt.Fprintf(fc, "uint8 x[%d];", n)
}
fmt.Fprintf(fc, "}p)\n")
fmt.Fprintf(fc, "{\n")
fmt.Fprintf(fc, "\truntime·cgocall(_cgo%s%s, &p);\n", cPrefix, n.Mangle)
if n.AddError {
// gcc leaves errno in first word of interface at end of p.
// check whether it is zero; if so, turn interface into nil.
// if not, turn interface into errno.
// Go init function initializes ·_Cerrno with an os.Errno
// for us to copy.
fmt.Fprintln(fc, ` {
int32 e;
void **v;
v = (void**)(&p+1) - 2; /* v = final two void* of p */
e = *(int32*)v;
v[0] = (void*)0xdeadbeef;
v[1] = (void*)0xdeadbeef;
if(e == 0) {
/* nil interface */
v[0] = 0;
v[1] = 0;
} else {
·_Cerrno(v, e); /* fill in v as error for errno e */
}
}`)
}
fmt.Fprintf(fc, "}\n")
fmt.Fprintf(fc, "\n")
}
// writeOutput creates stubs for a specific source file to be compiled by 6g
// (The comments here say 6g and 6c but the code applies to the 8 and 5 tools too.)
func (p *Package) writeOutput(f *File, srcfile string) {
base := srcfile
if strings.HasSuffix(base, ".go") {
base = base[0 : len(base)-3]
}
base = strings.Map(slashToUnderscore, base)
fgo1 := creat(*objDir + base + ".cgo1.go")
fgcc := creat(*objDir + base + ".cgo2.c")
p.GoFiles = append(p.GoFiles, base+".cgo1.go")
p.GccFiles = append(p.GccFiles, base+".cgo2.c")
// Write Go output: Go input with rewrites of C.xxx to _C_xxx.
fmt.Fprintf(fgo1, "// Created by cgo - DO NOT EDIT\n\n")
conf.Fprint(fgo1, fset, f.AST)
// While we process the vars and funcs, also write 6c and gcc output.
// Gcc output starts with the preamble.
fmt.Fprintf(fgcc, "%s\n", f.Preamble)
fmt.Fprintf(fgcc, "%s\n", gccProlog)
for _, key := range nameKeys(f.Name) {
n := f.Name[key]
if n.FuncType != nil {
p.writeOutputFunc(fgcc, n)
}
}
fgo1.Close()
fgcc.Close()
}
// fixGo converts the internal Name.Go field into the name we should show
// to users in error messages. There's only one for now: on input we rewrite
// C.malloc into C._CMalloc, so change it back here.
func fixGo(name string) string {
if name == "_CMalloc" {
return "malloc"
}
return name
}
var isBuiltin = map[string]bool{
"_Cfunc_CString": true,
"_Cfunc_GoString": true,
"_Cfunc_GoStringN": true,
"_Cfunc_GoBytes": true,
"_Cfunc__CMalloc": true,
}
func (p *Package) writeOutputFunc(fgcc *os.File, n *Name) {
name := n.Mangle
if isBuiltin[name] || p.Written[name] {
// The builtins are already defined in the C prolog, and we don't
// want to duplicate function definitions we've already done.
return
}
p.Written[name] = true
if *gccgo {
p.writeGccgoOutputFunc(fgcc, n)
return
}
ctype, _ := p.structType(n)
// Gcc wrapper unpacks the C argument struct
// and calls the actual C function.
fmt.Fprintf(fgcc, "void\n")
fmt.Fprintf(fgcc, "_cgo%s%s(void *v)\n", cPrefix, n.Mangle)
fmt.Fprintf(fgcc, "{\n")
if n.AddError {
fmt.Fprintf(fgcc, "\terrno = 0;\n")
}
// We're trying to write a gcc struct that matches 6c/8c/5c's layout.
// Use packed attribute to force no padding in this struct in case
// gcc has different packing requirements.
fmt.Fprintf(fgcc, "\t%s %v *a = v;\n", ctype, p.packedAttribute())
fmt.Fprintf(fgcc, "\t")
if t := n.FuncType.Result; t != nil {
fmt.Fprintf(fgcc, "a->r = ")
if c := t.C.String(); c[len(c)-1] == '*' {
fmt.Fprint(fgcc, "(__typeof__(a->r)) ")
}
}
fmt.Fprintf(fgcc, "%s(", n.C)
for i, t := 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")
if n.AddError {
fmt.Fprintf(fgcc, "\t*(int*)(a->e) = errno;\n")
}
fmt.Fprintf(fgcc, "}\n")
fmt.Fprintf(fgcc, "\n")
}
// Write out a wrapper for a function when using gccgo. This is a
// simple wrapper that just calls the real function. We only need a
// wrapper to support static functions in the prologue--without a
// wrapper, we can't refer to the function, since the reference is in
// a different file.
func (p *Package) writeGccgoOutputFunc(fgcc *os.File, n *Name) {
if t := n.FuncType.Result; t != nil {
fmt.Fprintf(fgcc, "%s\n", t.C.String())
} else {
fmt.Fprintf(fgcc, "void\n")
}
fmt.Fprintf(fgcc, "_cgo%s%s(", cPrefix, n.Mangle)
for i, t := range n.FuncType.Params {
if i > 0 {
fmt.Fprintf(fgcc, ", ")
}
c := t.Typedef
if c == "" {
c = t.C.String()
}
fmt.Fprintf(fgcc, "%s p%d", c, i)
}
fmt.Fprintf(fgcc, ")\n")
fmt.Fprintf(fgcc, "{\n")
fmt.Fprintf(fgcc, "\t")
if t := n.FuncType.Result; t != nil {
fmt.Fprintf(fgcc, "return ")
// 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, "%s(", n.C)
for i, t := 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")
fmt.Fprintf(fgcc, "}\n")
fmt.Fprintf(fgcc, "\n")
}
// packedAttribute returns host compiler struct attribute that will be
// used to match 6c/8c/5c's struct layout. For example, on 386 Windows,
// gcc wants to 8-align int64s, but 8c does not.
// Use __gcc_struct__ to work around http://gcc.gnu.org/PR52991 on x86,
// and http://golang.org/issue/5603.
func (p *Package) packedAttribute() string {
s := "__attribute__((__packed__"
if !strings.Contains(p.gccBaseCmd()[0], "clang") && (goarch == "amd64" || goarch == "386") {
s += ", __gcc_struct__"
}
return s + "))"
}
// Write out the various stubs we need to support functions exported
// from Go so that they are callable from C.
func (p *Package) writeExports(fgo2, fc, fm *os.File) {
fgcc := creat(*objDir + "_cgo_export.c")
fgcch := creat(*objDir + "_cgo_export.h")
fmt.Fprintf(fgcch, "/* Created by cgo - DO NOT EDIT. */\n")
fmt.Fprintf(fgcch, "%s\n", p.Preamble)
fmt.Fprintf(fgcch, "%s\n", p.gccExportHeaderProlog())
fmt.Fprintf(fgcc, "/* Created by cgo - DO NOT EDIT. */\n")
fmt.Fprintf(fgcc, "#include \"_cgo_export.h\"\n")
fmt.Fprintf(fgcc, "\nextern void crosscall2(void (*fn)(void *, int), void *, int);\n\n")
for _, exp := range p.ExpFunc {
fn := exp.Func
// Construct a gcc struct matching the 6c argument and
// result frame. The gcc struct will be compiled with
// __attribute__((packed)) so all padding must be accounted
// for explicitly.
ctype := "struct {\n"
off := int64(0)
npad := 0
if fn.Recv != nil {
t := p.cgoType(fn.Recv.List[0].Type)
ctype += fmt.Sprintf("\t\t%s recv;\n", t.C)
off += t.Size
}
fntype := fn.Type
forFieldList(fntype.Params,
func(i int, atype ast.Expr) {
t := p.cgoType(atype)
if off%t.Align != 0 {
pad := t.Align - off%t.Align
ctype += fmt.Sprintf("\t\tchar __pad%d[%d];\n", npad, pad)
off += pad
npad++
}
ctype += fmt.Sprintf("\t\t%s p%d;\n", t.C, i)
off += t.Size
})
if off%p.PtrSize != 0 {
pad := p.PtrSize - off%p.PtrSize
ctype += fmt.Sprintf("\t\tchar __pad%d[%d];\n", npad, pad)
off += pad
npad++
}
forFieldList(fntype.Results,
func(i int, atype ast.Expr) {
t := p.cgoType(atype)
if off%t.Align != 0 {
pad := t.Align - off%t.Align
ctype += fmt.Sprintf("\t\tchar __pad%d[%d];\n", npad, pad)
off += pad
npad++
}
ctype += fmt.Sprintf("\t\t%s r%d;\n", t.C, i)
off += t.Size
})
if off%p.PtrSize != 0 {
pad := p.PtrSize - off%p.PtrSize
ctype += fmt.Sprintf("\t\tchar __pad%d[%d];\n", npad, pad)
off += pad
npad++
}
if ctype == "struct {\n" {
ctype += "\t\tchar unused;\n" // avoid empty struct
}
ctype += "\t}"
// Get the return type of the wrapper function
// compiled by gcc.
gccResult := ""
if fntype.Results == nil || len(fntype.Results.List) == 0 {
gccResult = "void"
} else if len(fntype.Results.List) == 1 && len(fntype.Results.List[0].Names) <= 1 {
gccResult = p.cgoType(fntype.Results.List[0].Type).C.String()
} else {
fmt.Fprintf(fgcch, "\n/* Return type for %s */\n", exp.ExpName)
fmt.Fprintf(fgcch, "struct %s_return {\n", exp.ExpName)
forFieldList(fntype.Results,
func(i int, atype ast.Expr) {
fmt.Fprintf(fgcch, "\t%s r%d;\n", p.cgoType(atype).C, i)
})
fmt.Fprintf(fgcch, "};\n")
gccResult = "struct " + exp.ExpName + "_return"
}
// Build the wrapper function compiled by gcc.
s := fmt.Sprintf("%s %s(", gccResult, exp.ExpName)
if fn.Recv != nil {
s += p.cgoType(fn.Recv.List[0].Type).C.String()
s += " recv"
}
forFieldList(fntype.Params,
func(i int, atype ast.Expr) {
if i > 0 || fn.Recv != nil {
s += ", "
}
s += fmt.Sprintf("%s p%d", p.cgoType(atype).C, i)
})
s += ")"
fmt.Fprintf(fgcch, "\nextern %s;\n", s)
fmt.Fprintf(fgcc, "extern void _cgoexp%s_%s(void *, int);\n", cPrefix, exp.ExpName)
fmt.Fprintf(fgcc, "\n%s\n", s)
fmt.Fprintf(fgcc, "{\n")
fmt.Fprintf(fgcc, "\t%s %v a;\n", ctype, p.packedAttribute())
if gccResult != "void" && (len(fntype.Results.List) > 1 || len(fntype.Results.List[0].Names) > 1) {
fmt.Fprintf(fgcc, "\t%s r;\n", gccResult)
}
if fn.Recv != nil {
fmt.Fprintf(fgcc, "\ta.recv = recv;\n")
}
forFieldList(fntype.Params,
func(i int, atype ast.Expr) {
fmt.Fprintf(fgcc, "\ta.p%d = p%d;\n", i, i)
})
fmt.Fprintf(fgcc, "\tcrosscall2(_cgoexp%s_%s, &a, %d);\n", cPrefix, exp.ExpName, off)
if gccResult != "void" {
if len(fntype.Results.List) == 1 && len(fntype.Results.List[0].Names) <= 1 {
fmt.Fprintf(fgcc, "\treturn a.r0;\n")
} else {
forFieldList(fntype.Results,
func(i int, atype ast.Expr) {
fmt.Fprintf(fgcc, "\tr.r%d = a.r%d;\n", i, i)
})
fmt.Fprintf(fgcc, "\treturn r;\n")
}
}
fmt.Fprintf(fgcc, "}\n")
// Build the wrapper function compiled by 6c/8c
goname := exp.Func.Name.Name
if fn.Recv != nil {
goname = "_cgoexpwrap" + cPrefix + "_" + fn.Recv.List[0].Names[0].Name + "_" + goname
}
fmt.Fprintf(fc, "#pragma cgo_export_dynamic %s\n", goname)
fmt.Fprintf(fc, "extern void ·%s();\n\n", goname)
fmt.Fprintf(fc, "#pragma cgo_export_static _cgoexp%s_%s\n", cPrefix, exp.ExpName)
fmt.Fprintf(fc, "#pragma textflag 7\n") // no split stack, so no use of m or g
fmt.Fprintf(fc, "void\n")
fmt.Fprintf(fc, "_cgoexp%s_%s(void *a, int32 n)\n", cPrefix, exp.ExpName)
fmt.Fprintf(fc, "{\n")
fmt.Fprintf(fc, "\truntime·cgocallback(·%s, a, n);\n", goname)
fmt.Fprintf(fc, "}\n")
fmt.Fprintf(fm, "int _cgoexp%s_%s;\n", cPrefix, exp.ExpName)
// Calling a function with a receiver from C requires
// a Go wrapper function.
if fn.Recv != nil {
fmt.Fprintf(fgo2, "func %s(recv ", goname)
conf.Fprint(fgo2, fset, fn.Recv.List[0].Type)
forFieldList(fntype.Params,
func(i int, atype ast.Expr) {
fmt.Fprintf(fgo2, ", p%d ", i)
conf.Fprint(fgo2, fset, atype)
})
fmt.Fprintf(fgo2, ")")
if gccResult != "void" {
fmt.Fprint(fgo2, " (")
forFieldList(fntype.Results,
func(i int, atype ast.Expr) {
if i > 0 {
fmt.Fprint(fgo2, ", ")
}
conf.Fprint(fgo2, fset, atype)
})
fmt.Fprint(fgo2, ")")
}
fmt.Fprint(fgo2, " {\n")
fmt.Fprint(fgo2, "\t")
if gccResult != "void" {
fmt.Fprint(fgo2, "return ")
}
fmt.Fprintf(fgo2, "recv.%s(", exp.Func.Name)
forFieldList(fntype.Params,
func(i int, atype ast.Expr) {
if i > 0 {
fmt.Fprint(fgo2, ", ")
}
fmt.Fprintf(fgo2, "p%d", i)
})
fmt.Fprint(fgo2, ")\n")
fmt.Fprint(fgo2, "}\n")
}
}
}
// Write out the C header allowing C code to call exported gccgo functions.
func (p *Package) writeGccgoExports(fgo2, fc, fm *os.File) {
fgcc := creat(*objDir + "_cgo_export.c")
fgcch := creat(*objDir + "_cgo_export.h")
gccgoSymbolPrefix := p.gccgoSymbolPrefix()
fmt.Fprintf(fgcch, "/* Created by cgo - DO NOT EDIT. */\n")
fmt.Fprintf(fgcch, "%s\n", p.Preamble)
fmt.Fprintf(fgcch, "%s\n", p.gccExportHeaderProlog())
fmt.Fprintf(fgcc, "/* Created by cgo - DO NOT EDIT. */\n")
fmt.Fprintf(fgcc, "#include \"_cgo_export.h\"\n")
fmt.Fprintf(fm, "#include \"_cgo_export.h\"\n")
for _, exp := range p.ExpFunc {
fn := exp.Func
fntype := fn.Type
cdeclBuf := new(bytes.Buffer)
resultCount := 0
forFieldList(fntype.Results,
func(i int, atype ast.Expr) { resultCount++ })
switch resultCount {
case 0:
fmt.Fprintf(cdeclBuf, "void")
case 1:
forFieldList(fntype.Results,
func(i int, atype ast.Expr) {
t := p.cgoType(atype)
fmt.Fprintf(cdeclBuf, "%s", t.C)
})
default:
// Declare a result struct.
fmt.Fprintf(fgcch, "struct %s_result {\n", exp.ExpName)
forFieldList(fntype.Results,
func(i int, atype ast.Expr) {
t := p.cgoType(atype)
fmt.Fprintf(fgcch, "\t%s r%d;\n", t.C, i)
})
fmt.Fprintf(fgcch, "};\n")
fmt.Fprintf(cdeclBuf, "struct %s_result", exp.ExpName)
}
cRet := cdeclBuf.String()
cdeclBuf = new(bytes.Buffer)
fmt.Fprintf(cdeclBuf, "(")
if fn.Recv != nil {
fmt.Fprintf(cdeclBuf, "%s recv", p.cgoType(fn.Recv.List[0].Type).C.String())
}
// Function parameters.
forFieldList(fntype.Params,
func(i int, atype ast.Expr) {
if i > 0 || fn.Recv != nil {
fmt.Fprintf(cdeclBuf, ", ")
}
t := p.cgoType(atype)
fmt.Fprintf(cdeclBuf, "%s p%d", t.C, i)
})
fmt.Fprintf(cdeclBuf, ")")
cParams := cdeclBuf.String()
// We need to use a name that will be exported by the
// Go code; otherwise gccgo will make it static and we
// will not be able to link against it from the C
// code.
goName := "Cgoexp_" + exp.ExpName
fmt.Fprintf(fgcch, `extern %s %s %s __asm__("%s.%s");`, cRet, goName, cParams, gccgoSymbolPrefix, goName)
fmt.Fprint(fgcch, "\n")
// Use a #define so that the C code that includes
// cgo_export.h will be able to refer to the Go
// function using the expected name.
fmt.Fprintf(fgcch, "#define %s %s\n", exp.ExpName, goName)
// Use a #undef in _cgo_export.c so that we ignore the
// #define from cgo_export.h, since here we are
// defining the real function.
fmt.Fprintf(fgcc, "#undef %s\n", exp.ExpName)
fmt.Fprint(fgcc, "\n")
fmt.Fprintf(fgcc, "%s %s %s {\n", cRet, exp.ExpName, cParams)
fmt.Fprint(fgcc, "\t")
if resultCount > 0 {
fmt.Fprint(fgcc, "return ")
}
fmt.Fprintf(fgcc, "%s(", goName)
if fn.Recv != nil {
fmt.Fprint(fgcc, "recv")
}
forFieldList(fntype.Params,
func(i int, atype ast.Expr) {
if i > 0 || fn.Recv != nil {
fmt.Fprintf(fgcc, ", ")
}
fmt.Fprintf(fgcc, "p%d", i)
})
fmt.Fprint(fgcc, ");\n")
fmt.Fprint(fgcc, "}\n")
// Dummy declaration for _cgo_main.c
fmt.Fprintf(fm, "%s %s %s {}\n", cRet, goName, cParams)
// For gccgo we use a wrapper function in Go, in order
// to call CgocallBack and CgocallBackDone.
// This code uses printer.Fprint, not conf.Fprint,
// because we don't want //line comments in the middle
// of the function types.
fmt.Fprint(fgo2, "\n")
fmt.Fprintf(fgo2, "func %s(", goName)
if fn.Recv != nil {
fmt.Fprint(fgo2, "recv ")
printer.Fprint(fgo2, fset, fn.Recv.List[0].Type)
}
forFieldList(fntype.Params,
func(i int, atype ast.Expr) {
if i > 0 || fn.Recv != nil {
fmt.Fprintf(fgo2, ", ")
}
fmt.Fprintf(fgo2, "p%d ", i)
printer.Fprint(fgo2, fset, atype)
})
fmt.Fprintf(fgo2, ")")
if resultCount > 0 {
fmt.Fprintf(fgo2, " (")
forFieldList(fntype.Results,
func(i int, atype ast.Expr) {
if i > 0 {
fmt.Fprint(fgo2, ", ")
}
printer.Fprint(fgo2, fset, atype)
})
fmt.Fprint(fgo2, ")")
}
fmt.Fprint(fgo2, " {\n")
fmt.Fprint(fgo2, "\tsyscall.CgocallBack()\n")
fmt.Fprint(fgo2, "\tdefer syscall.CgocallBackDone()\n")
fmt.Fprint(fgo2, "\t")
if resultCount > 0 {
fmt.Fprint(fgo2, "return ")
}
if fn.Recv != nil {
fmt.Fprint(fgo2, "recv.")
}
fmt.Fprintf(fgo2, "%s(", exp.Func.Name)
forFieldList(fntype.Params,
func(i int, atype ast.Expr) {
if i > 0 {
fmt.Fprint(fgo2, ", ")
}
fmt.Fprintf(fgo2, "p%d", i)
})
fmt.Fprint(fgo2, ")\n")
fmt.Fprint(fgo2, "}\n")
}
}
// Return the package prefix when using gccgo.
func (p *Package) gccgoSymbolPrefix() string {
if !*gccgo {
return ""
}
clean := func(r rune) rune {
switch {
case 'A' <= r && r <= 'Z', 'a' <= r && r <= 'z',
'0' <= r && r <= '9':
return r
}
return '_'
}
if *gccgopkgpath != "" {
return strings.Map(clean, *gccgopkgpath)
}
if *gccgoprefix == "" && p.PackageName == "main" {
return "main"
}
prefix := strings.Map(clean, *gccgoprefix)
if prefix == "" {
prefix = "go"
}
return prefix + "." + p.PackageName
}
// Call a function for each entry in an ast.FieldList, passing the
// index into the list and the type.
func forFieldList(fl *ast.FieldList, fn func(int, ast.Expr)) {
if fl == nil {
return
}
i := 0
for _, r := range fl.List {
if r.Names == nil {
fn(i, r.Type)
i++
} else {
for _ = range r.Names {
fn(i, r.Type)
i++
}
}
}
}
func c(repr string, args ...interface{}) *TypeRepr {
return &TypeRepr{repr, args}
}
// Map predeclared Go types to Type.
var goTypes = map[string]*Type{
"bool": {Size: 1, Align: 1, C: c("GoUint8")},
"byte": {Size: 1, Align: 1, C: c("GoUint8")},
"int": {Size: 0, Align: 0, C: c("GoInt")},
"uint": {Size: 0, Align: 0, C: c("GoUint")},
"rune": {Size: 4, Align: 4, C: c("GoInt32")},
"int8": {Size: 1, Align: 1, C: c("GoInt8")},
"uint8": {Size: 1, Align: 1, C: c("GoUint8")},
"int16": {Size: 2, Align: 2, C: c("GoInt16")},
"uint16": {Size: 2, Align: 2, C: c("GoUint16")},
"int32": {Size: 4, Align: 4, C: c("GoInt32")},
"uint32": {Size: 4, Align: 4, C: c("GoUint32")},
"int64": {Size: 8, Align: 8, C: c("GoInt64")},
"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")},
}
// Map an ast type to a Type.
func (p *Package) cgoType(e ast.Expr) *Type {
switch t := e.(type) {
case *ast.StarExpr:
x := p.cgoType(t.X)
return &Type{Size: p.PtrSize, Align: p.PtrSize, C: c("%s*", x.C)}
case *ast.ArrayType:
if t.Len == nil {
// Slice: pointer, len, cap.
return &Type{Size: p.PtrSize * 3, Align: p.PtrSize, C: c("GoSlice")}
}
case *ast.StructType:
// TODO
case *ast.FuncType:
return &Type{Size: p.PtrSize, Align: p.PtrSize, C: c("void*")}
case *ast.InterfaceType:
return &Type{Size: 2 * p.PtrSize, Align: p.PtrSize, C: c("GoInterface")}
case *ast.MapType:
return &Type{Size: p.PtrSize, Align: p.PtrSize, C: c("GoMap")}
case *ast.ChanType:
return &Type{Size: p.PtrSize, Align: p.PtrSize, C: c("GoChan")}
case *ast.Ident:
// Look up the type in the top level declarations.
// TODO: Handle types defined within a function.
for _, d := range p.Decl {
gd, ok := d.(*ast.GenDecl)
if !ok || gd.Tok != token.TYPE {
continue
}
for _, spec := range gd.Specs {
ts, ok := spec.(*ast.TypeSpec)
if !ok {
continue
}
if ts.Name.Name == t.Name {
return p.cgoType(ts.Type)
}
}
}
if def := typedef[t.Name]; def != nil {
return def
}
if t.Name == "uintptr" {
return &Type{Size: p.PtrSize, Align: p.PtrSize, C: c("GoUintptr")}
}
if t.Name == "string" {
// The string data is 1 pointer + 1 (pointer-sized) int.
return &Type{Size: 2 * p.PtrSize, Align: p.PtrSize, C: c("GoString")}
}
if t.Name == "error" {
return &Type{Size: 2 * p.PtrSize, Align: p.PtrSize, C: c("GoInterface")}
}
if r, ok := goTypes[t.Name]; ok {
if r.Size == 0 { // int or uint
rr := new(Type)
*rr = *r
rr.Size = p.IntSize
rr.Align = p.IntSize
r = rr
}
if r.Align > p.PtrSize {
r.Align = p.PtrSize
}
return r
}
error_(e.Pos(), "unrecognized Go type %s", t.Name)
return &Type{Size: 4, Align: 4, C: c("int")}
case *ast.SelectorExpr:
id, ok := t.X.(*ast.Ident)
if ok && id.Name == "unsafe" && t.Sel.Name == "Pointer" {
return &Type{Size: p.PtrSize, Align: p.PtrSize, C: c("void*")}
}
}
error_(e.Pos(), "Go type not supported in export: %s", gofmt(e))
return &Type{Size: 4, Align: 4, C: c("int")}
}
const gccProlog = `
// Usual nonsense: if x and y are not equal, the type will be invalid
// (have a negative array count) and an inscrutable error will come
// out of the compiler and hopefully mention "name".
#define __cgo_compile_assert_eq(x, y, name) typedef char name[(x-y)*(x-y)*-2+1];
// Check at compile time that the sizes we use match our expectations.
#define __cgo_size_assert(t, n) __cgo_compile_assert_eq(sizeof(t), n, _cgo_sizeof_##t##_is_not_##n)
__cgo_size_assert(char, 1)
__cgo_size_assert(short, 2)
__cgo_size_assert(int, 4)
typedef long long __cgo_long_long;
__cgo_size_assert(__cgo_long_long, 8)
__cgo_size_assert(float, 4)
__cgo_size_assert(double, 8)
#include <errno.h>
#include <string.h>
`
const builtinProlog = `
#include <sys/types.h> /* for size_t below */
/* Define intgo when compiling with GCC. */
#ifdef __PTRDIFF_TYPE__
typedef __PTRDIFF_TYPE__ intgo;
#elif defined(_LP64)
typedef long long intgo;
#else
typedef int intgo;
#endif
typedef struct { char *p; intgo n; } _GoString_;
typedef struct { char *p; intgo n; intgo c; } _GoBytes_;
_GoString_ GoString(char *p);
_GoString_ GoStringN(char *p, int l);
_GoBytes_ GoBytes(void *p, int n);
char *CString(_GoString_);
void *_CMalloc(size_t);
`
const cProlog = `
#include "runtime.h"
#include "cgocall.h"
void ·_Cerrno(void*, int32);
void
·_Cfunc_GoString(int8 *p, String s)
{
s = runtime·gostring((byte*)p);
FLUSH(&s);
}
void
·_Cfunc_GoStringN(int8 *p, int32 l, String s)
{
s = runtime·gostringn((byte*)p, l);
FLUSH(&s);
}
void
·_Cfunc_GoBytes(int8 *p, int32 l, Slice s)
{
s = runtime·gobytes((byte*)p, l);
FLUSH(&s);
}
void
·_Cfunc_CString(String s, int8 *p)
{
p = runtime·cmalloc(s.len+1);
runtime·memmove((byte*)p, s.str, s.len);
p[s.len] = 0;
FLUSH(&p);
}
void
·_Cfunc__CMalloc(uintptr n, int8 *p)
{
p = runtime·cmalloc(n);
FLUSH(&p);
}
`
func (p *Package) cPrologGccgo() string {
return strings.Replace(cPrologGccgo, "PREFIX", cPrefix, -1)
}
const cPrologGccgo = `
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
typedef unsigned char byte;
typedef intptr_t intgo;
struct __go_string {
const unsigned char *__data;
intgo __length;
};
typedef struct __go_open_array {
void* __values;
intgo __count;
intgo __capacity;
} Slice;
struct __go_string __go_byte_array_to_string(const void* p, intgo len);
struct __go_open_array __go_string_to_byte_array (struct __go_string str);
const char *_cgoPREFIX_Cfunc_CString(struct __go_string s) {
char *p = malloc(s.__length+1);
memmove(p, s.__data, s.__length);
p[s.__length] = 0;
return p;
}
struct __go_string _cgoPREFIX_Cfunc_GoString(char *p) {
intgo len = (p != NULL) ? strlen(p) : 0;
return __go_byte_array_to_string(p, len);
}
struct __go_string _cgoPREFIX_Cfunc_GoStringN(char *p, int32_t n) {
return __go_byte_array_to_string(p, n);
}
Slice _cgoPREFIX_Cfunc_GoBytes(char *p, int32_t n) {
struct __go_string s = { (const unsigned char *)p, n };
return __go_string_to_byte_array(s);
}
extern void runtime_throw(const char *);
void *_cgoPREFIX_Cfunc__CMalloc(size_t n) {
void *p = malloc(n);
if(p == NULL && n == 0)
p = malloc(1);
if(p == NULL)
runtime_throw("runtime: C malloc failed");
return p;
}
`
func (p *Package) gccExportHeaderProlog() string {
return strings.Replace(gccExportHeaderProlog, "GOINTBITS", fmt.Sprint(8*p.IntSize), -1)
}
const gccExportHeaderProlog = `
typedef signed char GoInt8;
typedef unsigned char GoUint8;
typedef short GoInt16;
typedef unsigned short GoUint16;
typedef int GoInt32;
typedef unsigned int GoUint32;
typedef long long GoInt64;
typedef unsigned long long GoUint64;
typedef GoIntGOINTBITS GoInt;
typedef GoUintGOINTBITS GoUint;
typedef __SIZE_TYPE__ GoUintptr;
typedef float GoFloat32;
typedef double GoFloat64;
typedef __complex float GoComplex64;
typedef __complex double GoComplex128;
typedef struct { char *p; GoInt n; } GoString;
typedef void *GoMap;
typedef void *GoChan;
typedef struct { void *t; void *v; } GoInterface;
typedef struct { void *data; GoInt len; GoInt cap; } GoSlice;
`
// Copyright 2009 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"
"go/token"
"os"
"os/exec"
)
// run runs the command argv, feeding in stdin on standard input.
// It returns the output to standard output and standard error.
// ok indicates whether the command exited successfully.
func run(stdin []byte, argv []string) (stdout, stderr []byte, ok bool) {
p := exec.Command(argv[0], argv[1:]...)
p.Stdin = bytes.NewReader(stdin)
var bout, berr bytes.Buffer
p.Stdout = &bout
p.Stderr = &berr
err := p.Run()
if _, ok := err.(*exec.ExitError); err != nil && !ok {
fatalf("%s", err)
}
ok = p.ProcessState.Success()
stdout, stderr = bout.Bytes(), berr.Bytes()
return
}
func lineno(pos token.Pos) string {
return fset.Position(pos).String()
}
// Die with an error message.
func fatalf(msg string, args ...interface{}) {
// If we've already printed other errors, they might have
// caused the fatal condition. Assume they're enough.
if nerrors == 0 {
fmt.Fprintf(os.Stderr, msg+"\n", args...)
}
os.Exit(2)
}
var nerrors int
func error_(pos token.Pos, msg string, args ...interface{}) {
nerrors++
if pos.IsValid() {
fmt.Fprintf(os.Stderr, "%s: ", fset.Position(pos).String())
}
fmt.Fprintf(os.Stderr, msg, args...)
fmt.Fprintf(os.Stderr, "\n")
}
// isName returns true if s is a valid C identifier
func isName(s string) bool {
for i, v := range s {
if v != '_' && (v < 'A' || v > 'Z') && (v < 'a' || v > 'z') && (v < '0' || v > '9') {
return false
}
if i == 0 && '0' <= v && v <= '9' {
return false
}
}
return s != ""
}
func creat(name string) *os.File {
f, err := os.Create(name)
if err != nil {
fatalf("%s", err)
}
return f
}
func slashToUnderscore(c rune) rune {
if c == '/' || c == '\\' || c == ':' {
c = '_'
}
return c
}
// Copyright 2012 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 cmd_go_bootstrap
// This code is compiled only into the bootstrap 'go' binary.
// These stubs avoid importing packages with large dependency
// trees, like the use of "net/http" in vcs.go.
package main
import (
"errors"
"io"
)
var errHTTP = errors.New("no http in bootstrap go command")
func httpGET(url string) ([]byte, error) {
return nil, errHTTP
}
func httpsOrHTTP(importPath string) (string, io.ReadCloser, error) {
return "", nil, errHTTP
}
func parseMetaGoImports(r io.Reader) ([]metaImport, error) {
panic("unreachable")
}
// Copyright 2011 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 (
"bufio"
"bytes"
"container/heap"
"errors"
"flag"
"fmt"
"go/build"
"io"
"io/ioutil"
"log"
"os"
"os/exec"
"path"
"path/filepath"
"regexp"
"runtime"
"strconv"
"strings"
"sync"
"time"
)
var cmdBuild = &Command{
UsageLine: "build [-o output] [-i] [build flags] [packages]",
Short: "compile packages and dependencies",
Long: `
Build compiles the packages named by the import paths,
along with their dependencies, but it does not install the results.
If the arguments are a list of .go files, build treats them as a list
of source files specifying a single package.
When the command line specifies a single main package,
build writes the resulting executable to output.
Otherwise build compiles the packages but discards the results,
serving only as a check that the packages can be built.
The -o flag specifies the output file name. If not specified, the
output file name depends on the arguments and derives from the name
of the package, such as p.a for package p, unless p is 'main'. If
the package is main and file names are provided, the file name
derives from the first file name mentioned, such as f1 for 'go build
f1.go f2.go'; with no files provided ('go build'), the output file
name is the base name of the containing directory.
The -i flag installs the packages that are dependencies of the target.
The build flags are shared by the build, clean, get, install, list, run,
and test commands:
-a
force rebuilding of packages that are already up-to-date.
-n
print the commands but do not run them.
-p n
the number of builds that can be run in parallel.
The default is the number of CPUs available.
-race
enable data race detection.
Supported only on linux/amd64, darwin/amd64 and windows/amd64.
-v
print the names of packages as they are compiled.
-work
print the name of the temporary work directory and
do not delete it when exiting.
-x
print the commands.
-ccflags 'arg list'
arguments to pass on each 5c, 6c, or 8c compiler invocation.
-compiler name
name of compiler to use, as in runtime.Compiler (gccgo or gc).
-gccgoflags 'arg list'
arguments to pass on each gccgo compiler/linker invocation.
-gcflags 'arg list'
arguments to pass on each 5g, 6g, or 8g compiler invocation.
-installsuffix suffix
a suffix to use in the name of the package installation directory,
in order to keep output separate from default builds.
If using the -race flag, the install suffix is automatically set to race
or, if set explicitly, has _race appended to it.
-ldflags 'flag list'
arguments to pass on each 5l, 6l, or 8l linker invocation.
-tags 'tag list'
a list of build tags to consider satisfied during the build.
For more information about build tags, see the description of
build constraints in the documentation for the go/build package.
The list flags accept a space-separated list of strings. To embed spaces
in an element in the list, surround it with either single or double quotes.
For more about specifying packages, see 'go help packages'.
For more about where packages and binaries are installed,
run 'go help gopath'. For more about calling between Go and C/C++,
run 'go help c'.
See also: go install, go get, go clean.
`,
}
func init() {
// break init cycle
cmdBuild.Run = runBuild
cmdInstall.Run = runInstall
cmdBuild.Flag.BoolVar(&buildI, "i", false, "")
addBuildFlags(cmdBuild)
addBuildFlags(cmdInstall)
}
// Flags set by multiple commands.
var buildA bool // -a flag
var buildN bool // -n flag
var buildP = runtime.NumCPU() // -p flag
var buildV bool // -v flag
var buildX bool // -x flag
var buildI bool // -i flag
var buildO = cmdBuild.Flag.String("o", "", "output file")
var buildWork bool // -work flag
var buildGcflags []string // -gcflags flag
var buildCcflags []string // -ccflags flag
var buildLdflags []string // -ldflags flag
var buildGccgoflags []string // -gccgoflags flag
var buildRace bool // -race flag
var reqPkgSrc bool // req src for Imports
var buildContext = build.Default
var buildToolchain toolchain = noToolchain{}
// buildCompiler implements flag.Var.
// It implements Set by updating both
// buildToolchain and buildContext.Compiler.
type buildCompiler struct{}
func (c buildCompiler) Set(value string) error {
switch value {
case "gc":
buildToolchain = gcToolchain{}
case "gccgo":
buildToolchain = gccgoToolchain{}
default:
return fmt.Errorf("unknown compiler %q", value)
}
buildContext.Compiler = value
return nil
}
func (c buildCompiler) String() string {
return buildContext.Compiler
}
func init() {
switch build.Default.Compiler {
case "gc":
buildToolchain = gcToolchain{}
case "gccgo":
buildToolchain = gccgoToolchain{}
}
}
// addBuildFlags adds the flags common to the build, clean, get,
// install, list, run, and test commands.
func addBuildFlags(cmd *Command) {
// NOTE: If you add flags here, also add them to testflag.go.
cmd.Flag.BoolVar(&buildA, "a", false, "")
cmd.Flag.BoolVar(&buildN, "n", false, "")
cmd.Flag.IntVar(&buildP, "p", buildP, "")
cmd.Flag.StringVar(&buildContext.InstallSuffix, "installsuffix", "", "")
cmd.Flag.BoolVar(&buildV, "v", false, "")
cmd.Flag.BoolVar(&buildX, "x", false, "")
cmd.Flag.BoolVar(&buildWork, "work", false, "")
cmd.Flag.Var((*stringsFlag)(&buildGcflags), "gcflags", "")
cmd.Flag.Var((*stringsFlag)(&buildCcflags), "ccflags", "")
cmd.Flag.Var((*stringsFlag)(&buildLdflags), "ldflags", "")
cmd.Flag.Var((*stringsFlag)(&buildGccgoflags), "gccgoflags", "")
cmd.Flag.Var((*stringsFlag)(&buildContext.BuildTags), "tags", "")
cmd.Flag.Var(buildCompiler{}, "compiler", "")
cmd.Flag.BoolVar(&buildRace, "race", false, "")
switch build.Default.Compiler {
case "gc":
reqPkgSrc = true
case "gccgo":
reqPkgSrc = false
}
}
func addBuildFlagsNX(cmd *Command) {
cmd.Flag.BoolVar(&buildN, "n", false, "")
cmd.Flag.BoolVar(&buildX, "x", false, "")
}
func isSpaceByte(c byte) bool {
return c == ' ' || c == '\t' || c == '\n' || c == '\r'
}
// fileExtSplit expects a filename and returns the name
// and ext (without the dot). If the file has no
// extension, ext will be empty.
func fileExtSplit(file string) (name, ext string) {
dotExt := filepath.Ext(file)
name = file[:len(file)-len(dotExt)]
if dotExt != "" {
ext = dotExt[1:]
}
return
}
type stringsFlag []string
func (v *stringsFlag) Set(s string) error {
var err error
*v, err = splitQuotedFields(s)
if *v == nil {
*v = []string{}
}
return err
}
func splitQuotedFields(s string) ([]string, error) {
// Split fields allowing '' or "" around elements.
// Quotes further inside the string do not count.
var f []string
for len(s) > 0 {
for len(s) > 0 && isSpaceByte(s[0]) {
s = s[1:]
}
if len(s) == 0 {
break
}
// Accepted quoted string. No unescaping inside.
if s[0] == '"' || s[0] == '\'' {
quote := s[0]
s = s[1:]
i := 0
for i < len(s) && s[i] != quote {
i++
}
if i >= len(s) {
return nil, fmt.Errorf("unterminated %c string", quote)
}
f = append(f, s[:i])
s = s[i+1:]
continue
}
i := 0
for i < len(s) && !isSpaceByte(s[i]) {
i++
}
f = append(f, s[:i])
s = s[i:]
}
return f, nil
}
func (v *stringsFlag) String() string {
return "<stringsFlag>"
}
func runBuild(cmd *Command, args []string) {
raceInit()
var b builder
b.init()
pkgs := packagesForBuild(args)
if len(pkgs) == 1 && pkgs[0].Name == "main" && *buildO == "" {
_, *buildO = path.Split(pkgs[0].ImportPath)
*buildO += exeSuffix
}
// sanity check some often mis-used options
switch buildContext.Compiler {
case "gccgo":
if len(buildGcflags) != 0 {
fmt.Println("go build: when using gccgo toolchain, please pass compiler flags using -gccgoflags, not -gcflags")
}
if len(buildLdflags) != 0 {
fmt.Println("go build: when using gccgo toolchain, please pass linker flags using -gccgoflags, not -ldflags")
}
case "gc":
if len(buildGccgoflags) != 0 {
fmt.Println("go build: when using gc toolchain, please pass compile flags using -gcflags, and linker flags using -ldflags")
}
}
if *buildO != "" {
if len(pkgs) > 1 {
fatalf("go build: cannot use -o with multiple packages")
}
p := pkgs[0]
p.target = "" // must build - not up to date
a := b.action(modeInstall, modeBuild, p)
a.target = *buildO
b.do(a)
return
}
a := &action{}
depMode := modeBuild
if buildI {
depMode = modeInstall
}
for _, p := range packages(args) {
a.deps = append(a.deps, b.action(modeBuild, depMode, p))
}
b.do(a)
}
var cmdInstall = &Command{
UsageLine: "install [build flags] [packages]",
Short: "compile and install packages and dependencies",
Long: `
Install compiles and installs the packages named by the import paths,
along with their dependencies.
For more about the build flags, see 'go help build'.
For more about specifying packages, see 'go help packages'.
See also: go build, go get, go clean.
`,
}
func runInstall(cmd *Command, args []string) {
raceInit()
pkgs := packagesForBuild(args)
for _, p := range pkgs {
if p.Target == "" && (!p.Standard || p.ImportPath != "unsafe") {
if p.cmdline {
errorf("go install: no install location for .go files listed on command line (GOBIN not set)")
} else if p.ConflictDir != "" {
errorf("go install: no install location for %s: hidden by %s", p.Dir, p.ConflictDir)
} else {
errorf("go install: no install location for directory %s outside GOPATH", p.Dir)
}
}
}
exitIfErrors()
var b builder
b.init()
a := &action{}
for _, p := range pkgs {
a.deps = append(a.deps, b.action(modeInstall, modeInstall, p))
}
b.do(a)
}
// Global build parameters (used during package load)
var (
goarch string
goos string
archChar string
exeSuffix string
)
func init() {
goarch = buildContext.GOARCH
goos = buildContext.GOOS
if goos == "windows" {
exeSuffix = ".exe"
}
var err error
archChar, err = build.ArchChar(goarch)
if err != nil {
if _, isgc := buildToolchain.(gcToolchain); isgc {
fatalf("%s", err)
}
// archChar is only required for gcToolchain, if we're using
// another toolchain leave it blank.
archChar = ""
}
}
// A builder holds global state about a build.
// It does not hold per-package state, because we
// build packages in parallel, and the builder is shared.
type builder struct {
work string // the temporary work directory (ends in filepath.Separator)
actionCache map[cacheKey]*action // a cache of already-constructed actions
mkdirCache map[string]bool // a cache of created directories
print func(args ...interface{}) (int, error)
output sync.Mutex
scriptDir string // current directory in printed script
exec sync.Mutex
readySema chan bool
ready actionQueue
}
// An action represents a single action in the action graph.
type action struct {
p *Package // the package this action works on
deps []*action // actions that must happen before this one
triggers []*action // inverse of deps
cgo *action // action for cgo binary if needed
args []string // additional args for runProgram
testOutput *bytes.Buffer // test output buffer
f func(*builder, *action) error // the action itself (nil = no-op)
ignoreFail bool // whether to run f even if dependencies fail
// Generated files, directories.
link bool // target is executable, not just package
pkgdir string // the -I or -L argument to use when importing this package
objdir string // directory for intermediate objects
objpkg string // the intermediate package .a file created during the action
target string // goal of the action: the created package or executable
// Execution state.
pending int // number of deps yet to complete
priority int // relative execution priority
failed bool // whether the action failed
}
// cacheKey is the key for the action cache.
type cacheKey struct {
mode buildMode
p *Package
}
// buildMode specifies the build mode:
// are we just building things or also installing the results?
type buildMode int
const (
modeBuild buildMode = iota
modeInstall
)
var (
goroot = filepath.Clean(runtime.GOROOT())
gobin = os.Getenv("GOBIN")
gorootBin = filepath.Join(goroot, "bin")
gorootSrcPkg = filepath.Join(goroot, "src/pkg")
gorootPkg = filepath.Join(goroot, "pkg")
gorootSrc = filepath.Join(goroot, "src")
)
func (b *builder) init() {
var err error
b.print = func(a ...interface{}) (int, error) {
return fmt.Fprint(os.Stderr, a...)
}
b.actionCache = make(map[cacheKey]*action)
b.mkdirCache = make(map[string]bool)
if buildN {
b.work = "$WORK"
} else {
b.work, err = ioutil.TempDir("", "go-build")
if err != nil {
fatalf("%s", err)
}
if buildX || buildWork {
fmt.Fprintf(os.Stderr, "WORK=%s\n", b.work)
}
if !buildWork {
workdir := b.work
atexit(func() { os.RemoveAll(workdir) })
}
}
}
// goFilesPackage creates a package for building a collection of Go files
// (typically named on the command line). The target is named p.a for
// package p or named after the first Go file for package main.
func goFilesPackage(gofiles []string) *Package {
// TODO: Remove this restriction.
for _, f := range gofiles {
if !strings.HasSuffix(f, ".go") {
fatalf("named files must be .go files")
}
}
var stk importStack
ctxt := buildContext
ctxt.UseAllFiles = true
// Synthesize fake "directory" that only shows the named files,
// to make it look like this is a standard package or
// command directory. So that local imports resolve
// consistently, the files must all be in the same directory.
var dirent []os.FileInfo
var dir string
for _, file := range gofiles {
fi, err := os.Stat(file)
if err != nil {
fatalf("%s", err)
}
if fi.IsDir() {
fatalf("%s is a directory, should be a Go file", file)
}
dir1, _ := filepath.Split(file)
if dir == "" {
dir = dir1
} else if dir != dir1 {
fatalf("named files must all be in one directory; have %s and %s", dir, dir1)
}
dirent = append(dirent, fi)
}
ctxt.ReadDir = func(string) ([]os.FileInfo, error) { return dirent, nil }
if !filepath.IsAbs(dir) {
dir = filepath.Join(cwd, dir)
}
bp, err := ctxt.ImportDir(dir, 0)
pkg := new(Package)
pkg.local = true
pkg.cmdline = true
pkg.load(&stk, bp, err)
pkg.localPrefix = dirToImportPath(dir)
pkg.ImportPath = "command-line-arguments"
pkg.target = ""
if pkg.Name == "main" {
_, elem := filepath.Split(gofiles[0])
exe := elem[:len(elem)-len(".go")] + exeSuffix
if *buildO == "" {
*buildO = exe
}
if gobin != "" {
pkg.target = filepath.Join(gobin, exe)
}
} else {
if *buildO == "" {
*buildO = pkg.Name + ".a"
}
}
pkg.Target = pkg.target
pkg.Stale = true
computeStale(pkg)
return pkg
}
// action returns the action for applying the given operation (mode) to the package.
// depMode is the action to use when building dependencies.
func (b *builder) action(mode buildMode, depMode buildMode, p *Package) *action {
key := cacheKey{mode, p}
a := b.actionCache[key]
if a != nil {
return a
}
a = &action{p: p, pkgdir: p.build.PkgRoot}
if p.pkgdir != "" { // overrides p.t
a.pkgdir = p.pkgdir
}
b.actionCache[key] = a
for _, p1 := range p.imports {
a.deps = append(a.deps, b.action(depMode, depMode, p1))
}
// If we are not doing a cross-build, then record the binary we'll
// generate for cgo as a dependency of the build of any package
// using cgo, to make sure we do not overwrite the binary while
// a package is using it. If this is a cross-build, then the cgo we
// are writing is not the cgo we need to use.
if goos == runtime.GOOS && goarch == runtime.GOARCH && !buildRace {
if reqPkgSrc {
if len(p.CgoFiles) > 0 || p.Standard && p.ImportPath == "runtime/cgo" {
var stk importStack
p1 := loadPackage("cmd/cgo", &stk)
if p1.Error != nil {
fatalf("load cmd/cgo: %v", p1.Error)
}
a.cgo = b.action(depMode, depMode, p1)
a.deps = append(a.deps, a.cgo)
}
}
}
if p.Standard {
switch p.ImportPath {
case "builtin", "unsafe":
// Fake packages - nothing to build.
return a
}
// gccgo standard library is "fake" too.
if _, ok := buildToolchain.(gccgoToolchain); ok {
// the target name is needed for cgo.
a.target = p.target
return a
}
}
if !p.Stale && p.target != "" {
// p.Stale==false implies that p.target is up-to-date.
// Record target name for use by actions depending on this one.
a.target = p.target
return a
}
if p.local && p.target == "" {
// Imported via local path. No permanent target.
mode = modeBuild
}
work := p.pkgdir
if work == "" {
work = b.work
}
a.objdir = filepath.Join(work, a.p.ImportPath, "_obj") + string(filepath.Separator)
a.objpkg = buildToolchain.pkgpath(work, a.p)
a.link = p.Name == "main"
switch mode {
case modeInstall:
a.f = (*builder).install
a.deps = []*action{b.action(modeBuild, depMode, p)}
a.target = a.p.target
case modeBuild:
a.f = (*builder).build
a.target = a.objpkg
if a.link {
// An executable file. (This is the name of a temporary file.)
// Because we run the temporary file in 'go run' and 'go test',
// the name will show up in ps listings. If the caller has specified
// a name, use that instead of a.out. The binary is generated
// in an otherwise empty subdirectory named exe to avoid
// naming conflicts. The only possible conflict is if we were
// to create a top-level package named exe.
name := "a.out"
if p.exeName != "" {
name = p.exeName
}
a.target = a.objdir + filepath.Join("exe", name) + exeSuffix
}
}
return a
}
// actionList returns the list of actions in the dag rooted at root
// as visited in a depth-first post-order traversal.
func actionList(root *action) []*action {
seen := map[*action]bool{}
all := []*action{}
var walk func(*action)
walk = func(a *action) {
if seen[a] {
return
}
seen[a] = true
for _, a1 := range a.deps {
walk(a1)
}
all = append(all, a)
}
walk(root)
return all
}
// do runs the action graph rooted at root.
func (b *builder) do(root *action) {
// Build list of all actions, assigning depth-first post-order priority.
// The original implementation here was a true queue
// (using a channel) but it had the effect of getting
// distracted by low-level leaf actions to the detriment
// of completing higher-level actions. The order of
// work does not matter much to overall execution time,
// but when running "go test std" it is nice to see each test
// results as soon as possible. The priorities assigned
// ensure that, all else being equal, the execution prefers
// to do what it would have done first in a simple depth-first
// dependency order traversal.
all := actionList(root)
for i, a := range all {
a.priority = i
}
b.readySema = make(chan bool, len(all))
// Initialize per-action execution state.
for _, a := range all {
for _, a1 := range a.deps {
a1.triggers = append(a1.triggers, a)
}
a.pending = len(a.deps)
if a.pending == 0 {
b.ready.push(a)
b.readySema <- true
}
}
// Handle runs a single action and takes care of triggering
// any actions that are runnable as a result.
handle := func(a *action) {
var err error
if a.f != nil && (!a.failed || a.ignoreFail) {
err = a.f(b, a)
}
// The actions run in parallel but all the updates to the
// shared work state are serialized through b.exec.
b.exec.Lock()
defer b.exec.Unlock()
if err != nil {
if err == errPrintedOutput {
setExitStatus(2)
} else {
errorf("%s", err)
}
a.failed = true
}
for _, a0 := range a.triggers {
if a.failed {
a0.failed = true
}
if a0.pending--; a0.pending == 0 {
b.ready.push(a0)
b.readySema <- true
}
}
if a == root {
close(b.readySema)
}
}
var wg sync.WaitGroup
// Kick off goroutines according to parallelism.
// If we are using the -n flag (just printing commands)
// drop the parallelism to 1, both to make the output
// deterministic and because there is no real work anyway.
par := buildP
if buildN {
par = 1
}
for i := 0; i < par; i++ {
wg.Add(1)
go func() {
defer wg.Done()
for {
select {
case _, ok := <-b.readySema:
if !ok {
return
}
// Receiving a value from b.readySema entitles
// us to take from the ready queue.
b.exec.Lock()
a := b.ready.pop()
b.exec.Unlock()
handle(a)
case <-interrupted:
setExitStatus(1)
return
}
}
}()
}
wg.Wait()
}
// hasString reports whether s appears in the list of strings.
func hasString(strings []string, s string) bool {
for _, t := range strings {
if s == t {
return true
}
}
return false
}
// build is the action for building a single package or command.
func (b *builder) build(a *action) (err error) {
// Return an error if the package has CXX files but it's not using
// cgo nor SWIG, since the CXX files can only be processed by cgo
// and SWIG (it's possible to have packages with C files without
// using cgo, they will get compiled with the plan9 C compiler and
// linked with the rest of the package).
if len(a.p.CXXFiles) > 0 && !a.p.usesCgo() && !a.p.usesSwig() {
return fmt.Errorf("can't build package %s because it contains C++ files (%s) but it's not using cgo nor SWIG",
a.p.ImportPath, strings.Join(a.p.CXXFiles, ","))
}
// Same as above for Objective-C files
if len(a.p.MFiles) > 0 && !a.p.usesCgo() && !a.p.usesSwig() {
return fmt.Errorf("can't build package %s because it contains Objective-C files (%s) but it's not using cgo nor SWIG",
a.p.ImportPath, strings.Join(a.p.MFiles, ","))
}
defer func() {
if err != nil && err != errPrintedOutput {
err = fmt.Errorf("go build %s: %v", a.p.ImportPath, err)
}
}()
if buildN {
// In -n mode, print a banner between packages.
// The banner is five lines so that when changes to
// different sections of the bootstrap script have to
// be merged, the banners give patch something
// to use to find its context.
fmt.Printf("\n#\n# %s\n#\n\n", a.p.ImportPath)
}
if buildV {
fmt.Fprintf(os.Stderr, "%s\n", a.p.ImportPath)
}
if a.p.Standard && a.p.ImportPath == "runtime" && buildContext.Compiler == "gc" &&
!hasString(a.p.HFiles, "zasm_"+buildContext.GOOS+"_"+buildContext.GOARCH+".h") {
return fmt.Errorf("%s/%s must be bootstrapped using make%v", buildContext.GOOS, buildContext.GOARCH, defaultSuffix())
}
// Make build directory.
obj := a.objdir
if err := b.mkdir(obj); err != nil {
return err
}
// make target directory
dir, _ := filepath.Split(a.target)
if dir != "" {
if err := b.mkdir(dir); err != nil {
return err
}
}
var gofiles, cfiles, sfiles, objects, cgoObjects []string
gofiles = append(gofiles, a.p.GoFiles...)
cfiles = append(cfiles, a.p.CFiles...)
sfiles = append(sfiles, a.p.SFiles...)
// Run cgo.
if a.p.usesCgo() {
// In a package using cgo, cgo compiles the C, C++ and assembly files with gcc.
// There is one exception: runtime/cgo's job is to bridge the
// cgo and non-cgo worlds, so it necessarily has files in both.
// In that case gcc only gets the gcc_* files.
var gccfiles []string
if a.p.Standard && a.p.ImportPath == "runtime/cgo" {
filter := func(files, nongcc, gcc []string) ([]string, []string) {
for _, f := range files {
if strings.HasPrefix(f, "gcc_") {
gcc = append(gcc, f)
} else {
nongcc = append(nongcc, f)
}
}
return nongcc, gcc
}
cfiles, gccfiles = filter(cfiles, cfiles[:0], gccfiles)
sfiles, gccfiles = filter(sfiles, sfiles[:0], gccfiles)
} else {
gccfiles = append(cfiles, sfiles...)
cfiles = nil
sfiles = nil
}
cgoExe := tool("cgo")
if a.cgo != nil && a.cgo.target != "" {
cgoExe = a.cgo.target
}
outGo, outObj, err := b.cgo(a.p, cgoExe, obj, gccfiles, a.p.CXXFiles, a.p.MFiles)
if err != nil {
return err
}
cgoObjects = append(cgoObjects, outObj...)
gofiles = append(gofiles, outGo...)
}
// Run SWIG.
if a.p.usesSwig() {
// In a package using SWIG, any .c or .s files are
// compiled with gcc.
gccfiles := append(cfiles, sfiles...)
cfiles = nil
sfiles = nil
outGo, outObj, err := b.swig(a.p, obj, gccfiles, a.p.CXXFiles, a.p.MFiles)
if err != nil {
return err
}
cgoObjects = append(cgoObjects, outObj...)
gofiles = append(gofiles, outGo...)
}
if len(gofiles) == 0 {
return &build.NoGoError{a.p.Dir}
}
// If we're doing coverage, preprocess the .go files and put them in the work directory
if a.p.coverMode != "" {
for i, file := range gofiles {
var sourceFile string
var coverFile string
var key string
if strings.HasSuffix(file, ".cgo1.go") {
// cgo files have absolute paths
base := filepath.Base(file)
sourceFile = file
coverFile = filepath.Join(obj, base)
key = strings.TrimSuffix(base, ".cgo1.go") + ".go"
} else {
sourceFile = filepath.Join(a.p.Dir, file)
coverFile = filepath.Join(obj, file)
key = file
}
cover := a.p.coverVars[key]
if cover == nil || isTestFile(file) {
// Not covering this file.
continue
}
if err := b.cover(a, coverFile, sourceFile, 0666, cover.Var); err != nil {
return err
}
gofiles[i] = coverFile
}
}
// Prepare Go import path list.
inc := b.includeArgs("-I", a.deps)
// Compile Go.
ofile, out, err := buildToolchain.gc(b, a.p, a.objpkg, obj, inc, gofiles)
if len(out) > 0 {
b.showOutput(a.p.Dir, a.p.ImportPath, b.processOutput(out))
if err != nil {
return errPrintedOutput
}
}
if err != nil {
return err
}
if ofile != a.objpkg {
objects = append(objects, ofile)
}
// Copy .h files named for goos or goarch or goos_goarch
// to names using GOOS and GOARCH.
// For example, defs_linux_amd64.h becomes defs_GOOS_GOARCH.h.
_goos_goarch := "_" + goos + "_" + goarch
_goos := "_" + goos
_goarch := "_" + goarch
for _, file := range a.p.HFiles {
name, ext := fileExtSplit(file)
switch {
case strings.HasSuffix(name, _goos_goarch):
targ := file[:len(name)-len(_goos_goarch)] + "_GOOS_GOARCH." + ext
if err := b.copyFile(a, obj+targ, filepath.Join(a.p.Dir, file), 0644); err != nil {
return err
}
case strings.HasSuffix(name, _goarch):
targ := file[:len(name)-len(_goarch)] + "_GOARCH." + ext
if err := b.copyFile(a, obj+targ, filepath.Join(a.p.Dir, file), 0644); err != nil {
return err
}
case strings.HasSuffix(name, _goos):
targ := file[:len(name)-len(_goos)] + "_GOOS." + ext
if err := b.copyFile(a, obj+targ, filepath.Join(a.p.Dir, file), 0644); err != nil {
return err
}
}
}
objExt := archChar
if _, ok := buildToolchain.(gccgoToolchain); ok {
objExt = "o"
}
for _, file := range cfiles {
out := file[:len(file)-len(".c")] + "." + objExt
if err := buildToolchain.cc(b, a.p, obj, obj+out, file); err != nil {
return err
}
objects = append(objects, out)
}
// Assemble .s files.
for _, file := range sfiles {
out := file[:len(file)-len(".s")] + "." + objExt
if err := buildToolchain.asm(b, a.p, obj, obj+out, file); err != nil {
return err
}
objects = append(objects, out)
}
// NOTE(rsc): On Windows, it is critically important that the
// gcc-compiled objects (cgoObjects) be listed after the ordinary
// objects in the archive. I do not know why this is.
// http://golang.org/issue/2601
objects = append(objects, cgoObjects...)
// Add system object files.
for _, syso := range a.p.SysoFiles {
objects = append(objects, filepath.Join(a.p.Dir, syso))
}
// Pack into archive in obj directory.
// If the Go compiler wrote an archive, we only need to add the
// object files for non-Go sources to the archive.
// If the Go compiler wrote an archive and the package is entirely
// Go sources, there is no pack to execute at all.
if len(objects) > 0 {
if err := buildToolchain.pack(b, a.p, obj, a.objpkg, objects); err != nil {
return err
}
}
// Link if needed.
if a.link {
// The compiler only cares about direct imports, but the
// linker needs the whole dependency tree.
all := actionList(a)
all = all[:len(all)-1] // drop a
if err := buildToolchain.ld(b, a.p, a.target, all, a.objpkg, objects); err != nil {
return err
}
}
return nil
}
// install is the action for installing a single package or executable.
func (b *builder) install(a *action) (err error) {
defer func() {
if err != nil && err != errPrintedOutput {
err = fmt.Errorf("go install %s: %v", a.p.ImportPath, err)
}
}()
a1 := a.deps[0]
perm := os.FileMode(0644)
if a1.link {
perm = 0755
}
// make target directory
dir, _ := filepath.Split(a.target)
if dir != "" {
if err := b.mkdir(dir); err != nil {
return err
}
}
// remove object dir to keep the amount of
// garbage down in a large build. On an operating system
// with aggressive buffering, cleaning incrementally like
// this keeps the intermediate objects from hitting the disk.
if !buildWork {
defer os.RemoveAll(a1.objdir)
defer os.Remove(a1.target)
}
return b.moveOrCopyFile(a, a.target, a1.target, perm)
}
// includeArgs returns the -I or -L directory list for access
// to the results of the list of actions.
func (b *builder) includeArgs(flag string, all []*action) []string {
inc := []string{}
incMap := map[string]bool{
b.work: true, // handled later
gorootPkg: true,
"": true, // ignore empty strings
}
// Look in the temporary space for results of test-specific actions.
// This is the $WORK/my/package/_test directory for the
// package being built, so there are few of these.
for _, a1 := range all {
if dir := a1.pkgdir; dir != a1.p.build.PkgRoot && !incMap[dir] {
incMap[dir] = true
inc = append(inc, flag, dir)
}
}
// Also look in $WORK for any non-test packages that have
// been built but not installed.
inc = append(inc, flag, b.work)
// Finally, look in the installed package directories for each action.
for _, a1 := range all {
if dir := a1.pkgdir; dir == a1.p.build.PkgRoot && !incMap[dir] {
incMap[dir] = true
if _, ok := buildToolchain.(gccgoToolchain); ok {
dir = filepath.Join(dir, "gccgo_"+goos+"_"+goarch)
} else {
dir = filepath.Join(dir, goos+"_"+goarch)
if buildContext.InstallSuffix != "" {
dir += "_" + buildContext.InstallSuffix
}
}
inc = append(inc, flag, dir)
}
}
return inc
}
// moveOrCopyFile is like 'mv src dst' or 'cp src dst'.
func (b *builder) moveOrCopyFile(a *action, dst, src string, perm os.FileMode) error {
if buildN {
b.showcmd("", "mv %s %s", src, dst)
return nil
}
// If we can update the mode and rename to the dst, do it.
// Otherwise fall back to standard copy.
if err := os.Chmod(src, perm); err == nil {
if err := os.Rename(src, dst); err == nil {
if buildX {
b.showcmd("", "mv %s %s", src, dst)
}
return nil
}
}
return b.copyFile(a, dst, src, perm)
}
// copyFile is like 'cp src dst'.
func (b *builder) copyFile(a *action, dst, src string, perm os.FileMode) error {
if buildN || buildX {
b.showcmd("", "cp %s %s", src, dst)
if buildN {
return nil
}
}
sf, err := os.Open(src)
if err != nil {
return err
}
defer sf.Close()
// Be careful about removing/overwriting dst.
// Do not remove/overwrite if dst exists and is a directory
// or a non-object file.
if fi, err := os.Stat(dst); err == nil {
if fi.IsDir() {
return fmt.Errorf("build output %q already exists and is a directory", dst)
}
if !isObject(dst) {
return fmt.Errorf("build output %q already exists and is not an object file", dst)
}
}
// On Windows, remove lingering ~ file from last attempt.
if toolIsWindows {
if _, err := os.Stat(dst + "~"); err == nil {
os.Remove(dst + "~")
}
}
os.Remove(dst)
df, err := os.OpenFile(dst, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, perm)
if err != nil && toolIsWindows {
// Windows does not allow deletion of a binary file
// while it is executing. Try to move it out of the way.
// If the move fails, which is likely, we'll try again the
// next time we do an install of this binary.
if err := os.Rename(dst, dst+"~"); err == nil {
os.Remove(dst + "~")
}
df, err = os.OpenFile(dst, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, perm)
}
if err != nil {
return err
}
_, err = io.Copy(df, sf)
df.Close()
if err != nil {
os.Remove(dst)
return fmt.Errorf("copying %s to %s: %v", src, dst, err)
}
return nil
}
// cover runs, in effect,
// go tool cover -mode=b.coverMode -var="varName" -o dst.go src.go
func (b *builder) cover(a *action, dst, src string, perm os.FileMode, varName string) error {
return b.run(a.objdir, "cover "+a.p.ImportPath, nil,
tool("cover"),
"-mode", a.p.coverMode,
"-var", varName,
"-o", dst,
src)
}
var objectMagic = [][]byte{
{'!', '<', 'a', 'r', 'c', 'h', '>', '\n'}, // Package archive
{'\x7F', 'E', 'L', 'F'}, // ELF
{0xFE, 0xED, 0xFA, 0xCE}, // Mach-O big-endian 32-bit
{0xFE, 0xED, 0xFA, 0xCF}, // Mach-O big-endian 64-bit
{0xCE, 0xFA, 0xED, 0xFE}, // Mach-O little-endian 32-bit
{0xCF, 0xFA, 0xED, 0xFE}, // Mach-O little-endian 64-bit
{0x4d, 0x5a, 0x90, 0x00, 0x03, 0x00, 0x04, 0x00}, // PE (Windows) as generated by 6l/8l
{0x00, 0x00, 0x01, 0xEB}, // Plan 9 i386
{0x00, 0x00, 0x8a, 0x97}, // Plan 9 amd64
}
func isObject(s string) bool {
f, err := os.Open(s)
if err != nil {
return false
}
defer f.Close()
buf := make([]byte, 64)
io.ReadFull(f, buf)
for _, magic := range objectMagic {
if bytes.HasPrefix(buf, magic) {
return true
}
}
return false
}
// fmtcmd formats a command in the manner of fmt.Sprintf but also:
//
// If dir is non-empty and the script is not in dir right now,
// fmtcmd inserts "cd dir\n" before the command.
//
// fmtcmd replaces the value of b.work with $WORK.
// fmtcmd replaces the value of goroot with $GOROOT.
// fmtcmd replaces the value of b.gobin with $GOBIN.
//
// fmtcmd replaces the name of the current directory with dot (.)
// but only when it is at the beginning of a space-separated token.
//
func (b *builder) fmtcmd(dir string, format string, args ...interface{}) string {
cmd := fmt.Sprintf(format, args...)
if dir != "" && dir != "/" {
cmd = strings.Replace(" "+cmd, " "+dir, " .", -1)[1:]
if b.scriptDir != dir {
b.scriptDir = dir
cmd = "cd " + dir + "\n" + cmd
}
}
if b.work != "" {
cmd = strings.Replace(cmd, b.work, "$WORK", -1)
}
return cmd
}
// showcmd prints the given command to standard output
// for the implementation of -n or -x.
func (b *builder) showcmd(dir string, format string, args ...interface{}) {
b.output.Lock()
defer b.output.Unlock()
b.print(b.fmtcmd(dir, format, args...) + "\n")
}
// showOutput prints "# desc" followed by the given output.
// The output is expected to contain references to 'dir', usually
// the source directory for the package that has failed to build.
// showOutput rewrites mentions of dir with a relative path to dir
// when the relative path is shorter. This is usually more pleasant.
// For example, if fmt doesn't compile and we are in src/pkg/html,
// the output is
//
// $ go build
// # fmt
// ../fmt/print.go:1090: undefined: asdf
// $
//
// instead of
//
// $ go build
// # fmt
// /usr/gopher/go/src/pkg/fmt/print.go:1090: undefined: asdf
// $
//
// showOutput also replaces references to the work directory with $WORK.
//
func (b *builder) showOutput(dir, desc, out string) {
prefix := "# " + desc
suffix := "\n" + out
if reldir := shortPath(dir); reldir != dir {
suffix = strings.Replace(suffix, " "+dir, " "+reldir, -1)
suffix = strings.Replace(suffix, "\n"+dir, "\n"+reldir, -1)
}
suffix = strings.Replace(suffix, " "+b.work, " $WORK", -1)
b.output.Lock()
defer b.output.Unlock()
b.print(prefix, suffix)
}
// shortPath returns an absolute or relative name for path, whatever is shorter.
func shortPath(path string) string {
if rel, err := filepath.Rel(cwd, path); err == nil && len(rel) < len(path) {
return rel
}
return path
}
// relPaths returns a copy of paths with absolute paths
// made relative to the current directory if they would be shorter.
func relPaths(paths []string) []string {
var out []string
pwd, _ := os.Getwd()
for _, p := range paths {
rel, err := filepath.Rel(pwd, p)
if err == nil && len(rel) < len(p) {
p = rel
}
out = append(out, p)
}
return out
}
// errPrintedOutput is a special error indicating that a command failed
// but that it generated output as well, and that output has already
// been printed, so there's no point showing 'exit status 1' or whatever
// the wait status was. The main executor, builder.do, knows not to
// print this error.
var errPrintedOutput = errors.New("already printed output - no need to show error")
var cgoLine = regexp.MustCompile(`\[[^\[\]]+\.cgo1\.go:[0-9]+\]`)
var cgoTypeSigRe = regexp.MustCompile(`\b_Ctype_\B`)
// run runs the command given by cmdline in the directory dir.
// If the command fails, run prints information about the failure
// and returns a non-nil error.
func (b *builder) run(dir string, desc string, env []string, cmdargs ...interface{}) error {
out, err := b.runOut(dir, desc, env, cmdargs...)
if len(out) > 0 {
if desc == "" {
desc = b.fmtcmd(dir, "%s", strings.Join(stringList(cmdargs...), " "))
}
b.showOutput(dir, desc, b.processOutput(out))
if err != nil {
err = errPrintedOutput
}
}
return err
}
// processOutput prepares the output of runOut to be output to the console.
func (b *builder) processOutput(out []byte) string {
if out[len(out)-1] != '\n' {
out = append(out, '\n')
}
messages := string(out)
// Fix up output referring to cgo-generated code to be more readable.
// Replace x.go:19[/tmp/.../x.cgo1.go:18] with x.go:19.
// Replace *[100]_Ctype_foo with *[100]C.foo.
// If we're using -x, assume we're debugging and want the full dump, so disable the rewrite.
if !buildX && cgoLine.MatchString(messages) {
messages = cgoLine.ReplaceAllString(messages, "")
messages = cgoTypeSigRe.ReplaceAllString(messages, "C.")
}
return messages
}
// runOut runs the command given by cmdline in the directory dir.
// It returns the command output and any errors that occurred.
func (b *builder) runOut(dir string, desc string, env []string, cmdargs ...interface{}) ([]byte, error) {
cmdline := stringList(cmdargs...)
if buildN || buildX {
var envcmdline string
for i := range env {
envcmdline += env[i]
envcmdline += " "
}
envcmdline += joinUnambiguously(cmdline)
b.showcmd(dir, "%s", envcmdline)
if buildN {
return nil, nil
}
}
nbusy := 0
for {
var buf bytes.Buffer
cmd := exec.Command(cmdline[0], cmdline[1:]...)
cmd.Stdout = &buf
cmd.Stderr = &buf
cmd.Dir = dir
cmd.Env = mergeEnvLists(env, envForDir(cmd.Dir))
err := cmd.Run()
// cmd.Run will fail on Unix if some other process has the binary
// we want to run open for writing. This can happen here because
// we build and install the cgo command and then run it.
// If another command was kicked off while we were writing the
// cgo binary, the child process for that command may be holding
// a reference to the fd, keeping us from running exec.
//
// But, you might reasonably wonder, how can this happen?
// The cgo fd, like all our fds, is close-on-exec, so that we need
// not worry about other processes inheriting the fd accidentally.
// The answer is that running a command is fork and exec.
// A child forked while the cgo fd is open inherits that fd.
// Until the child has called exec, it holds the fd open and the
// kernel will not let us run cgo. Even if the child were to close
// the fd explicitly, it would still be open from the time of the fork
// until the time of the explicit close, and the race would remain.
//
// On Unix systems, this results in ETXTBSY, which formats
// as "text file busy". Rather than hard-code specific error cases,
// we just look for that string. If this happens, sleep a little
// and try again. We let this happen three times, with increasing
// sleep lengths: 100+200+400 ms = 0.7 seconds.
//
// An alternate solution might be to split the cmd.Run into
// separate cmd.Start and cmd.Wait, and then use an RWLock
// to make sure that copyFile only executes when no cmd.Start
// call is in progress. However, cmd.Start (really syscall.forkExec)
// only guarantees that when it returns, the exec is committed to
// happen and succeed. It uses a close-on-exec file descriptor
// itself to determine this, so we know that when cmd.Start returns,
// at least one close-on-exec file descriptor has been closed.
// However, we cannot be sure that all of them have been closed,
// so the program might still encounter ETXTBSY even with such
// an RWLock. The race window would be smaller, perhaps, but not
// guaranteed to be gone.
//
// Sleeping when we observe the race seems to be the most reliable
// option we have.
//
// http://golang.org/issue/3001
//
if err != nil && nbusy < 3 && strings.Contains(err.Error(), "text file busy") {
time.Sleep(100 * time.Millisecond << uint(nbusy))
nbusy++
continue
}
return buf.Bytes(), err
}
}
// joinUnambiguously prints the slice, quoting where necessary to make the
// output unambiguous.
// TODO: See issue 5279. The printing of commands needs a complete redo.
func joinUnambiguously(a []string) string {
var buf bytes.Buffer
for i, s := range a {
if i > 0 {
buf.WriteByte(' ')
}
q := strconv.Quote(s)
if s == "" || strings.Contains(s, " ") || len(q) > len(s)+2 {
buf.WriteString(q)
} else {
buf.WriteString(s)
}
}
return buf.String()
}
// mkdir makes the named directory.
func (b *builder) mkdir(dir string) error {
b.exec.Lock()
defer b.exec.Unlock()
// We can be a little aggressive about being
// sure directories exist. Skip repeated calls.
if b.mkdirCache[dir] {
return nil
}
b.mkdirCache[dir] = true
if buildN || buildX {
b.showcmd("", "mkdir -p %s", dir)
if buildN {
return nil
}
}
if err := os.MkdirAll(dir, 0777); err != nil {
return err
}
return nil
}
// mkAbs returns an absolute path corresponding to
// evaluating f in the directory dir.
// We always pass absolute paths of source files so that
// the error messages will include the full path to a file
// in need of attention.
func mkAbs(dir, f string) string {
// Leave absolute paths alone.
// Also, during -n mode we use the pseudo-directory $WORK
// instead of creating an actual work directory that won't be used.
// Leave paths beginning with $WORK alone too.
if filepath.IsAbs(f) || strings.HasPrefix(f, "$WORK") {
return f
}
return filepath.Join(dir, f)
}
type toolchain interface {
// gc runs the compiler in a specific directory on a set of files
// and returns the name of the generated output file.
// The compiler runs in the directory dir.
gc(b *builder, p *Package, archive, obj string, importArgs []string, gofiles []string) (ofile string, out []byte, err error)
// cc runs the toolchain's C compiler in a directory on a C file
// to produce an output file.
cc(b *builder, p *Package, objdir, ofile, cfile string) error
// 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
// 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
// an archive from a set of object files.
// typically it is run in the object directory.
pack(b *builder, p *Package, objDir, afile string, ofiles []string) error
// ld runs the linker to create a package starting at mainpkg.
ld(b *builder, p *Package, out string, allactions []*action, mainpkg string, ofiles []string) error
compiler() string
linker() string
}
type noToolchain struct{}
func noCompiler() error {
log.Fatalf("unknown compiler %q", buildContext.Compiler)
return nil
}
func (noToolchain) compiler() string {
noCompiler()
return ""
}
func (noToolchain) linker() string {
noCompiler()
return ""
}
func (noToolchain) gc(b *builder, p *Package, archive, obj string, importArgs []string, gofiles []string) (ofile string, out []byte, err error) {
return "", nil, noCompiler()
}
func (noToolchain) asm(b *builder, p *Package, obj, ofile, sfile string) error {
return noCompiler()
}
func (noToolchain) pkgpath(basedir string, p *Package) string {
noCompiler()
return ""
}
func (noToolchain) pack(b *builder, p *Package, objDir, afile string, ofiles []string) error {
return noCompiler()
}
func (noToolchain) ld(b *builder, p *Package, out string, allactions []*action, mainpkg string, ofiles []string) error {
return noCompiler()
}
func (noToolchain) cc(b *builder, p *Package, objdir, ofile, cfile string) error {
return noCompiler()
}
// The Go toolchain.
type gcToolchain struct{}
func (gcToolchain) compiler() string {
return tool(archChar + "g")
}
func (gcToolchain) linker() string {
return tool(archChar + "l")
}
func (gcToolchain) gc(b *builder, p *Package, archive, obj string, importArgs []string, gofiles []string) (ofile string, output []byte, err error) {
if archive != "" {
ofile = archive
} else {
out := "_go_." + archChar
ofile = obj + out
}
gcargs := []string{"-p", p.ImportPath}
if p.Standard && p.ImportPath == "runtime" {
// runtime compiles with a special 6g flag to emit
// additional reflect type data.
gcargs = append(gcargs, "-+")
}
// If we're giving the compiler the entire package (no C etc files), tell it that,
// so that it can give good error messages about forward declarations.
// Exceptions: a few standard packages have forward declarations for
// pieces supplied behind-the-scenes by package runtime.
extFiles := len(p.CgoFiles) + len(p.CFiles) + len(p.CXXFiles) + len(p.MFiles) + len(p.SFiles) + len(p.SysoFiles) + len(p.SwigFiles) + len(p.SwigCXXFiles)
if p.Standard {
switch p.ImportPath {
case "os", "runtime/pprof", "sync", "time":
extFiles++
}
}
if extFiles == 0 {
gcargs = append(gcargs, "-complete")
}
if buildContext.InstallSuffix != "" {
gcargs = append(gcargs, "-installsuffix", buildContext.InstallSuffix)
}
args := stringList(tool(archChar+"g"), "-o", ofile, "-trimpath", b.work, buildGcflags, gcargs, "-D", p.localPrefix, importArgs)
if ofile == archive {
args = append(args, "-pack")
}
for _, f := range gofiles {
args = append(args, mkAbs(p.Dir, f))
}
output, err = b.runOut(p.Dir, p.ImportPath, nil, args)
return ofile, output, err
}
func (gcToolchain) asm(b *builder, p *Package, obj, ofile, sfile string) error {
sfile = mkAbs(p.Dir, sfile)
return b.run(p.Dir, p.ImportPath, nil, tool(archChar+"a"), "-trimpath", b.work, "-I", obj, "-o", ofile, "-D", "GOOS_"+goos, "-D", "GOARCH_"+goarch, sfile)
}
func (gcToolchain) pkgpath(basedir string, p *Package) string {
end := filepath.FromSlash(p.ImportPath + ".a")
return filepath.Join(basedir, end)
}
func (gcToolchain) pack(b *builder, p *Package, objDir, afile string, ofiles []string) error {
var absOfiles []string
for _, f := range ofiles {
absOfiles = append(absOfiles, mkAbs(objDir, f))
}
cmd := "c"
absAfile := mkAbs(objDir, afile)
appending := false
if _, err := os.Stat(absAfile); err == nil {
appending = true
cmd = "r"
}
cmdline := stringList("pack", cmd, absAfile, absOfiles)
if appending {
if buildN || buildX {
b.showcmd(p.Dir, "%s # internal", joinUnambiguously(cmdline))
}
if buildN {
return nil
}
if err := packInternal(b, absAfile, absOfiles); err != nil {
b.showOutput(p.Dir, p.ImportPath, err.Error()+"\n")
return errPrintedOutput
}
return nil
}
// Need actual pack.
cmdline[0] = tool("pack")
return b.run(p.Dir, p.ImportPath, nil, cmdline)
}
func packInternal(b *builder, afile string, ofiles []string) error {
dst, err := os.OpenFile(afile, os.O_WRONLY|os.O_APPEND, 0)
if err != nil {
return err
}
defer dst.Close() // only for error returns or panics
w := bufio.NewWriter(dst)
for _, ofile := range ofiles {
src, err := os.Open(ofile)
if err != nil {
return err
}
fi, err := src.Stat()
if err != nil {
src.Close()
return err
}
// Note: Not using %-16.16s format because we care
// about bytes, not runes.
name := fi.Name()
if len(name) > 16 {
name = name[:16]
} else {
name += strings.Repeat(" ", 16-len(name))
}
size := fi.Size()
fmt.Fprintf(w, "%s%-12d%-6d%-6d%-8o%-10d`\n",
name, 0, 0, 0, 0644, size)
n, err := io.Copy(w, src)
src.Close()
if err == nil && n < size {
err = io.ErrUnexpectedEOF
} else if err == nil && n > size {
err = fmt.Errorf("file larger than size reported by stat")
}
if err != nil {
return fmt.Errorf("copying %s to %s: %v", ofile, afile, err)
}
if size&1 != 0 {
w.WriteByte(0)
}
}
if err := w.Flush(); err != nil {
return err
}
return dst.Close()
}
func (gcToolchain) ld(b *builder, p *Package, out string, allactions []*action, mainpkg string, ofiles []string) error {
importArgs := b.includeArgs("-L", allactions)
cxx := false
for _, a := range allactions {
if a.p != nil && len(a.p.CXXFiles) > 0 {
cxx = true
}
}
ldflags := buildLdflags
// Limit slice capacity so that concurrent appends do not race on the shared array.
ldflags = ldflags[:len(ldflags):len(ldflags)]
if buildContext.InstallSuffix != "" {
ldflags = append(ldflags, "-installsuffix", buildContext.InstallSuffix)
}
if p.omitDWARF {
ldflags = append(ldflags, "-w")
}
// If the user has not specified the -extld option, then specify the
// appropriate linker. In case of C++ code, use the compiler named
// by the CXX environment variable or defaultCXX if CXX is not set.
// Else, use the CC environment variable and defaultCC as fallback.
extld := false
for _, f := range ldflags {
if f == "-extld" || strings.HasPrefix(f, "-extld=") {
extld = true
break
}
}
if !extld {
var compiler []string
if cxx {
compiler = envList("CXX", defaultCXX)
} else {
compiler = envList("CC", defaultCC)
}
ldflags = append(ldflags, "-extld="+compiler[0])
if len(compiler) > 1 {
extldflags := false
add := strings.Join(compiler[1:], " ")
for i, f := range ldflags {
if f == "-extldflags" && i+1 < len(ldflags) {
ldflags[i+1] = add + " " + ldflags[i+1]
extldflags = true
break
} else if strings.HasPrefix(f, "-extldflags=") {
ldflags[i] = "-extldflags=" + add + " " + ldflags[i][len("-extldflags="):]
extldflags = true
break
}
}
if !extldflags {
ldflags = append(ldflags, "-extldflags="+add)
}
}
}
return b.run(".", p.ImportPath, nil, tool(archChar+"l"), "-o", out, importArgs, ldflags, mainpkg)
}
func (gcToolchain) cc(b *builder, p *Package, objdir, ofile, cfile string) error {
inc := filepath.Join(goroot, "pkg", fmt.Sprintf("%s_%s", goos, goarch))
cfile = mkAbs(p.Dir, cfile)
args := stringList(tool(archChar+"c"), "-F", "-V", "-w", "-trimpath", b.work, "-I", objdir, "-I", inc, "-o", ofile, buildCcflags, "-D", "GOOS_"+goos, "-D", "GOARCH_"+goarch, cfile)
return b.run(p.Dir, p.ImportPath, nil, args)
}
// The Gccgo toolchain.
type gccgoToolchain struct{}
var gccgoBin, _ = exec.LookPath("gccgo")
func (gccgoToolchain) compiler() string {
return gccgoBin
}
func (gccgoToolchain) linker() string {
return gccgoBin
}
func (gccgoToolchain) gc(b *builder, p *Package, archive, obj string, importArgs []string, gofiles []string) (ofile string, output []byte, err error) {
out := p.Name + ".o"
ofile = obj + out
gcargs := []string{"-g"}
gcargs = append(gcargs, b.gccArchArgs()...)
if pkgpath := gccgoPkgpath(p); pkgpath != "" {
gcargs = append(gcargs, "-fgo-pkgpath="+pkgpath)
}
if p.localPrefix != "" {
gcargs = append(gcargs, "-fgo-relative-import-path="+p.localPrefix)
}
args := stringList("gccgo", importArgs, "-c", gcargs, "-o", ofile, buildGccgoflags)
for _, f := range gofiles {
args = append(args, mkAbs(p.Dir, f))
}
output, err = b.runOut(p.Dir, p.ImportPath, nil, args)
return ofile, output, err
}
func (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+`"`)
}
defs = append(defs, b.gccArchArgs()...)
return b.run(p.Dir, p.ImportPath, nil, "gccgo", "-I", obj, "-o", ofile, defs, sfile)
}
func (gccgoToolchain) pkgpath(basedir string, p *Package) string {
end := filepath.FromSlash(p.ImportPath + ".a")
afile := filepath.Join(basedir, end)
// add "lib" to the final element
return filepath.Join(filepath.Dir(afile), "lib"+filepath.Base(afile))
}
func (gccgoToolchain) pack(b *builder, p *Package, objDir, afile string, ofiles []string) error {
var absOfiles []string
for _, f := range ofiles {
absOfiles = append(absOfiles, mkAbs(objDir, f))
}
return b.run(p.Dir, p.ImportPath, nil, "ar", "cru", mkAbs(objDir, afile), absOfiles)
}
func (tools gccgoToolchain) ld(b *builder, p *Package, out string, allactions []*action, mainpkg string, ofiles []string) error {
// gccgo needs explicit linking with all package dependencies,
// and all LDFLAGS from cgo dependencies.
apackagesSeen := make(map[*Package]bool)
afiles := []string{}
ldflags := b.gccArchArgs()
cgoldflags := []string{}
usesCgo := false
cxx := false
objc := false
// Prefer the output of an install action to the output of a build action,
// because the install action will delete the output of the build action.
// Iterate over the list backward (reverse dependency order) so that we
// always see the install before the build.
for i := len(allactions) - 1; i >= 0; i-- {
a := allactions[i]
if !a.p.Standard {
if a.p != nil && !apackagesSeen[a.p] {
apackagesSeen[a.p] = true
if a.p.fake {
// move _test files to the top of the link order
afiles = append([]string{a.target}, afiles...)
} else {
afiles = append(afiles, a.target)
}
}
}
}
for _, a := range allactions {
if a.p != nil {
cgoldflags = append(cgoldflags, a.p.CgoLDFLAGS...)
if len(a.p.CgoFiles) > 0 {
usesCgo = true
}
if a.p.usesSwig() {
usesCgo = true
}
if len(a.p.CXXFiles) > 0 {
cxx = true
}
if len(a.p.MFiles) > 0 {
objc = true
}
}
}
ldflags = append(ldflags, afiles...)
ldflags = append(ldflags, cgoldflags...)
ldflags = append(ldflags, p.CgoLDFLAGS...)
if usesCgo && goos == "linux" {
ldflags = append(ldflags, "-Wl,-E")
}
if cxx {
ldflags = append(ldflags, "-lstdc++")
}
if objc {
ldflags = append(ldflags, "-lobjc")
}
return b.run(".", p.ImportPath, nil, "gccgo", "-o", out, ofiles, "-Wl,-(", ldflags, "-Wl,-)", buildGccgoflags)
}
func (gccgoToolchain) cc(b *builder, p *Package, objdir, ofile, cfile string) error {
inc := filepath.Join(goroot, "pkg", fmt.Sprintf("%s_%s", goos, goarch))
cfile = mkAbs(p.Dir, cfile)
defs := []string{"-D", "GOOS_" + goos, "-D", "GOARCH_" + goarch}
defs = append(defs, b.gccArchArgs()...)
if pkgpath := gccgoCleanPkgpath(p); pkgpath != "" {
defs = append(defs, `-D`, `GOPKGPATH="`+pkgpath+`"`)
}
// TODO: Support using clang here (during gccgo build)?
return b.run(p.Dir, p.ImportPath, nil, "gcc", "-Wall", "-g",
"-I", objdir, "-I", inc, "-o", ofile, defs, "-c", cfile)
}
func gccgoPkgpath(p *Package) string {
if p.build.IsCommand() && !p.forceLibrary {
return ""
}
return p.ImportPath
}
func gccgoCleanPkgpath(p *Package) string {
clean := func(r rune) rune {
switch {
case 'A' <= r && r <= 'Z', 'a' <= r && r <= 'z',
'0' <= r && r <= '9':
return r
}
return '_'
}
return strings.Map(clean, gccgoPkgpath(p))
}
// libgcc returns the filename for libgcc, as determined by invoking gcc with
// the -print-libgcc-file-name option.
func (b *builder) libgcc(p *Package) (string, error) {
var buf bytes.Buffer
gccCmd := b.gccCmd(p.Dir)
prev := b.print
if buildN {
// In -n mode we temporarily swap out the builder's
// print function to capture the command-line. This
// let's us assign it to $LIBGCC and produce a valid
// buildscript for cgo packages.
b.print = func(a ...interface{}) (int, error) {
return fmt.Fprint(&buf, a...)
}
}
f, err := b.runOut(p.Dir, p.ImportPath, nil, gccCmd, "-print-libgcc-file-name")
if err != nil {
return "", fmt.Errorf("gcc -print-libgcc-file-name: %v (%s)", err, f)
}
if buildN {
s := fmt.Sprintf("LIBGCC=$(%s)\n", buf.Next(buf.Len()-1))
b.print = prev
b.print(s)
return "$LIBGCC", nil
}
// clang might not be able to find libgcc, and in that case,
// it will simply return "libgcc.a", which is of no use to us.
if strings.Contains(gccCmd[0], "clang") && !filepath.IsAbs(string(f)) {
return "", nil
}
return strings.Trim(string(f), "\r\n"), nil
}
// gcc runs the gcc C compiler to create an object from a single C file.
func (b *builder) gcc(p *Package, out string, flags []string, cfile string) error {
return b.ccompile(p, out, flags, cfile, b.gccCmd(p.Dir))
}
// gxx runs the g++ C++ compiler to create an object from a single C++ file.
func (b *builder) gxx(p *Package, out string, flags []string, cxxfile string) error {
return b.ccompile(p, out, flags, cxxfile, b.gxxCmd(p.Dir))
}
// 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 {
file = mkAbs(p.Dir, file)
return b.run(p.Dir, p.ImportPath, nil, compiler, flags, "-o", out, "-c", file)
}
// gccld runs the gcc linker to create an executable from a set of object files.
func (b *builder) gccld(p *Package, out string, flags []string, obj []string) error {
var cmd []string
if len(p.CXXFiles) > 0 {
cmd = b.gxxCmd(p.Dir)
} else {
cmd = b.gccCmd(p.Dir)
}
return b.run(p.Dir, p.ImportPath, nil, cmd, "-o", out, obj, flags)
}
// gccCmd returns a gcc command line prefix
// defaultCC is defined in zdefaultcc.go, written by cmd/dist.
func (b *builder) gccCmd(objdir string) []string {
return b.ccompilerCmd("CC", defaultCC, objdir)
}
// gxxCmd returns a g++ command line prefix
// defaultCXX is defined in zdefaultcc.go, written by cmd/dist.
func (b *builder) gxxCmd(objdir string) []string {
return b.ccompilerCmd("CXX", defaultCXX, objdir)
}
// ccompilerCmd returns a command line prefix for the given environment
// variable and using the default command when the variable is empty.
func (b *builder) ccompilerCmd(envvar, defcmd, objdir string) []string {
// NOTE: env.go's mkEnv knows that the first three
// strings returned are "gcc", "-I", objdir (and cuts them off).
compiler := envList(envvar, defcmd)
a := []string{compiler[0], "-I", objdir}
a = append(a, compiler[1:]...)
// Definitely want -fPIC but on Windows gcc complains
// "-fPIC ignored for target (all code is position independent)"
if goos != "windows" {
a = append(a, "-fPIC")
}
a = append(a, b.gccArchArgs()...)
// gcc-4.5 and beyond require explicit "-pthread" flag
// for multithreading with pthread library.
if buildContext.CgoEnabled {
switch goos {
case "windows":
a = append(a, "-mthreads")
default:
a = append(a, "-pthread")
}
}
if strings.Contains(a[0], "clang") {
// disable ASCII art in clang errors, if possible
a = append(a, "-fno-caret-diagnostics")
// clang is too smart about command-line arguments
a = append(a, "-Qunused-arguments")
}
// disable word wrapping in error messages
a = append(a, "-fmessage-length=0")
// On OS X, some of the compilers behave as if -fno-common
// is always set, and the Mach-O linker in 6l/8l assumes this.
// See http://golang.org/issue/3253.
if goos == "darwin" {
a = append(a, "-fno-common")
}
return a
}
// gccArchArgs returns arguments to pass to gcc based on the architecture.
func (b *builder) gccArchArgs() []string {
switch archChar {
case "8":
return []string{"-m32"}
case "6":
return []string{"-m64"}
case "5":
return []string{"-marm"} // not thumb
}
return nil
}
// envList returns the value of the given environment variable broken
// into fields, using the default value when the variable is empty.
func envList(key, def string) []string {
v := os.Getenv(key)
if v == "" {
v = def
}
return strings.Fields(v)
}
// Return the flags to use when invoking the C or C++ compilers, or cgo.
func (b *builder) cflags(p *Package, def bool) (cppflags, cflags, cxxflags, ldflags []string) {
var defaults string
if def {
defaults = "-g -O2"
}
cppflags = stringList(envList("CGO_CPPFLAGS", ""), p.CgoCPPFLAGS)
cflags = stringList(envList("CGO_CFLAGS", defaults), p.CgoCFLAGS)
cxxflags = stringList(envList("CGO_CXXFLAGS", defaults), p.CgoCXXFLAGS)
ldflags = stringList(envList("CGO_LDFLAGS", defaults), p.CgoLDFLAGS)
return
}
var cgoRe = regexp.MustCompile(`[/\\:]`)
var (
cgoLibGccFile string
cgoLibGccErr error
cgoLibGccFileOnce sync.Once
)
func (b *builder) cgo(p *Package, cgoExe, obj string, gccfiles, gxxfiles, mfiles []string) (outGo, outObj []string, err error) {
cgoCPPFLAGS, cgoCFLAGS, cgoCXXFLAGS, cgoLDFLAGS := b.cflags(p, true)
_, cgoexeCFLAGS, _, _ := b.cflags(p, false)
// If we are compiling Objective-C code, then we need to link against libobjc
if len(mfiles) > 0 {
cgoLDFLAGS = append(cgoLDFLAGS, "-lobjc")
}
if pkgs := p.CgoPkgConfig; len(pkgs) > 0 {
out, err := b.runOut(p.Dir, p.ImportPath, nil, "pkg-config", "--cflags", pkgs)
if err != nil {
b.showOutput(p.Dir, "pkg-config --cflags "+strings.Join(pkgs, " "), string(out))
b.print(err.Error() + "\n")
return nil, nil, errPrintedOutput
}
if len(out) > 0 {
cgoCPPFLAGS = append(cgoCPPFLAGS, strings.Fields(string(out))...)
}
out, err = b.runOut(p.Dir, p.ImportPath, nil, "pkg-config", "--libs", pkgs)
if err != nil {
b.showOutput(p.Dir, "pkg-config --libs "+strings.Join(pkgs, " "), string(out))
b.print(err.Error() + "\n")
return nil, nil, errPrintedOutput
}
if len(out) > 0 {
cgoLDFLAGS = append(cgoLDFLAGS, strings.Fields(string(out))...)
}
}
// Allows including _cgo_export.h from .[ch] files in the package.
cgoCPPFLAGS = append(cgoCPPFLAGS, "-I", obj)
// cgo
// TODO: CGOPKGPATH, CGO_FLAGS?
gofiles := []string{obj + "_cgo_gotypes.go"}
cfiles := []string{"_cgo_main.c", "_cgo_export.c"}
for _, fn := range p.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?
objExt := archChar
if p.Standard && p.ImportPath == "runtime/cgo" {
cgoflags = append(cgoflags, "-import_runtime_cgo=false")
}
if p.Standard && (p.ImportPath == "runtime/race" || p.ImportPath == "runtime/cgo") {
cgoflags = append(cgoflags, "-import_syscall=false")
}
// Update $CGO_LDFLAGS with p.CgoLDFLAGS.
var cgoenv []string
if len(cgoLDFLAGS) > 0 {
flags := make([]string, len(cgoLDFLAGS))
for i, f := range cgoLDFLAGS {
flags[i] = strconv.Quote(f)
}
cgoenv = []string{"CGO_LDFLAGS=" + strings.Join(flags, " ")}
}
if _, ok := buildToolchain.(gccgoToolchain); ok {
cgoflags = append(cgoflags, "-gccgo")
if pkgpath := gccgoPkgpath(p); pkgpath != "" {
cgoflags = append(cgoflags, "-gccgopkgpath="+pkgpath)
}
objExt = "o"
}
if err := b.run(p.Dir, p.ImportPath, cgoenv, cgoExe, "-objdir", obj, cgoflags, "--", cgoCPPFLAGS, cgoexeCFLAGS, p.CgoFiles); err != nil {
return nil, nil, err
}
outGo = append(outGo, gofiles...)
// cc _cgo_defun.c
defunObj := obj + "_cgo_defun." + objExt
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
// filter out -lsomelib, -l somelib, *.{so,dll,dylib}, and (on Darwin) -framework X
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"):
continue
default:
bareLDFLAGS = append(bareLDFLAGS, f)
}
}
cgoLibGccFileOnce.Do(func() {
cgoLibGccFile, cgoLibGccErr = b.libgcc(p)
})
if cgoLibGccFile == "" && cgoLibGccErr != nil {
return nil, nil, err
}
var staticLibs []string
if goos == "windows" {
// libmingw32 and libmingwex might also use libgcc, so libgcc must come last,
// and they also have some inter-dependencies, so must use linker groups.
staticLibs = []string{"-Wl,--start-group", "-lmingwex", "-lmingw32", "-Wl,--end-group"}
}
if cgoLibGccFile != "" {
staticLibs = append(staticLibs, cgoLibGccFile)
}
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)
}
}
for _, file := range gccfiles {
ofile := obj + cgoRe.ReplaceAllString(file[:len(file)-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"
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"
if err := b.gcc(p, ofile, cflags, file); err != nil {
return nil, nil, err
}
linkobj = append(linkobj, ofile)
outObj = append(outObj, ofile)
}
linkobj = append(linkobj, p.SysoFiles...)
dynobj := obj + "_cgo_.o"
if goarch == "arm" && goos == "linux" { // we need to use -pie for Linux/ARM to get accurate imported sym
cgoLDFLAGS = append(cgoLDFLAGS, "-pie")
}
if err := b.gccld(p, dynobj, cgoLDFLAGS, linkobj); err != nil {
return nil, nil, err
}
if goarch == "arm" && goos == "linux" { // but we don't need -pie for normal cgo programs
cgoLDFLAGS = cgoLDFLAGS[0 : len(cgoLDFLAGS)-1]
}
if _, ok := buildToolchain.(gccgoToolchain); ok {
// we don't use dynimport when using gccgo.
return outGo, outObj, nil
}
// cgo -dynimport
importC := obj + "_cgo_import.c"
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, cgoExe, "-objdir", obj, "-dynimport", dynobj, "-dynout", importC, cgoflags); err != nil {
return nil, nil, err
}
// cc _cgo_import.ARCH
importObj := obj + "_cgo_import." + objExt
if err := buildToolchain.cc(b, p, obj, importObj, importC); err != nil {
return nil, nil, err
}
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)
}
}
if err := b.gccld(p, ofile, stringList(bareLDFLAGS, "-Wl,-r", "-nostdlib", staticLibs), 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. http://golang.org/issue/2601
outObj = stringList(importObj, nonGccObjs, ofile)
return outGo, outObj, nil
}
// Run SWIG on all SWIG input files.
// TODO: Don't build a shared library, once SWIG emits the necessary
// pragmas for external linking.
func (b *builder) swig(p *Package, obj string, gccfiles, gxxfiles, mfiles []string) (outGo, outObj []string, err error) {
cgoCPPFLAGS, cgoCFLAGS, cgoCXXFLAGS, _ := b.cflags(p, true)
cflags := stringList(cgoCPPFLAGS, cgoCFLAGS)
cxxflags := stringList(cgoCPPFLAGS, cgoCXXFLAGS)
for _, file := range gccfiles {
ofile := obj + cgoRe.ReplaceAllString(file[:len(file)-1], "_") + "o"
if err := b.gcc(p, ofile, cflags, file); err != nil {
return nil, nil, err
}
outObj = append(outObj, ofile)
}
for _, file := range gxxfiles {
// Append .o to the file, just in case the pkg has file.c and file.cpp
ofile := obj + cgoRe.ReplaceAllString(file, "_") + ".o"
if err := b.gxx(p, ofile, cxxflags, file); err != nil {
return nil, nil, err
}
outObj = append(outObj, ofile)
}
for _, file := range mfiles {
// Append .o to the file, just in case the pkg has file.c and file.cpp
ofile := obj + cgoRe.ReplaceAllString(file, "_") + ".o"
if err := b.gcc(p, ofile, cflags, file); err != nil {
return nil, nil, err
}
outObj = append(outObj, ofile)
}
if err := b.swigVersionCheck(); err != nil {
return nil, nil, err
}
intgosize, err := b.swigIntSize(obj)
if err != nil {
return nil, nil, err
}
for _, f := range p.SwigFiles {
goFile, objFile, gccObjFile, err := b.swigOne(p, f, obj, false, intgosize)
if err != nil {
return nil, nil, err
}
if goFile != "" {
outGo = append(outGo, goFile)
}
if objFile != "" {
outObj = append(outObj, objFile)
}
if gccObjFile != "" {
outObj = append(outObj, gccObjFile)
}
}
for _, f := range p.SwigCXXFiles {
goFile, objFile, gccObjFile, err := b.swigOne(p, f, obj, true, intgosize)
if err != nil {
return nil, nil, err
}
if goFile != "" {
outGo = append(outGo, goFile)
}
if objFile != "" {
outObj = append(outObj, objFile)
}
if gccObjFile != "" {
outObj = append(outObj, gccObjFile)
}
}
return outGo, outObj, nil
}
// Make sure SWIG is new enough.
var (
swigCheckOnce sync.Once
swigCheck error
)
func (b *builder) swigDoVersionCheck() error {
out, err := b.runOut("", "", nil, "swig", "-version")
if err != nil {
return err
}
re := regexp.MustCompile(`[vV]ersion +([\d])`)
matches := re.FindSubmatch(out)
if matches == nil {
// Can't find version number; hope for the best.
return nil
}
major, err := strconv.Atoi(string(matches[1]))
if err != nil {
// Can't find version number; hope for the best.
return nil
}
if major < 3 {
return errors.New("must have SWIG version >= 3.0")
}
return nil
}
func (b *builder) swigVersionCheck() error {
swigCheckOnce.Do(func() {
swigCheck = b.swigDoVersionCheck()
})
return swigCheck
}
// This code fails to build if sizeof(int) <= 32
const swigIntSizeCode = `
package main
const i int = 1 << 32
`
// Determine the size of int on the target system for the -intgosize option
// of swig >= 2.0.9
func (b *builder) swigIntSize(obj string) (intsize string, err error) {
if buildN {
return "$INTBITS", nil
}
src := filepath.Join(b.work, "swig_intsize.go")
if err = ioutil.WriteFile(src, []byte(swigIntSizeCode), 0644); err != nil {
return
}
srcs := []string{src}
p := goFilesPackage(srcs)
if _, _, e := buildToolchain.gc(b, p, "", obj, nil, srcs); e != nil {
return "32", nil
}
return "64", nil
}
// Run SWIG on one SWIG input file.
func (b *builder) swigOne(p *Package, file, obj string, cxx bool, intgosize string) (outGo, outObj, objGccObj string, err error) {
cgoCPPFLAGS, cgoCFLAGS, cgoCXXFLAGS, _ := b.cflags(p, true)
var cflags []string
if cxx {
cflags = stringList(cgoCPPFLAGS, cgoCXXFLAGS)
} else {
cflags = stringList(cgoCPPFLAGS, cgoCFLAGS)
}
n := 5 // length of ".swig"
if cxx {
n = 8 // length of ".swigcxx"
}
base := file[:len(file)-n]
goFile := base + ".go"
cBase := base + "_gc."
gccBase := base + "_wrap."
gccExt := "c"
if cxx {
gccExt = "cxx"
}
_, gccgo := buildToolchain.(gccgoToolchain)
// swig
args := []string{
"-go",
"-intgosize", intgosize,
"-module", base,
"-o", obj + gccBase + gccExt,
"-outdir", obj,
}
if gccgo {
args = append(args, "-gccgo")
if pkgpath := gccgoPkgpath(p); pkgpath != "" {
args = append(args, "-go-pkgpath", pkgpath)
}
}
if cxx {
args = append(args, "-c++")
}
if out, err := b.runOut(p.Dir, p.ImportPath, nil, "swig", args, file); err != nil {
if len(out) > 0 {
if bytes.Contains(out, []byte("Unrecognized option -intgosize")) {
return "", "", "", errors.New("must have SWIG version >= 3.0")
}
b.showOutput(p.Dir, p.ImportPath, b.processOutput(out))
return "", "", "", errPrintedOutput
}
return "", "", "", err
}
var cObj string
if !gccgo {
// cc
cObj = obj + cBase + archChar
if err := buildToolchain.cc(b, p, obj, cObj, obj+cBase+"c"); err != nil {
return "", "", "", err
}
}
// gcc
gccObj := obj + gccBase + "o"
if !cxx {
if err := b.gcc(p, gccObj, cflags, obj+gccBase+gccExt); err != nil {
return "", "", "", err
}
} else {
if err := b.gxx(p, gccObj, cflags, obj+gccBase+gccExt); err != nil {
return "", "", "", err
}
}
return obj + goFile, cObj, gccObj, nil
}
// An actionQueue is a priority queue of actions.
type actionQueue []*action
// Implement heap.Interface
func (q *actionQueue) Len() int { return len(*q) }
func (q *actionQueue) Swap(i, j int) { (*q)[i], (*q)[j] = (*q)[j], (*q)[i] }
func (q *actionQueue) Less(i, j int) bool { return (*q)[i].priority < (*q)[j].priority }
func (q *actionQueue) Push(x interface{}) { *q = append(*q, x.(*action)) }
func (q *actionQueue) Pop() interface{} {
n := len(*q) - 1
x := (*q)[n]
*q = (*q)[:n]
return x
}
func (q *actionQueue) push(a *action) {
heap.Push(q, a)
}
func (q *actionQueue) pop() *action {
return heap.Pop(q).(*action)
}
func raceInit() {
if !buildRace {
return
}
if goarch != "amd64" || goos != "linux" && goos != "darwin" && goos != "windows" {
fmt.Fprintf(os.Stderr, "go %s: -race is only supported on linux/amd64, darwin/amd64 and windows/amd64\n", flag.Args()[0])
os.Exit(2)
}
buildGcflags = append(buildGcflags, "-race")
buildLdflags = append(buildLdflags, "-race")
buildCcflags = append(buildCcflags, "-D", "RACE")
if buildContext.InstallSuffix != "" {
buildContext.InstallSuffix += "_"
}
buildContext.InstallSuffix += "race"
buildContext.BuildTags = append(buildContext.BuildTags, "race")
}
// defaultSuffix returns file extension used for command files in
// current os environment.
func defaultSuffix() string {
switch runtime.GOOS {
case "windows":
return ".bat"
case "plan9":
return ".rc"
default:
return ".bash"
}
}
// Copyright 2012 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 (
"fmt"
"io/ioutil"
"os"
"path/filepath"
"strings"
)
var cmdClean = &Command{
UsageLine: "clean [-i] [-r] [-n] [-x] [build flags] [packages]",
Short: "remove object files",
Long: `
Clean removes object files from package source directories.
The go command builds most objects in a temporary directory,
so go clean is mainly concerned with object files left by other
tools or by manual invocations of go build.
Specifically, clean removes the following files from each of the
source directories corresponding to the import paths:
_obj/ old object directory, left from Makefiles
_test/ old test directory, left from Makefiles
_testmain.go old gotest file, left from Makefiles
test.out old test log, left from Makefiles
build.out old test log, left from Makefiles
*.[568ao] object files, left from Makefiles
DIR(.exe) from go build
DIR.test(.exe) from go test -c
MAINFILE(.exe) from go build MAINFILE.go
*.so from SWIG
In the list, DIR represents the final path element of the
directory, and MAINFILE is the base name of any Go source
file in the directory that is not included when building
the package.
The -i flag causes clean to remove the corresponding installed
archive or binary (what 'go install' would create).
The -n flag causes clean to print the remove commands it would execute,
but not run them.
The -r flag causes clean to be applied recursively to all the
dependencies of the packages named by the import paths.
The -x flag causes clean to print remove commands as it executes them.
For more about build flags, see 'go help build'.
For more about specifying packages, see 'go help packages'.
`,
}
var cleanI bool // clean -i flag
var cleanR bool // clean -r flag
func init() {
// break init cycle
cmdClean.Run = runClean
cmdClean.Flag.BoolVar(&cleanI, "i", false, "")
cmdClean.Flag.BoolVar(&cleanR, "r", false, "")
// -n and -x are important enough to be
// mentioned explicitly in the docs but they
// are part of the build flags.
addBuildFlags(cmdClean)
}
func runClean(cmd *Command, args []string) {
for _, pkg := range packagesAndErrors(args) {
clean(pkg)
}
}
var cleaned = map[*Package]bool{}
// TODO: These are dregs left by Makefile-based builds.
// Eventually, can stop deleting these.
var cleanDir = map[string]bool{
"_test": true,
"_obj": true,
}
var cleanFile = map[string]bool{
"_testmain.go": true,
"test.out": true,
"build.out": true,
"a.out": true,
}
var cleanExt = map[string]bool{
".5": true,
".6": true,
".8": true,
".a": true,
".o": true,
".so": true,
}
func clean(p *Package) {
if cleaned[p] {
return
}
cleaned[p] = true
if p.Dir == "" {
errorf("can't load package: %v", p.Error)
return
}
dirs, err := ioutil.ReadDir(p.Dir)
if err != nil {
errorf("go clean %s: %v", p.Dir, err)
return
}
var b builder
b.print = fmt.Print
packageFile := map[string]bool{}
if p.Name != "main" {
// Record which files are not in package main.
// The others are.
keep := func(list []string) {
for _, f := range list {
packageFile[f] = true
}
}
keep(p.GoFiles)
keep(p.CgoFiles)
keep(p.TestGoFiles)
keep(p.XTestGoFiles)
}
_, elem := filepath.Split(p.Dir)
var allRemove []string
// Remove dir-named executable only if this is package main.
if p.Name == "main" {
allRemove = append(allRemove,
elem,
elem+".exe",
)
}
// Remove package test executables.
allRemove = append(allRemove,
elem+".test",
elem+".test.exe",
)
// Remove a potential executable for each .go file in the directory that
// is not part of the directory's package.
for _, dir := range dirs {
name := dir.Name()
if packageFile[name] {
continue
}
if !dir.IsDir() && strings.HasSuffix(name, ".go") {
// TODO(adg,rsc): check that this .go file is actually
// in "package main", and therefore capable of building
// to an executable file.
base := name[:len(name)-len(".go")]
allRemove = append(allRemove, base, base+".exe")
}
}
if buildN || buildX {
b.showcmd(p.Dir, "rm -f %s", strings.Join(allRemove, " "))
}
toRemove := map[string]bool{}
for _, name := range allRemove {
toRemove[name] = true
}
for _, dir := range dirs {
name := dir.Name()
if dir.IsDir() {
// TODO: Remove once Makefiles are forgotten.
if cleanDir[name] {
if buildN || buildX {
b.showcmd(p.Dir, "rm -r %s", name)
if buildN {
continue
}
}
if err := os.RemoveAll(filepath.Join(p.Dir, name)); err != nil {
errorf("go clean: %v", err)
}
}
continue
}
if buildN {
continue
}
if cleanFile[name] || cleanExt[filepath.Ext(name)] || toRemove[name] {
removeFile(filepath.Join(p.Dir, name))
}
}
if cleanI && p.target != "" {
if buildN || buildX {
b.showcmd("", "rm -f %s", p.target)
}
if !buildN {
removeFile(p.target)
}
}
if cleanR {
for _, p1 := range p.imports {
clean(p1)
}
}
}
// removeFile tries to remove file f, if error other than file doesn't exist
// occurs, it will report the error.
func removeFile(f string) {
err := os.Remove(f)
if err == nil || os.IsNotExist(err) {
return
}
// Windows does not allow deletion of a binary file while it is executing.
if toolIsWindows {
// Remove lingering ~ file from last attempt.
if _, err2 := os.Stat(f + "~"); err2 == nil {
os.Remove(f + "~")
}
// Try to move it out of the way. If the move fails,
// which is likely, we'll try again the
// next time we do an install of this binary.
if err2 := os.Rename(f, f+"~"); err2 == nil {
os.Remove(f + "~")
return
}
}
errorf("go clean: %v", err)
}
// Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package main
import (
"go/build"
)
type Context struct {
GOARCH string `json:",omitempty"` // target architecture
GOOS string `json:",omitempty"` // target operating system
GOROOT string `json:",omitempty"` // Go root
GOPATH string `json:",omitempty"` // Go path
CgoEnabled bool `json:",omitempty"` // whether cgo can be used
UseAllFiles bool `json:",omitempty"` // use files regardless of +build lines, file names
Compiler string `json:",omitempty"` // compiler to assume when computing target paths
BuildTags []string `json:",omitempty"` // build constraints to match in +build lines
ReleaseTags []string `json:",omitempty"` // releases the current release is compatible with
InstallSuffix string `json:",omitempty"` // suffix to use in the name of the install dir
}
func newContext(c *build.Context) *Context {
return &Context{
GOARCH: c.GOARCH,
GOOS: c.GOOS,
GOROOT: c.GOROOT,
CgoEnabled: c.CgoEnabled,
UseAllFiles: c.UseAllFiles,
Compiler: c.Compiler,
BuildTags: c.BuildTags,
ReleaseTags: c.ReleaseTags,
InstallSuffix: c.InstallSuffix,
}
}
// Copyright 2012 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 !cmd_go_bootstrap
// This code is compiled into the real 'go' binary, but it is not
// compiled into the binary that is built during all.bash, so as
// to avoid needing to build net (and thus use cgo) during the
// bootstrap process.
package main
import (
"encoding/xml"
"fmt"
"io"
"strings"
)
// charsetReader returns a reader for the given charset. Currently
// it only supports UTF-8 and ASCII. Otherwise, it returns a meaningful
// error which is printed by go get, so the user can find why the package
// wasn't downloaded if the encoding is not supported. Note that, in
// order to reduce potential errors, ASCII is treated as UTF-8 (i.e. characters
// greater than 0x7f are not rejected).
func charsetReader(charset string, input io.Reader) (io.Reader, error) {
switch strings.ToLower(charset) {
case "ascii":
return input, nil
default:
return nil, fmt.Errorf("can't decode XML document using charset %q", charset)
}
}
// parseMetaGoImports returns meta imports from the HTML in r.
// Parsing ends at the end of the <head> section or the beginning of the <body>.
func parseMetaGoImports(r io.Reader) (imports []metaImport, err error) {
d := xml.NewDecoder(r)
d.CharsetReader = charsetReader
d.Strict = false
var t xml.Token
for {
t, err = d.Token()
if err != nil {
if err == io.EOF {
err = nil
}
return
}
if e, ok := t.(xml.StartElement); ok && strings.EqualFold(e.Name.Local, "body") {
return
}
if e, ok := t.(xml.EndElement); ok && strings.EqualFold(e.Name.Local, "head") {
return
}
e, ok := t.(xml.StartElement)
if !ok || !strings.EqualFold(e.Name.Local, "meta") {
continue
}
if attrValue(e.Attr, "name") != "go-import" {
continue
}
if f := strings.Fields(attrValue(e.Attr, "content")); len(f) == 3 {
imports = append(imports, metaImport{
Prefix: f[0],
VCS: f[1],
RepoRoot: f[2],
})
}
}
}
// attrValue returns the attribute value for the case-insensitive key
// `name', or the empty string if nothing is found.
func attrValue(attrs []xml.Attr, name string) string {
for _, a := range attrs {
if strings.EqualFold(a.Name.Local, name) {
return a.Value
}
}
return ""
}
// Copyright 2011 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.
// DO NOT EDIT THIS FILE. GENERATED BY mkdoc.sh.
// Edit the documentation in other files and rerun mkdoc.sh to generate this one.
/*
Go is a tool for managing Go source code.
Usage:
go command [arguments]
The commands are:
build compile packages and dependencies
clean remove object files
env print Go environment information
fix run go tool fix on packages
fmt run gofmt on package sources
get download and install packages and dependencies
install compile and install packages and dependencies
list list packages
run compile and run Go program
test test packages
tool run specified go tool
version print Go version
vet run go tool vet on packages
Use "go help [command]" for more information about a command.
Additional help topics:
c calling between Go and C
filetype file types
gopath GOPATH environment variable
importpath import path syntax
packages description of package lists
testflag description of testing flags
testfunc description of testing functions
Use "go help [topic]" for more information about that topic.
Compile packages and dependencies
Usage:
go build [-o output] [-i] [build flags] [packages]
Build compiles the packages named by the import paths,
along with their dependencies, but it does not install the results.
If the arguments are a list of .go files, build treats them as a list
of source files specifying a single package.
When the command line specifies a single main package,
build writes the resulting executable to output.
Otherwise build compiles the packages but discards the results,
serving only as a check that the packages can be built.
The -o flag specifies the output file name. If not specified, the
output file name depends on the arguments and derives from the name
of the package, such as p.a for package p, unless p is 'main'. If
the package is main and file names are provided, the file name
derives from the first file name mentioned, such as f1 for 'go build
f1.go f2.go'; with no files provided ('go build'), the output file
name is the base name of the containing directory.
The -i flag installs the packages that are dependencies of the target.
The build flags are shared by the build, clean, get, install, list, run,
and test commands:
-a
force rebuilding of packages that are already up-to-date.
-n
print the commands but do not run them.
-p n
the number of builds that can be run in parallel.
The default is the number of CPUs available.
-race
enable data race detection.
Supported only on linux/amd64, darwin/amd64 and windows/amd64.
-v
print the names of packages as they are compiled.
-work
print the name of the temporary work directory and
do not delete it when exiting.
-x
print the commands.
-ccflags 'arg list'
arguments to pass on each 5c, 6c, or 8c compiler invocation.
-compiler name
name of compiler to use, as in runtime.Compiler (gccgo or gc).
-gccgoflags 'arg list'
arguments to pass on each gccgo compiler/linker invocation.
-gcflags 'arg list'
arguments to pass on each 5g, 6g, or 8g compiler invocation.
-installsuffix suffix
a suffix to use in the name of the package installation directory,
in order to keep output separate from default builds.
If using the -race flag, the install suffix is automatically set to race
or, if set explicitly, has _race appended to it.
-ldflags 'flag list'
arguments to pass on each 5l, 6l, or 8l linker invocation.
-tags 'tag list'
a list of build tags to consider satisfied during the build.
For more information about build tags, see the description of
build constraints in the documentation for the go/build package.
The list flags accept a space-separated list of strings. To embed spaces
in an element in the list, surround it with either single or double quotes.
For more about specifying packages, see 'go help packages'.
For more about where packages and binaries are installed,
run 'go help gopath'. For more about calling between Go and C/C++,
run 'go help c'.
See also: go install, go get, go clean.
Remove object files
Usage:
go clean [-i] [-r] [-n] [-x] [build flags] [packages]
Clean removes object files from package source directories.
The go command builds most objects in a temporary directory,
so go clean is mainly concerned with object files left by other
tools or by manual invocations of go build.
Specifically, clean removes the following files from each of the
source directories corresponding to the import paths:
_obj/ old object directory, left from Makefiles
_test/ old test directory, left from Makefiles
_testmain.go old gotest file, left from Makefiles
test.out old test log, left from Makefiles
build.out old test log, left from Makefiles
*.[568ao] object files, left from Makefiles
DIR(.exe) from go build
DIR.test(.exe) from go test -c
MAINFILE(.exe) from go build MAINFILE.go
*.so from SWIG
In the list, DIR represents the final path element of the
directory, and MAINFILE is the base name of any Go source
file in the directory that is not included when building
the package.
The -i flag causes clean to remove the corresponding installed
archive or binary (what 'go install' would create).
The -n flag causes clean to print the remove commands it would execute,
but not run them.
The -r flag causes clean to be applied recursively to all the
dependencies of the packages named by the import paths.
The -x flag causes clean to print remove commands as it executes them.
For more about build flags, see 'go help build'.
For more about specifying packages, see 'go help packages'.
Print Go environment information
Usage:
go env [var ...]
Env prints Go environment information.
By default env prints information as a shell script
(on Windows, a batch file). If one or more variable
names is given as arguments, env prints the value of
each named variable on its own line.
Run go tool fix on packages
Usage:
go fix [packages]
Fix runs the Go fix command on the packages named by the import paths.
For more about fix, see 'godoc fix'.
For more about specifying packages, see 'go help packages'.
To run fix with specific options, run 'go tool fix'.
See also: go fmt, go vet.
Run gofmt on package sources
Usage:
go fmt [-n] [-x] [packages]
Fmt runs the command 'gofmt -l -w' on the packages named
by the import paths. It prints the names of the files that are modified.
For more about gofmt, see 'godoc gofmt'.
For more about specifying packages, see 'go help packages'.
The -n flag prints commands that would be executed.
The -x flag prints commands as they are executed.
To run gofmt with specific options, run gofmt itself.
See also: go fix, go vet.
Download and install packages and dependencies
Usage:
go get [-d] [-fix] [-t] [-u] [build flags] [packages]
Get downloads and installs the packages named by the import paths,
along with their dependencies.
The -d flag instructs get to stop after downloading the packages; that is,
it instructs get not to install the packages.
The -fix flag instructs get to run the fix tool on the downloaded packages
before resolving dependencies or building the code.
The -t flag instructs get to also download the packages required to build
the tests for the specified packages.
The -u flag instructs get to use the network to update the named packages
and their dependencies. By default, get uses the network to check out
missing packages but does not use it to look for updates to existing packages.
Get also accepts build flags to control the installation. See 'go help build'.
When checking out or updating a package, get looks for a branch or tag
that matches the locally installed version of Go. The most important
rule is that if the local installation is running version "go1", get
searches for a branch or tag named "go1". If no such version exists it
retrieves the most recent version of the package.
For more about specifying packages, see 'go help packages'.
For more about how 'go get' finds source code to
download, see 'go help importpath'.
See also: go build, go install, go clean.
Compile and install packages and dependencies
Usage:
go install [build flags] [packages]
Install compiles and installs the packages named by the import paths,
along with their dependencies.
For more about the build flags, see 'go help build'.
For more about specifying packages, see 'go help packages'.
See also: go build, go get, go clean.
List packages
Usage:
go list [-e] [-f format] [-json] [build flags] [packages]
List lists the packages named by the import paths, one per line.
The default output shows the package import path:
code.google.com/p/google-api-go-client/books/v1
code.google.com/p/goauth2/oauth
code.google.com/p/sqlite
The -f flag specifies an alternate format for the list, using the
syntax of package template. The default output is equivalent to -f
'{{.ImportPath}}'. The struct being passed to the template is:
type Package struct {
Dir string // directory containing package sources
ImportPath string // import path of package in dir
Name string // package name
Doc string // package documentation string
Target string // install path
Goroot bool // is this package in the Go root?
Standard bool // is this package part of the standard Go library?
Stale bool // would 'go install' do anything for this package?
Root string // Go root or Go path dir containing this package
// Source files
GoFiles []string // .go source files (excluding CgoFiles, TestGoFiles, XTestGoFiles)
CgoFiles []string // .go sources files that import "C"
IgnoredGoFiles []string // .go sources ignored due to build constraints
CFiles []string // .c source files
CXXFiles []string // .cc, .cxx and .cpp source files
MFiles []string // .m source files
HFiles []string // .h, .hh, .hpp and .hxx source files
SFiles []string // .s source files
SwigFiles []string // .swig files
SwigCXXFiles []string // .swigcxx files
SysoFiles []string // .syso object files to add to archive
// Cgo directives
CgoCFLAGS []string // cgo: flags for C compiler
CgoCPPFLAGS []string // cgo: flags for C preprocessor
CgoCXXFLAGS []string // cgo: flags for C++ compiler
CgoLDFLAGS []string // cgo: flags for linker
CgoPkgConfig []string // cgo: pkg-config names
// Dependency information
Imports []string // import paths used by this package
Deps []string // all (recursively) imported dependencies
// 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
}
The template function "join" calls strings.Join.
The template function "context" returns the build context, defined as:
type Context struct {
GOARCH string // target architecture
GOOS string // target operating system
GOROOT string // Go root
GOPATH string // Go path
CgoEnabled bool // whether cgo can be used
UseAllFiles bool // use files regardless of +build lines, file names
Compiler string // compiler to assume when computing target paths
BuildTags []string // build constraints to match in +build lines
ReleaseTags []string // releases the current release is compatible with
InstallSuffix string // suffix to use in the name of the install dir
}
For more information about the meaning of these fields see the documentation
for the go/build package's Context type.
The -json flag causes the package data to be printed in JSON format
instead of using the template format.
The -e flag changes the handling of erroneous packages, those that
cannot be found or are malformed. By default, the list command
prints an error to standard error for each erroneous package and
omits the packages from consideration during the usual printing.
With the -e flag, the list command never prints errors to standard
error and instead processes the erroneous packages with the usual
printing. Erroneous packages will have a non-empty ImportPath and
a non-nil Error field; other information may or may not be missing
(zeroed).
For more about build flags, see 'go help build'.
For more about specifying packages, see 'go help packages'.
Compile and run Go program
Usage:
go run [build flags] [-exec xprog] gofiles... [arguments...]
Run compiles and runs the main package comprising the named Go source files.
A Go source file is defined to be a file ending in a literal ".go" suffix.
By default, 'go run' runs the compiled binary directly: 'a.out arguments...'.
If the -exec flag is given, 'go run' invokes the binary using xprog: 'xprog a.out arguments...'.
If the -exec flag is not given, GOOS or GOARCH is different from the system
default, and a program named go_$GOOS_$GOARCH_exec can be found
on the current search path, 'go run' invokes the binary using that program,
for example 'go_nacl_386_exec a.out arguments...'. This allows execution of
cross-compiled programs when a simulator or other execution method is
available.
For more about build flags, see 'go help build'.
See also: go build.
Test packages
Usage:
go test [-c] [-i] [build and test flags] [packages] [flags for test binary]
'Go test' automates testing the packages named by the import paths.
It prints a summary of the test results in the format:
ok archive/tar 0.011s
FAIL archive/zip 0.022s
ok compress/gzip 0.033s
...
followed by detailed output for each failed package.
'Go test' recompiles each package along with any files with names matching
the file pattern "*_test.go".
Files whose names begin with "_" (including "_test.go") or "." are ignored.
These additional files can contain test functions, benchmark functions, and
example functions. See 'go help testfunc' for more.
Each listed package causes the execution of a separate test binary.
Test files that declare a package with the suffix "_test" will be compiled as a
separate package, and then linked and run with the main test binary.
By default, go test needs no arguments. It compiles and tests the package
with source in the current directory, including tests, and runs the tests.
The package is built in a temporary directory so it does not interfere with the
non-test installation.
In addition to the build flags, the flags handled by 'go test' itself are:
-c Compile the test binary to pkg.test but do not run it.
(Where pkg is the last element of the package's import path.)
-i
Install packages that are dependencies of the test.
Do not run the test.
-exec xprog
Run the test binary using xprog. The behavior is the same as
in 'go run'. See 'go help run' for details.
The test binary also accepts flags that control execution of the test; these
flags are also accessible by 'go test'. See 'go help testflag' for details.
If the test binary needs any other flags, they should be presented after the
package names. The go tool treats as a flag the first argument that begins with
a minus sign that it does not recognize itself; that argument and all subsequent
arguments are passed as arguments to the test binary.
For more about build flags, see 'go help build'.
For more about specifying packages, see 'go help packages'.
See also: go build, go vet.
Run specified go tool
Usage:
go tool [-n] command [args...]
Tool runs the go tool command identified by the arguments.
With no arguments it prints the list of known tools.
The -n flag causes tool to print the command that would be
executed but not execute it.
For more about each tool command, see 'go tool command -h'.
Print Go version
Usage:
go version
Version prints the Go version, as reported by runtime.Version.
Run go tool vet on packages
Usage:
go vet [-n] [-x] [packages]
Vet runs the Go vet command on the packages named by the import paths.
For more about vet, see 'godoc code.google.com/p/go.tools/cmd/vet'.
For more about specifying packages, see 'go help packages'.
To run the vet tool with specific options, run 'go tool vet'.
The -n flag prints commands that would be executed.
The -x flag prints commands as they are executed.
See also: go fmt, go fix.
Calling between Go and C
There are two different ways to call between Go and C/C++ code.
The first is the cgo tool, which is part of the Go distribution. For
information on how to use it see the cgo documentation (godoc cmd/cgo).
The second is the SWIG program, which is a general tool for
interfacing between languages. For information on SWIG see
http://swig.org/. When running go build, any file with a .swig
extension will be passed to SWIG. Any file with a .swigcxx extension
will be passed to SWIG with the -c++ option.
When either cgo or SWIG is used, go build will pass any .c, .m, .s,
or .S files to the C compiler, and any .cc, .cpp, .cxx files to the C++
compiler. The CC or CXX environment variables may be set to determine
the C or C++ compiler, respectively, to use.
File types
The go command examines the contents of a restricted set of files
in each directory. It identifies which files to examine based on
the extension of the file name. These extensions are:
.go
Go source files.
.c, .h
C source files.
If the package uses cgo, these will be compiled with the
OS-native compiler (typically gcc); otherwise they will be
compiled with the Go-specific support compiler,
5c, 6c, or 8c, etc. as appropriate.
.cc, .cpp, .cxx, .hh, .hpp, .hxx
C++ source files. Only useful with cgo or SWIG, and always
compiled with the OS-native compiler.
.m
Objective-C source files. Only useful with cgo, and always
compiled with the OS-native compiler.
.s, .S
Assembler source files.
If the package uses cgo, these will be assembled with the
OS-native assembler (typically gcc (sic)); otherwise they
will be assembled with the Go-specific support assembler,
5a, 6a, or 8a, etc., as appropriate.
.swig, .swigcxx
SWIG definition files.
.syso
System object files.
Files of each of these types except .syso may contain build
constraints, but the go command stops scanning for build constraints
at the first item in the file that is not a blank line or //-style
line comment.
GOPATH environment variable
The Go path is used to resolve import statements.
It is implemented by and documented in the go/build package.
The GOPATH environment variable lists places to look for Go code.
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.
Each directory listed in GOPATH must have a prescribed structure:
The src/ directory holds source code. The path below 'src'
determines the import path or executable name.
The pkg/ directory holds installed package objects.
As in the Go tree, each target operating system and
architecture pair has its own subdirectory of pkg
(pkg/GOOS_GOARCH).
If DIR is a directory listed in the GOPATH, a package with
source in DIR/src/foo/bar can be imported as "foo/bar" and
has its compiled form installed to "DIR/pkg/GOOS_GOARCH/foo/bar.a".
The bin/ directory holds compiled commands.
Each command is named for its source directory, but only
the final element, not the entire path. That is, the
command with source in DIR/src/foo/quux is installed into
DIR/bin/quux, not DIR/bin/foo/quux. The foo/ is stripped
so that you can add DIR/bin to your PATH to get at the
installed commands. If the GOBIN environment variable is
set, commands are installed to the directory it names instead
of DIR/bin.
Here's an example directory layout:
GOPATH=/home/user/gocode
/home/user/gocode/
src/
foo/
bar/ (go code in package bar)
x.go
quux/ (go code in package main)
y.go
bin/
quux (installed command)
pkg/
linux_amd64/
foo/
bar.a (installed package object)
Go searches each directory listed in GOPATH to find source code,
but new packages are always downloaded into the first directory
in the list.
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').
Relative import paths
An import path beginning with ./ or ../ is called a relative path.
The toolchain supports relative import paths as a shortcut in two ways.
First, a relative path can be used as a shorthand on the command line.
If you are working in the directory containing the code imported as
"unicode" and want to run the tests for "unicode/utf8", you can type
"go test ./utf8" instead of needing to specify the full path.
Similarly, in the reverse situation, "go test .." will test "unicode" from
the "unicode/utf8" directory. Relative patterns are also allowed, like
"go test ./..." to test all subdirectories. See 'go help packages' for details
on the pattern syntax.
Second, if you are compiling a Go program not in a work space,
you can use a relative path in an import statement in that program
to refer to nearby code also not in a work space.
This makes it easy to experiment with small multipackage programs
outside of the usual work spaces, but such programs cannot be
installed with "go install" (there is no work space in which to install them),
so they are rebuilt from scratch each time they are built.
To avoid ambiguity, Go programs cannot use relative import paths
within a work space.
Remote import paths
Certain import paths also
describe how to obtain the source code for the package using
a revision control system.
A few common code hosting sites have special syntax:
Bitbucket (Git, Mercurial)
import "bitbucket.org/user/project"
import "bitbucket.org/user/project/sub/directory"
GitHub (Git)
import "github.com/user/project"
import "github.com/user/project/sub/directory"
Google Code Project Hosting (Git, Mercurial, Subversion)
import "code.google.com/p/project"
import "code.google.com/p/project/sub/directory"
import "code.google.com/p/project.subrepository"
import "code.google.com/p/project.subrepository/sub/directory"
Launchpad (Bazaar)
import "launchpad.net/project"
import "launchpad.net/project/series"
import "launchpad.net/project/series/sub/directory"
import "launchpad.net/~user/project/branch"
import "launchpad.net/~user/project/branch/sub/directory"
For code hosted on other servers, import paths may either be qualified
with the version control type, or the go tool can dynamically fetch
the import path over https/http and discover where the code resides
from a <meta> tag in the HTML.
To declare the code location, an import path of the form
repository.vcs/path
specifies the given repository, with or without the .vcs suffix,
using the named version control system, and then the path inside
that repository. The supported version control systems are:
Bazaar .bzr
Git .git
Mercurial .hg
Subversion .svn
For example,
import "example.org/user/foo.hg"
denotes the root directory of the Mercurial repository at
example.org/user/foo or foo.hg, and
import "example.org/repo.git/foo/bar"
denotes the foo/bar directory of the Git repository at
example.org/repo or repo.git.
When a version control system supports multiple protocols,
each is tried in turn when downloading. For example, a Git
download tries git://, then https://, then http://.
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
<head>.
The meta tag has the form:
<meta name="go-import" content="import-prefix vcs repo-root">
The import-prefix is the import path corresponding to the repository
root. It must be a prefix or an exact match of the package being
fetched with "go get". If it's not an exact match, another http
request is made at the prefix to verify the <meta> tags match.
The vcs is one of "git", "hg", "svn", etc,
The repo-root is the root of the version control system
containing a scheme and not containing a .vcs qualifier.
For example,
import "example.org/pkg/foo"
will result in the following request(s):
https://example.org/pkg/foo?go-get=1 (preferred)
http://example.org/pkg/foo?go-get=1 (fallback)
If that page contains the meta tag
<meta name="go-import" content="example.org git https://code.org/r/p/exproj">
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').
The go command attempts to download the version of the
package appropriate for the Go release being used.
Run 'go help install' for more.
Description of package lists
Many commands apply to a set of packages:
go action [packages]
Usually, [packages] is a list of import paths.
An import path that is a rooted path or that begins with
a . or .. element is interpreted as a file system path and
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').
If no import paths are given, the action applies to the
package in the current directory.
There are three reserved names for paths that should not be used
for packages to be built with the go tool:
- "main" denotes the top-level package in a stand-alone executable.
- "all" expands to all package directories found in all the GOPATH
trees. For example, 'go list all' lists all the packages on the local
system.
- "std" is like all but expands to just the packages in the standard
Go library.
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
directories found in the GOPATH trees with names matching the
patterns. As a special case, x/... matches x as well as x's subdirectories.
For example, net/... expands to net and packages in its subdirectories.
An import path can also name a package to be downloaded from
a remote repository. Run 'go help importpath' for details.
Every package in a program must have a unique import path.
By convention, this is arranged by starting each path with a
unique prefix that belongs to you. For example, paths used
internally at Google all begin with 'google', and paths
denoting remote repositories begin with the path to the code,
such as 'code.google.com/p/project'.
As a special case, if the package list is a list of .go files from a
single directory, the command is applied to a single synthesized
package made up of exactly those files, ignoring any build constraints
in those files and ignoring any other files in the directory.
File names that begin with "." or "_" are ignored by the go tool.
Description of testing flags
The 'go test' command takes both flags that apply to 'go test' itself
and flags that apply to the resulting test binary.
Several of the flags control profiling and write an execution profile
suitable for "go tool pprof"; run "go tool pprof help" for more
information. The --alloc_space, --alloc_objects, and --show_bytes
options of pprof control how the information is presented.
The following flags are recognized by the 'go test' command and
control the execution of any test:
-bench regexp
Run benchmarks matching the regular expression.
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.
-blockprofilerate n
Control the detail provided in goroutine blocking profiles by
calling runtime.SetBlockProfileRate with n.
See 'godoc 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.
-cover
Enable coverage analysis.
-covermode set,count,atomic
Set the mode for coverage analysis for the package[s]
being tested. The default is "set" unless -race is enabled,
in which case it is "atomic".
The values:
set: bool: does this statement run?
count: int: how many times does this statement run?
atomic: int: count, but correct in multithreaded tests;
significantly more expensive.
Sets -cover.
-coverpkg pkg1,pkg2,pkg3
Apply coverage analysis in each test to the given list of packages.
The default is for each test to analyze only the package being tested.
Packages are specified as import paths.
Sets -cover.
-coverprofile cover.out
Write a coverage profile to the specified 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.
-memprofile mem.out
Write a memory profile to the specified file after all tests
have passed.
-memprofilerate n
Enable more precise (and expensive) memory profiles by setting
runtime.MemProfileRate. See 'godoc runtime MemProfileRate'.
To profile all memory allocations, use -test.memprofilerate=1
and 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
simultaneously; by default, it is set to the value of GOMAXPROCS.
-run regexp
Run only those tests and examples matching the regular
expression.
-short
Tell long-running tests to shorten their run time.
It is off by default but set during all.bash so that installing
the Go tree can run a sanity check but not spend time running
exhaustive tests.
-timeout t
If a test runs longer than t, panic.
-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 test binary, called pkg.test where pkg is the name of the
directory containing the package sources, can be invoked directly
after building it with 'go test -c'. When invoking the test binary
directly, each of the standard flag names must be prefixed with 'test.',
as in -test.run=TestMyFunc or -test.v.
When running 'go test', flags not listed above are passed through
unaltered. For instance, the command
go test -x -v -cpuprofile=prof.out -dir=testdata -update
will compile the test binary and then run it as
pkg.test -test.v -test.cpuprofile=prof.out -dir=testdata -update
The test flags that generate profiles (other than for coverage) also
leave the test binary in pkg.test for use when analyzing the profiles.
Flags not recognized by 'go test' must be placed after any specified packages.
Description of testing functions
The 'go test' command expects to find test, benchmark, and example functions
in the "*_test.go" files corresponding to the package under test.
A test function is one named TestXXX (where XXX is any alphanumeric string
not starting with a lower case letter) and should have the signature,
func TestXXX(t *testing.T) { ... }
A benchmark function is one named BenchmarkXXX and should have the signature,
func BenchmarkXXX(b *testing.B) { ... }
An example function is similar to a test function but, instead of using
*testing.T to report success or failure, prints output to os.Stdout.
That output is compared against the function's "Output:" comment, which
must be the last comment in the function body (see example below). An
example with no such comment, or with no text after "Output:" is compiled
but not executed.
Godoc displays the body of ExampleXXX to demonstrate the use
of the function, constant, or variable XXX. An example of a method M with
receiver type T or *T is named ExampleT_M. There may be multiple examples
for a given function, constant, or variable, distinguished by a trailing _xxx,
where xxx is a suffix not beginning with an upper case letter.
Here is an example of an example:
func ExamplePrintln() {
Println("The output of\nthis example.")
// Output: The output of
// this example.
}
The entire test file is presented as the example when it contains a single
example function, at least one other function, type, variable, or constant
declaration, and no test or benchmark functions.
See the documentation of the testing package for more information.
*/
package main
// Copyright 2012 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 (
"fmt"
"os"
"runtime"
"strings"
)
var cmdEnv = &Command{
Run: runEnv,
UsageLine: "env [var ...]",
Short: "print Go environment information",
Long: `
Env prints Go environment information.
By default env prints information as a shell script
(on Windows, a batch file). If one or more variable
names is given as arguments, env prints the value of
each named variable on its own line.
`,
}
type envVar struct {
name, value string
}
func mkEnv() []envVar {
var b builder
b.init()
env := []envVar{
{"GOARCH", goarch},
{"GOBIN", gobin},
{"GOCHAR", archChar},
{"GOEXE", exeSuffix},
{"GOHOSTARCH", runtime.GOARCH},
{"GOHOSTOS", runtime.GOOS},
{"GOOS", goos},
{"GOPATH", os.Getenv("GOPATH")},
{"GORACE", os.Getenv("GORACE")},
{"GOROOT", goroot},
{"GOTOOLDIR", toolDir},
// disable escape codes in clang errors
{"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 buildContext.CgoEnabled {
env = append(env, envVar{"CGO_ENABLED", "1"})
} else {
env = append(env, envVar{"CGO_ENABLED", "0"})
}
return env
}
func findEnv(env []envVar, name string) string {
for _, e := range env {
if e.name == name {
return e.value
}
}
return ""
}
func runEnv(cmd *Command, args []string) {
env := mkEnv()
if len(args) > 0 {
for _, name := range args {
fmt.Printf("%s\n", findEnv(env, name))
}
return
}
for _, e := range env {
if e.name != "TERM" {
switch runtime.GOOS {
default:
fmt.Printf("%s=\"%s\"\n", e.name, e.value)
case "plan9":
if strings.IndexByte(e.value, '\x00') < 0 {
fmt.Printf("%s='%s'\n", e.name, strings.Replace(e.value, "'", "''", -1))
} else {
v := strings.Split(e.value, "\x00")
fmt.Printf("%s=(", e.name)
for x, s := range v {
if x > 0 {
fmt.Printf(" ")
}
fmt.Printf("%s", s)
}
fmt.Printf(")\n")
}
case "windows":
fmt.Printf("set %s=%s\n", e.name, e.value)
}
}
}
}
// Copyright 2011 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
var cmdFix = &Command{
Run: runFix,
UsageLine: "fix [packages]",
Short: "run go tool fix on packages",
Long: `
Fix runs the Go fix command on the packages named by the import paths.
For more about fix, see 'godoc fix'.
For more about specifying packages, see 'go help packages'.
To run fix with specific options, run 'go tool fix'.
See also: go fmt, go vet.
`,
}
func runFix(cmd *Command, args []string) {
for _, pkg := range packages(args) {
// Use pkg.gofiles instead of pkg.Dir so that
// the command only applies to this package,
// not to packages in subdirectories.
run(stringList(tool("fix"), relPaths(pkg.allgofiles)))
}
}
// Copyright 2011 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
func init() {
addBuildFlagsNX(cmdFmt)
}
var cmdFmt = &Command{
Run: runFmt,
UsageLine: "fmt [-n] [-x] [packages]",
Short: "run gofmt on package sources",
Long: `
Fmt runs the command 'gofmt -l -w' on the packages named
by the import paths. It prints the names of the files that are modified.
For more about gofmt, see 'godoc gofmt'.
For more about specifying packages, see 'go help packages'.
The -n flag prints commands that would be executed.
The -x flag prints commands as they are executed.
To run gofmt with specific options, run gofmt itself.
See also: go fix, go vet.
`,
}
func runFmt(cmd *Command, args []string) {
for _, pkg := range packages(args) {
// Use pkg.gofiles instead of pkg.Dir so that
// the command only applies to this package,
// not to packages in subdirectories.
run(stringList("gofmt", "-l", "-w", relPaths(pkg.allgofiles)))
}
}
// Copyright 2011 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 (
"fmt"
"go/build"
"os"
"path/filepath"
"regexp"
"runtime"
"strconv"
"strings"
)
var cmdGet = &Command{
UsageLine: "get [-d] [-fix] [-t] [-u] [build flags] [packages]",
Short: "download and install packages and dependencies",
Long: `
Get downloads and installs the packages named by the import paths,
along with their dependencies.
The -d flag instructs get to stop after downloading the packages; that is,
it instructs get not to install the packages.
The -fix flag instructs get to run the fix tool on the downloaded packages
before resolving dependencies or building the code.
The -t flag instructs get to also download the packages required to build
the tests for the specified packages.
The -u flag instructs get to use the network to update the named packages
and their dependencies. By default, get uses the network to check out
missing packages but does not use it to look for updates to existing packages.
Get also accepts build flags to control the installation. See 'go help build'.
When checking out or updating a package, get looks for a branch or tag
that matches the locally installed version of Go. The most important
rule is that if the local installation is running version "go1", get
searches for a branch or tag named "go1". If no such version exists it
retrieves the most recent version of the package.
For more about specifying packages, see 'go help packages'.
For more about how 'go get' finds source code to
download, see 'go help importpath'.
See also: go build, go install, go clean.
`,
}
var getD = cmdGet.Flag.Bool("d", false, "")
var getT = cmdGet.Flag.Bool("t", false, "")
var getU = cmdGet.Flag.Bool("u", false, "")
var getFix = cmdGet.Flag.Bool("fix", false, "")
func init() {
addBuildFlags(cmdGet)
cmdGet.Run = runGet // break init loop
}
func runGet(cmd *Command, args []string) {
// Phase 1. Download/update.
var stk importStack
for _, arg := range downloadPaths(args) {
download(arg, &stk, *getT)
}
exitIfErrors()
// Phase 2. Rescan packages and re-evaluate args list.
// Code we downloaded and all code that depends on it
// needs to be evicted from the package cache so that
// the information will be recomputed. Instead of keeping
// track of the reverse dependency information, evict
// everything.
for name := range packageCache {
delete(packageCache, name)
}
args = importPaths(args)
// Phase 3. Install.
if *getD {
// Download only.
// Check delayed until now so that importPaths
// has a chance to print errors.
return
}
runInstall(cmd, args)
}
// downloadPaths prepares the list of paths to pass to download.
// It expands ... patterns that can be expanded. If there is no match
// for a particular pattern, downloadPaths leaves it in the result list,
// in the hope that we can figure out the repository from the
// initial ...-free prefix.
func downloadPaths(args []string) []string {
args = importPathsNoDotExpansion(args)
var out []string
for _, a := range args {
if strings.Contains(a, "...") {
var expand []string
// Use matchPackagesInFS to avoid printing
// warnings. They will be printed by the
// eventual call to importPaths instead.
if build.IsLocalImport(a) {
expand = matchPackagesInFS(a)
} else {
expand = matchPackages(a)
}
if len(expand) > 0 {
out = append(out, expand...)
continue
}
}
out = append(out, a)
}
return out
}
// downloadCache records the import paths we have already
// considered during the download, to avoid duplicate work when
// there is more than one dependency sequence leading to
// a particular package.
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
// 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{}
// download runs the download half of the get command
// for the package named by the argument.
func download(arg string, stk *importStack, getTestDeps bool) {
p := loadPackage(arg, stk)
if p.Error != nil && p.Error.hard {
errorf("%s", p.Error)
return
}
// There's nothing to do if this is a package in the standard library.
if p.Standard {
return
}
// Only process each package once.
if downloadCache[arg] {
return
}
downloadCache[arg] = true
pkgs := []*Package{p}
wildcardOkay := len(*stk) == 0
isWildcard := false
// Download if the package is missing, or update if we're using -u.
if p.Dir == "" || *getU {
// The actual download.
stk.push(p.ImportPath)
err := downloadPackage(p)
if err != nil {
errorf("%s", &PackageError{ImportStack: stk.copy(), Err: err.Error()})
stk.pop()
return
}
args := []string{arg}
// If the argument has a wildcard in it, re-evaluate the wildcard.
// We delay this until after reloadPackage so that the old entry
// for p has been replaced in the package cache.
if wildcardOkay && strings.Contains(arg, "...") {
if build.IsLocalImport(arg) {
args = matchPackagesInFS(arg)
} else {
args = matchPackages(arg)
}
isWildcard = true
}
// Clear all relevant package cache entries before
// doing any new loads.
for _, arg := range args {
p := packageCache[arg]
if p != nil {
delete(packageCache, p.Dir)
delete(packageCache, p.ImportPath)
}
}
pkgs = pkgs[:0]
for _, arg := range args {
stk.push(arg)
p := loadPackage(arg, stk)
stk.pop()
if p.Error != nil {
errorf("%s", p.Error)
continue
}
pkgs = append(pkgs, p)
}
}
// Process package, which might now be multiple packages
// due to wildcard expansion.
for _, p := range pkgs {
if *getFix {
run(stringList(tool("fix"), relPaths(p.allgofiles)))
// The imports might have changed, so reload again.
p = reloadPackage(arg, stk)
if p.Error != nil {
errorf("%s", p.Error)
return
}
}
if isWildcard {
// Report both the real package and the
// wildcard in any error message.
stk.push(p.ImportPath)
}
// Process dependencies, now that we know what they are.
for _, dep := range p.deps {
// Don't get test dependencies recursively.
download(dep.ImportPath, stk, false)
}
if getTestDeps {
// Process test dependencies when -t is specified.
// (Don't get test dependencies for test dependencies.)
for _, path := range p.TestImports {
download(path, stk, false)
}
for _, path := range p.XTestImports {
download(path, stk, false)
}
}
if isWildcard {
stk.pop()
}
}
}
// downloadPackage runs the create or download command
// to make the first copy of or update a copy of the given package.
func downloadPackage(p *Package) error {
var (
vcs *vcsCmd
repo, rootPath string
err error
)
if p.build.SrcRoot != "" {
// Directory exists. Look for checkout along path to src.
vcs, rootPath, err = vcsForDir(p)
if err != nil {
return err
}
repo = "<local>" // should be unused; make distinctive
} else {
// Analyze the import path to determine the version control system,
// repository, and the import path for the root of the repository.
rr, err := repoRootForImportPath(p.ImportPath)
if err != nil {
return err
}
vcs, repo, rootPath = rr.vcs, rr.repo, rr.root
}
if p.build.SrcRoot == "" {
// 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")
}
// 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")
}
p.build.SrcRoot = filepath.Join(list[0], "src")
p.build.PkgRoot = filepath.Join(list[0], "pkg")
}
root := filepath.Join(p.build.SrcRoot, rootPath)
// If we've considered this repository already, don't do it again.
if downloadRootCache[root] {
return nil
}
downloadRootCache[root] = true
if buildV {
fmt.Fprintf(os.Stderr, "%s (download)\n", rootPath)
}
// Check that this is an appropriate place for the repo to be checked out.
// The target directory must either not exist or have a repo checked out already.
meta := filepath.Join(root, "."+vcs.cmd)
st, err := os.Stat(meta)
if err == nil && !st.IsDir() {
return fmt.Errorf("%s exists but is not a directory", meta)
}
if err != nil {
// Metadata directory does not exist. Prepare to checkout new copy.
// Some version control tools require the target directory not to exist.
// We require that too, just to avoid stepping on existing work.
if _, err := os.Stat(root); err == nil {
return fmt.Errorf("%s exists but %s does not - stale checkout?", root, meta)
}
// 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 err = vcs.create(root, repo); err != nil {
return err
}
} else {
// Metadata directory does exist; download incremental updates.
if err = vcs.download(root); err != nil {
return err
}
}
if buildN {
// Do not show tag sync in -n; it's noise more than anything,
// and since we're not running commands, no tag will be found.
// But avoid printing nothing.
fmt.Fprintf(os.Stderr, "# cd %s; %s sync/update\n", root, vcs.cmd)
return nil
}
// Select and sync to appropriate version of the repository.
tags, err := vcs.tags(root)
if err != nil {
return err
}
vers := runtime.Version()
if i := strings.Index(vers, " "); i >= 0 {
vers = vers[:i]
}
if err := vcs.tagSync(root, selectTag(vers, tags)); err != nil {
return err
}
return nil
}
// goTag matches go release tags such as go1 and go1.2.3.
// The numbers involved must be small (at most 4 digits),
// have no unnecessary leading zeros, and the version cannot
// end in .0 - it is go1, not go1.0 or go1.0.0.
var goTag = regexp.MustCompile(
`^go((0|[1-9][0-9]{0,3})\.)*([1-9][0-9]{0,3})$`,
)
// selectTag returns the closest matching tag for a given version.
// Closest means the latest one that is not after the current release.
// Version "goX" (or "goX.Y" or "goX.Y.Z") matches tags of the same form.
// Version "release.rN" matches tags of the form "go.rN" (N being a floating-point number).
// Version "weekly.YYYY-MM-DD" matches tags like "go.weekly.YYYY-MM-DD".
//
// NOTE(rsc): Eventually we will need to decide on some logic here.
// For now, there is only "go1". This matches the docs in go help get.
func selectTag(goVersion string, tags []string) (match string) {
for _, t := range tags {
if t == "go1" {
return "go1"
}
}
return ""
/*
if goTag.MatchString(goVersion) {
v := goVersion
for _, t := range tags {
if !goTag.MatchString(t) {
continue
}
if cmpGoVersion(match, t) < 0 && cmpGoVersion(t, v) <= 0 {
match = t
}
}
}
return match
*/
}
// cmpGoVersion returns -1, 0, +1 reporting whether
// x < y, x == y, or x > y.
func cmpGoVersion(x, y string) int {
// Malformed strings compare less than well-formed strings.
if !goTag.MatchString(x) {
return -1
}
if !goTag.MatchString(y) {
return +1
}
// Compare numbers in sequence.
xx := strings.Split(x[len("go"):], ".")
yy := strings.Split(y[len("go"):], ".")
for i := 0; i < len(xx) && i < len(yy); i++ {
// The Atoi are guaranteed to succeed
// because the versions match goTag.
xi, _ := strconv.Atoi(xx[i])
yi, _ := strconv.Atoi(yy[i])
if xi < yi {
return -1
} else if xi > yi {
return +1
}
}
if len(xx) < len(yy) {
return -1
}
if len(xx) > len(yy) {
return +1
}
return 0
}
// Copyright 2013 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 go1.1
package main
// Test that go1.1 tag above is included in builds. main.go refers to this definition.
const go11tag = true
// Copyright 2011 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
var helpC = &Command{
UsageLine: "c",
Short: "calling between Go and C",
Long: `
There are two different ways to call between Go and C/C++ code.
The first is the cgo tool, which is part of the Go distribution. For
information on how to use it see the cgo documentation (godoc cmd/cgo).
The second is the SWIG program, which is a general tool for
interfacing between languages. For information on SWIG see
http://swig.org/. When running go build, any file with a .swig
extension will be passed to SWIG. Any file with a .swigcxx extension
will be passed to SWIG with the -c++ option.
When either cgo or SWIG is used, go build will pass any .c, .m, .s,
or .S files to the C compiler, and any .cc, .cpp, .cxx files to the C++
compiler. The CC or CXX environment variables may be set to determine
the C or C++ compiler, respectively, to use.
`,
}
var helpPackages = &Command{
UsageLine: "packages",
Short: "description of package lists",
Long: `
Many commands apply to a set of packages:
go action [packages]
Usually, [packages] is a list of import paths.
An import path that is a rooted path or that begins with
a . or .. element is interpreted as a file system path and
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').
If no import paths are given, the action applies to the
package in the current directory.
There are three reserved names for paths that should not be used
for packages to be built with the go tool:
- "main" denotes the top-level package in a stand-alone executable.
- "all" expands to all package directories found in all the GOPATH
trees. For example, 'go list all' lists all the packages on the local
system.
- "std" is like all but expands to just the packages in the standard
Go library.
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
directories found in the GOPATH trees with names matching the
patterns. As a special case, x/... matches x as well as x's subdirectories.
For example, net/... expands to net and packages in its subdirectories.
An import path can also name a package to be downloaded from
a remote repository. Run 'go help importpath' for details.
Every package in a program must have a unique import path.
By convention, this is arranged by starting each path with a
unique prefix that belongs to you. For example, paths used
internally at Google all begin with 'google', and paths
denoting remote repositories begin with the path to the code,
such as 'code.google.com/p/project'.
As a special case, if the package list is a list of .go files from a
single directory, the command is applied to a single synthesized
package made up of exactly those files, ignoring any build constraints
in those files and ignoring any other files in the directory.
File names that begin with "." or "_" are ignored by the go tool.
`,
}
var helpImportPath = &Command{
UsageLine: "importpath",
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').
Relative import paths
An import path beginning with ./ or ../ is called a relative path.
The toolchain supports relative import paths as a shortcut in two ways.
First, a relative path can be used as a shorthand on the command line.
If you are working in the directory containing the code imported as
"unicode" and want to run the tests for "unicode/utf8", you can type
"go test ./utf8" instead of needing to specify the full path.
Similarly, in the reverse situation, "go test .." will test "unicode" from
the "unicode/utf8" directory. Relative patterns are also allowed, like
"go test ./..." to test all subdirectories. See 'go help packages' for details
on the pattern syntax.
Second, if you are compiling a Go program not in a work space,
you can use a relative path in an import statement in that program
to refer to nearby code also not in a work space.
This makes it easy to experiment with small multipackage programs
outside of the usual work spaces, but such programs cannot be
installed with "go install" (there is no work space in which to install them),
so they are rebuilt from scratch each time they are built.
To avoid ambiguity, Go programs cannot use relative import paths
within a work space.
Remote import paths
Certain import paths also
describe how to obtain the source code for the package using
a revision control system.
A few common code hosting sites have special syntax:
Bitbucket (Git, Mercurial)
import "bitbucket.org/user/project"
import "bitbucket.org/user/project/sub/directory"
GitHub (Git)
import "github.com/user/project"
import "github.com/user/project/sub/directory"
Google Code Project Hosting (Git, Mercurial, Subversion)
import "code.google.com/p/project"
import "code.google.com/p/project/sub/directory"
import "code.google.com/p/project.subrepository"
import "code.google.com/p/project.subrepository/sub/directory"
Launchpad (Bazaar)
import "launchpad.net/project"
import "launchpad.net/project/series"
import "launchpad.net/project/series/sub/directory"
import "launchpad.net/~user/project/branch"
import "launchpad.net/~user/project/branch/sub/directory"
For code hosted on other servers, import paths may either be qualified
with the version control type, or the go tool can dynamically fetch
the import path over https/http and discover where the code resides
from a <meta> tag in the HTML.
To declare the code location, an import path of the form
repository.vcs/path
specifies the given repository, with or without the .vcs suffix,
using the named version control system, and then the path inside
that repository. The supported version control systems are:
Bazaar .bzr
Git .git
Mercurial .hg
Subversion .svn
For example,
import "example.org/user/foo.hg"
denotes the root directory of the Mercurial repository at
example.org/user/foo or foo.hg, and
import "example.org/repo.git/foo/bar"
denotes the foo/bar directory of the Git repository at
example.org/repo or repo.git.
When a version control system supports multiple protocols,
each is tried in turn when downloading. For example, a Git
download tries git://, then https://, then http://.
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
<head>.
The meta tag has the form:
<meta name="go-import" content="import-prefix vcs repo-root">
The import-prefix is the import path corresponding to the repository
root. It must be a prefix or an exact match of the package being
fetched with "go get". If it's not an exact match, another http
request is made at the prefix to verify the <meta> tags match.
The vcs is one of "git", "hg", "svn", etc,
The repo-root is the root of the version control system
containing a scheme and not containing a .vcs qualifier.
For example,
import "example.org/pkg/foo"
will result in the following request(s):
https://example.org/pkg/foo?go-get=1 (preferred)
http://example.org/pkg/foo?go-get=1 (fallback)
If that page contains the meta tag
<meta name="go-import" content="example.org git https://code.org/r/p/exproj">
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').
The go command attempts to download the version of the
package appropriate for the Go release being used.
Run 'go help install' for more.
`,
}
var helpGopath = &Command{
UsageLine: "gopath",
Short: "GOPATH environment variable",
Long: `
The Go path is used to resolve import statements.
It is implemented by and documented in the go/build package.
The GOPATH environment variable lists places to look for Go code.
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.
Each directory listed in GOPATH must have a prescribed structure:
The src/ directory holds source code. The path below 'src'
determines the import path or executable name.
The pkg/ directory holds installed package objects.
As in the Go tree, each target operating system and
architecture pair has its own subdirectory of pkg
(pkg/GOOS_GOARCH).
If DIR is a directory listed in the GOPATH, a package with
source in DIR/src/foo/bar can be imported as "foo/bar" and
has its compiled form installed to "DIR/pkg/GOOS_GOARCH/foo/bar.a".
The bin/ directory holds compiled commands.
Each command is named for its source directory, but only
the final element, not the entire path. That is, the
command with source in DIR/src/foo/quux is installed into
DIR/bin/quux, not DIR/bin/foo/quux. The foo/ is stripped
so that you can add DIR/bin to your PATH to get at the
installed commands. If the GOBIN environment variable is
set, commands are installed to the directory it names instead
of DIR/bin.
Here's an example directory layout:
GOPATH=/home/user/gocode
/home/user/gocode/
src/
foo/
bar/ (go code in package bar)
x.go
quux/ (go code in package main)
y.go
bin/
quux (installed command)
pkg/
linux_amd64/
foo/
bar.a (installed package object)
Go searches each directory listed in GOPATH to find source code,
but new packages are always downloaded into the first directory
in the list.
`,
}
var helpFileType = &Command{
UsageLine: "filetype",
Short: "file types",
Long: `
The go command examines the contents of a restricted set of files
in each directory. It identifies which files to examine based on
the extension of the file name. These extensions are:
.go
Go source files.
.c, .h
C source files.
If the package uses cgo, these will be compiled with the
OS-native compiler (typically gcc); otherwise they will be
compiled with the Go-specific support compiler,
5c, 6c, or 8c, etc. as appropriate.
.cc, .cpp, .cxx, .hh, .hpp, .hxx
C++ source files. Only useful with cgo or SWIG, and always
compiled with the OS-native compiler.
.m
Objective-C source files. Only useful with cgo, and always
compiled with the OS-native compiler.
.s, .S
Assembler source files.
If the package uses cgo, these will be assembled with the
OS-native assembler (typically gcc (sic)); otherwise they
will be assembled with the Go-specific support assembler,
5a, 6a, or 8a, etc., as appropriate.
.swig, .swigcxx
SWIG definition files.
.syso
System object files.
Files of each of these types except .syso may contain build
constraints, but the go command stops scanning for build constraints
at the first item in the file that is not a blank line or //-style
line comment.
`,
}
// Copyright 2012 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 !cmd_go_bootstrap
// This code is compiled into the real 'go' binary, but it is not
// compiled into the binary that is built during all.bash, so as
// to avoid needing to build net (and thus use cgo) during the
// bootstrap process.
package main
import (
"fmt"
"io"
"io/ioutil"
"log"
"net/http"
"net/url"
)
// httpClient is the default HTTP client, but a variable so it can be
// changed by tests, without modifying http.DefaultClient.
var httpClient = http.DefaultClient
// httpGET returns the data from an HTTP GET request for the given URL.
func httpGET(url string) ([]byte, error) {
resp, err := httpClient.Get(url)
if err != nil {
return nil, err
}
defer resp.Body.Close()
if resp.StatusCode != 200 {
return nil, fmt.Errorf("%s: %s", url, resp.Status)
}
b, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, fmt.Errorf("%s: %v", url, err)
}
return b, nil
}
// httpsOrHTTP returns the body of either the importPath's
// https resource or, if unavailable, the http resource.
func httpsOrHTTP(importPath string) (urlStr string, body io.ReadCloser, err error) {
fetch := func(scheme string) (urlStr string, res *http.Response, err error) {
u, err := url.Parse(scheme + "://" + importPath)
if err != nil {
return "", nil, err
}
u.RawQuery = "go-get=1"
urlStr = u.String()
if buildV {
log.Printf("Fetching %s", urlStr)
}
res, err = httpClient.Get(urlStr)
return
}
closeBody := func(res *http.Response) {
if res != nil {
res.Body.Close()
}
}
urlStr, res, err := fetch("https")
if err != nil || res.StatusCode != 200 {
if buildV {
if err != nil {
log.Printf("https fetch failed.")
} else {
log.Printf("ignoring https fetch with status code %d", res.StatusCode)
}
}
closeBody(res)
urlStr, res, err = fetch("http")
}
if err != nil {
closeBody(res)
return "", nil, err
}
// Note: accepting a non-200 OK here, so people can serve a
// meta import in their http 404 page.
if buildV {
log.Printf("Parsing meta tags from %s (status code %d)", urlStr, res.StatusCode)
}
return urlStr, res.Body, nil
}
// Copyright 2011 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 (
"bufio"
"encoding/json"
"io"
"os"
"strings"
"text/template"
)
var cmdList = &Command{
UsageLine: "list [-e] [-f format] [-json] [build flags] [packages]",
Short: "list packages",
Long: `
List lists the packages named by the import paths, one per line.
The default output shows the package import path:
code.google.com/p/google-api-go-client/books/v1
code.google.com/p/goauth2/oauth
code.google.com/p/sqlite
The -f flag specifies an alternate format for the list, using the
syntax of package template. The default output is equivalent to -f
'{{.ImportPath}}'. The struct being passed to the template is:
type Package struct {
Dir string // directory containing package sources
ImportPath string // import path of package in dir
Name string // package name
Doc string // package documentation string
Target string // install path
Goroot bool // is this package in the Go root?
Standard bool // is this package part of the standard Go library?
Stale bool // would 'go install' do anything for this package?
Root string // Go root or Go path dir containing this package
// Source files
GoFiles []string // .go source files (excluding CgoFiles, TestGoFiles, XTestGoFiles)
CgoFiles []string // .go sources files that import "C"
IgnoredGoFiles []string // .go sources ignored due to build constraints
CFiles []string // .c source files
CXXFiles []string // .cc, .cxx and .cpp source files
MFiles []string // .m source files
HFiles []string // .h, .hh, .hpp and .hxx source files
SFiles []string // .s source files
SwigFiles []string // .swig files
SwigCXXFiles []string // .swigcxx files
SysoFiles []string // .syso object files to add to archive
// Cgo directives
CgoCFLAGS []string // cgo: flags for C compiler
CgoCPPFLAGS []string // cgo: flags for C preprocessor
CgoCXXFLAGS []string // cgo: flags for C++ compiler
CgoLDFLAGS []string // cgo: flags for linker
CgoPkgConfig []string // cgo: pkg-config names
// Dependency information
Imports []string // import paths used by this package
Deps []string // all (recursively) imported dependencies
// 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
}
The template function "join" calls strings.Join.
The template function "context" returns the build context, defined as:
type Context struct {
GOARCH string // target architecture
GOOS string // target operating system
GOROOT string // Go root
GOPATH string // Go path
CgoEnabled bool // whether cgo can be used
UseAllFiles bool // use files regardless of +build lines, file names
Compiler string // compiler to assume when computing target paths
BuildTags []string // build constraints to match in +build lines
ReleaseTags []string // releases the current release is compatible with
InstallSuffix string // suffix to use in the name of the install dir
}
For more information about the meaning of these fields see the documentation
for the go/build package's Context type.
The -json flag causes the package data to be printed in JSON format
instead of using the template format.
The -e flag changes the handling of erroneous packages, those that
cannot be found or are malformed. By default, the list command
prints an error to standard error for each erroneous package and
omits the packages from consideration during the usual printing.
With the -e flag, the list command never prints errors to standard
error and instead processes the erroneous packages with the usual
printing. Erroneous packages will have a non-empty ImportPath and
a non-nil Error field; other information may or may not be missing
(zeroed).
For more about build flags, see 'go help build'.
For more about specifying packages, see 'go help packages'.
`,
}
func init() {
cmdList.Run = runList // break init cycle
addBuildFlags(cmdList)
}
var listE = cmdList.Flag.Bool("e", false, "")
var listFmt = cmdList.Flag.String("f", "{{.ImportPath}}", "")
var listJson = cmdList.Flag.Bool("json", false, "")
var nl = []byte{'\n'}
func runList(cmd *Command, args []string) {
out := newTrackingWriter(os.Stdout)
defer out.w.Flush()
var do func(*Package)
if *listJson {
do = func(p *Package) {
b, err := json.MarshalIndent(p, "", "\t")
if err != nil {
out.Flush()
fatalf("%s", err)
}
out.Write(b)
out.Write(nl)
}
} else {
var cachedCtxt *Context
context := func() *Context {
if cachedCtxt == nil {
cachedCtxt = newContext(&buildContext)
}
return cachedCtxt
}
fm := template.FuncMap{
"join": strings.Join,
"context": context,
}
tmpl, err := template.New("main").Funcs(fm).Parse(*listFmt)
if err != nil {
fatalf("%s", err)
}
do = func(p *Package) {
if err := tmpl.Execute(out, p); err != nil {
out.Flush()
fatalf("%s", err)
}
if out.NeedNL() {
out.Write(nl)
}
}
}
load := packages
if *listE {
load = packagesAndErrors
}
for _, pkg := range load(args) {
do(pkg)
}
}
// TrackingWriter tracks the last byte written on every write so
// we can avoid printing a newline if one was already written or
// if there is no output at all.
type TrackingWriter struct {
w *bufio.Writer
last byte
}
func newTrackingWriter(w io.Writer) *TrackingWriter {
return &TrackingWriter{
w: bufio.NewWriter(w),
last: '\n',
}
}
func (t *TrackingWriter) Write(p []byte) (n int, err error) {
n, err = t.w.Write(p)
if n > 0 {
t.last = p[n-1]
}
return
}
func (t *TrackingWriter) Flush() {
t.w.Flush()
}
func (t *TrackingWriter) NeedNL() bool {
return t.last != '\n'
}
// Copyright 2011 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"
"flag"
"fmt"
"go/build"
"io"
"log"
"os"
"os/exec"
"path"
"path/filepath"
"regexp"
"runtime"
"strings"
"sync"
"text/template"
"unicode"
"unicode/utf8"
)
// A Command is an implementation of a go command
// like go build or go fix.
type Command struct {
// Run runs the command.
// The args are the arguments after the command name.
Run func(cmd *Command, args []string)
// UsageLine is the one-line usage message.
// The first word in the line is taken to be the command name.
UsageLine string
// Short is the short description shown in the 'go help' output.
Short string
// Long is the long message shown in the 'go help <this-command>' output.
Long string
// Flag is a set of flags specific to this command.
Flag flag.FlagSet
// CustomFlags indicates that the command will do its own
// flag parsing.
CustomFlags bool
}
// Name returns the command's name: the first word in the usage line.
func (c *Command) Name() string {
name := c.UsageLine
i := strings.Index(name, " ")
if i >= 0 {
name = name[:i]
}
return name
}
func (c *Command) Usage() {
fmt.Fprintf(os.Stderr, "usage: %s\n\n", c.UsageLine)
fmt.Fprintf(os.Stderr, "%s\n", strings.TrimSpace(c.Long))
os.Exit(2)
}
// Runnable reports whether the command can be run; otherwise
// it is a documentation pseudo-command such as importpath.
func (c *Command) Runnable() bool {
return c.Run != nil
}
// Commands lists the available commands and help topics.
// The order here is the order in which they are printed by 'go help'.
var commands = []*Command{
cmdBuild,
cmdClean,
cmdEnv,
cmdFix,
cmdFmt,
cmdGet,
cmdInstall,
cmdList,
cmdRun,
cmdTest,
cmdTool,
cmdVersion,
cmdVet,
helpC,
helpFileType,
helpGopath,
helpImportPath,
helpPackages,
helpTestflag,
helpTestfunc,
}
var exitStatus = 0
var exitMu sync.Mutex
func setExitStatus(n int) {
exitMu.Lock()
if exitStatus < n {
exitStatus = n
}
exitMu.Unlock()
}
func main() {
_ = go11tag
flag.Usage = usage
flag.Parse()
log.SetFlags(0)
args := flag.Args()
if len(args) < 1 {
usage()
}
if args[0] == "help" {
help(args[1:])
return
}
// 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() {
fmt.Fprintf(os.Stderr, "warning: GOPATH set to GOROOT (%s) has no effect\n", gopath)
} else {
for _, p := range filepath.SplitList(gopath) {
// Note: using HasPrefix instead of Contains because a ~ can appear
// in the middle of directory elements, such as /tmp/git-1.8.2~rc3
// or C:\PROGRA~1. Only ~ as a path prefix has meaning to the shell.
if strings.HasPrefix(p, "~") {
fmt.Fprintf(os.Stderr, "go: GOPATH entry cannot start with shell metacharacter '~': %q\n", p)
os.Exit(2)
}
if build.IsLocalImport(p) {
fmt.Fprintf(os.Stderr, "go: GOPATH entry is relative; must be absolute path: %q.\nRun 'go help gopath' for usage.\n", p)
os.Exit(2)
}
}
}
if fi, err := os.Stat(goroot); err != nil || !fi.IsDir() {
fmt.Fprintf(os.Stderr, "go: cannot find GOROOT directory: %v\n", goroot)
os.Exit(2)
}
for _, cmd := range commands {
if cmd.Name() == args[0] && cmd.Run != nil {
cmd.Flag.Usage = func() { cmd.Usage() }
if cmd.CustomFlags {
args = args[1:]
} else {
cmd.Flag.Parse(args[1:])
args = cmd.Flag.Args()
}
cmd.Run(cmd, args)
exit()
return
}
}
fmt.Fprintf(os.Stderr, "go: unknown subcommand %q\nRun 'go help' for usage.\n", args[0])
setExitStatus(2)
exit()
}
var usageTemplate = `Go is a tool for managing Go source code.
Usage:
go command [arguments]
The commands are:
{{range .}}{{if .Runnable}}
{{.Name | printf "%-11s"}} {{.Short}}{{end}}{{end}}
Use "go help [command]" for more information about a command.
Additional help topics:
{{range .}}{{if not .Runnable}}
{{.Name | printf "%-11s"}} {{.Short}}{{end}}{{end}}
Use "go help [topic]" for more information about that topic.
`
var helpTemplate = `{{if .Runnable}}usage: go {{.UsageLine}}
{{end}}{{.Long | trim}}
`
var documentationTemplate = `// Copyright 2011 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.
// DO NOT EDIT THIS FILE. GENERATED BY mkdoc.sh.
// Edit the documentation in other files and rerun mkdoc.sh to generate this one.
/*
{{range .}}{{if .Short}}{{.Short | capitalize}}
{{end}}{{if .Runnable}}Usage:
go {{.UsageLine}}
{{end}}{{.Long | trim}}
{{end}}*/
package main
`
// tmpl executes the given template text on data, writing the result to w.
func tmpl(w io.Writer, text string, data interface{}) {
t := template.New("top")
t.Funcs(template.FuncMap{"trim": strings.TrimSpace, "capitalize": capitalize})
template.Must(t.Parse(text))
if err := t.Execute(w, data); err != nil {
panic(err)
}
}
func capitalize(s string) string {
if s == "" {
return s
}
r, n := utf8.DecodeRuneInString(s)
return string(unicode.ToTitle(r)) + s[n:]
}
func printUsage(w io.Writer) {
tmpl(w, usageTemplate, commands)
}
func usage() {
// special case "go test -h"
if len(os.Args) > 1 && os.Args[1] == "test" {
help([]string{"testflag"})
os.Exit(2)
}
printUsage(os.Stderr)
os.Exit(2)
}
// help implements the 'help' command.
func help(args []string) {
if len(args) == 0 {
printUsage(os.Stdout)
// not exit 2: succeeded at 'go help'.
return
}
if len(args) != 1 {
fmt.Fprintf(os.Stderr, "usage: go help command\n\nToo many arguments given.\n")
os.Exit(2) // failed at 'go help'
}
arg := args[0]
// 'go help documentation' generates doc.go.
if arg == "documentation" {
buf := new(bytes.Buffer)
printUsage(buf)
usage := &Command{Long: buf.String()}
tmpl(os.Stdout, documentationTemplate, append([]*Command{usage}, commands...))
return
}
for _, cmd := range commands {
if cmd.Name() == arg {
tmpl(os.Stdout, helpTemplate, cmd)
// not exit 2: succeeded at 'go help cmd'.
return
}
}
fmt.Fprintf(os.Stderr, "Unknown help topic %#q. Run 'go help'.\n", arg)
os.Exit(2) // failed at 'go help cmd'
}
// importPathsNoDotExpansion returns the import paths to use for the given
// command line, but it does no ... expansion.
func importPathsNoDotExpansion(args []string) []string {
if len(args) == 0 {
return []string{"."}
}
var out []string
for _, a := range args {
// Arguments are supposed to be import paths, but
// as a courtesy to Windows developers, rewrite \ to /
// in command-line arguments. Handles .\... and so on.
if filepath.Separator == '\\' {
a = strings.Replace(a, `\`, `/`, -1)
}
// Put argument in canonical form, but preserve leading ./.
if strings.HasPrefix(a, "./") {
a = "./" + path.Clean(a)
if a == "./." {
a = "."
}
} else {
a = path.Clean(a)
}
if a == "all" || a == "std" {
out = append(out, allPackages(a)...)
continue
}
out = append(out, a)
}
return out
}
// importPaths returns the import paths to use for the given command line.
func importPaths(args []string) []string {
args = importPathsNoDotExpansion(args)
var out []string
for _, a := range args {
if strings.Contains(a, "...") {
if build.IsLocalImport(a) {
out = append(out, allPackagesInFS(a)...)
} else {
out = append(out, allPackages(a)...)
}
continue
}
out = append(out, a)
}
return out
}
var atexitFuncs []func()
func atexit(f func()) {
atexitFuncs = append(atexitFuncs, f)
}
func exit() {
for _, f := range atexitFuncs {
f()
}
os.Exit(exitStatus)
}
func fatalf(format string, args ...interface{}) {
errorf(format, args...)
exit()
}
func errorf(format string, args ...interface{}) {
log.Printf(format, args...)
setExitStatus(1)
}
var logf = log.Printf
func exitIfErrors() {
if exitStatus != 0 {
exit()
}
}
func run(cmdargs ...interface{}) {
cmdline := stringList(cmdargs...)
if buildN || buildX {
fmt.Printf("%s\n", strings.Join(cmdline, " "))
if buildN {
return
}
}
cmd := exec.Command(cmdline[0], cmdline[1:]...)
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
if err := cmd.Run(); err != nil {
errorf("%v", err)
}
}
func runOut(dir string, cmdargs ...interface{}) []byte {
cmdline := stringList(cmdargs...)
cmd := exec.Command(cmdline[0], cmdline[1:]...)
cmd.Dir = dir
out, err := cmd.CombinedOutput()
if err != nil {
os.Stderr.Write(out)
errorf("%v", err)
out = nil
}
return out
}
// envForDir returns a copy of the environment
// suitable for running in the given directory.
// The environment is the current process's environment
// but with an updated $PWD, so that an os.Getwd in the
// child will be faster.
func envForDir(dir string) []string {
env := os.Environ()
// Internally we only use rooted paths, so dir is rooted.
// Even if dir is not rooted, no harm done.
return mergeEnvLists([]string{"PWD=" + dir}, env)
}
// mergeEnvLists merges the two environment lists such that
// variables with the same name in "in" replace those in "out".
func mergeEnvLists(in, out []string) []string {
NextVar:
for _, inkv := range in {
k := strings.SplitAfterN(inkv, "=", 2)[0]
for i, outkv := range out {
if strings.HasPrefix(outkv, k) {
out[i] = inkv
continue NextVar
}
}
out = append(out, inkv)
}
return out
}
// matchPattern(pattern)(name) reports whether
// name matches pattern. Pattern is a limited glob
// pattern in which '...' means 'any string' and there
// is no other special syntax.
func matchPattern(pattern string) func(name string) bool {
re := regexp.QuoteMeta(pattern)
re = strings.Replace(re, `\.\.\.`, `.*`, -1)
// Special case: foo/... matches foo too.
if strings.HasSuffix(re, `/.*`) {
re = re[:len(re)-len(`/.*`)] + `(/.*)?`
}
reg := regexp.MustCompile(`^` + re + `$`)
return func(name string) bool {
return reg.MatchString(name)
}
}
// hasPathPrefix reports whether the path s begins with the
// elements in prefix.
func hasPathPrefix(s, prefix string) bool {
switch {
default:
return false
case len(s) == len(prefix):
return s == prefix
case len(s) > len(prefix):
if prefix != "" && prefix[len(prefix)-1] == '/' {
return strings.HasPrefix(s, prefix)
}
return s[len(prefix)] == '/' && s[:len(prefix)] == prefix
}
}
// treeCanMatchPattern(pattern)(name) reports whether
// name or children of name can possibly match pattern.
// Pattern is the same limited glob accepted by matchPattern.
func treeCanMatchPattern(pattern string) func(name string) bool {
wildCard := false
if i := strings.Index(pattern, "..."); i >= 0 {
wildCard = true
pattern = pattern[:i]
}
return func(name string) bool {
return len(name) <= len(pattern) && hasPathPrefix(pattern, name) ||
wildCard && strings.HasPrefix(name, pattern)
}
}
// allPackages returns all the packages that can be found
// under the $GOPATH directories and $GOROOT matching pattern.
// The pattern is either "all" (all packages), "std" (standard packages)
// or a path including "...".
func allPackages(pattern string) []string {
pkgs := matchPackages(pattern)
if len(pkgs) == 0 {
fmt.Fprintf(os.Stderr, "warning: %q matched no packages\n", pattern)
}
return pkgs
}
func matchPackages(pattern string) []string {
match := func(string) bool { return true }
treeCanMatch := func(string) bool { return true }
if pattern != "all" && pattern != "std" {
match = matchPattern(pattern)
treeCanMatch = treeCanMatchPattern(pattern)
}
have := map[string]bool{
"builtin": true, // ignore pseudo-package that exists only for documentation
}
if !buildContext.CgoEnabled {
have["runtime/cgo"] = true // ignore during walk
}
var pkgs []string
// Commands
cmd := filepath.Join(goroot, "src/cmd") + string(filepath.Separator)
filepath.Walk(cmd, func(path string, fi os.FileInfo, err error) error {
if err != nil || !fi.IsDir() || path == cmd {
return nil
}
name := path[len(cmd):]
if !treeCanMatch(name) {
return filepath.SkipDir
}
// Commands are all in cmd/, not in subdirectories.
if strings.Contains(name, string(filepath.Separator)) {
return filepath.SkipDir
}
// We use, e.g., cmd/gofmt as the pseudo import path for gofmt.
name = "cmd/" + name
if have[name] {
return nil
}
have[name] = true
if !match(name) {
return nil
}
_, err = buildContext.ImportDir(path, 0)
if err != nil {
if _, noGo := err.(*build.NoGoError); !noGo {
log.Print(err)
}
return nil
}
pkgs = append(pkgs, name)
return nil
})
for _, src := range buildContext.SrcDirs() {
if pattern == "std" && src != gorootSrcPkg {
continue
}
src = filepath.Clean(src) + string(filepath.Separator)
filepath.Walk(src, func(path string, fi os.FileInfo, err error) error {
if err != nil || !fi.IsDir() || path == src {
return nil
}
// Avoid .foo, _foo, and testdata directory trees.
_, elem := filepath.Split(path)
if strings.HasPrefix(elem, ".") || strings.HasPrefix(elem, "_") || elem == "testdata" {
return filepath.SkipDir
}
name := filepath.ToSlash(path[len(src):])
if pattern == "std" && strings.Contains(name, ".") {
return filepath.SkipDir
}
if !treeCanMatch(name) {
return filepath.SkipDir
}
if have[name] {
return nil
}
have[name] = true
if !match(name) {
return nil
}
_, err = buildContext.ImportDir(path, 0)
if err != nil {
if _, noGo := err.(*build.NoGoError); noGo {
return nil
}
}
pkgs = append(pkgs, name)
return nil
})
}
return pkgs
}
// allPackagesInFS is like allPackages but is passed a pattern
// beginning ./ or ../, meaning it should scan the tree rooted
// at the given directory. There are ... in the pattern too.
func allPackagesInFS(pattern string) []string {
pkgs := matchPackagesInFS(pattern)
if len(pkgs) == 0 {
fmt.Fprintf(os.Stderr, "warning: %q matched no packages\n", pattern)
}
return pkgs
}
func matchPackagesInFS(pattern string) []string {
// Find directory to begin the scan.
// Could be smarter but this one optimization
// is enough for now, since ... is usually at the
// end of a path.
i := strings.Index(pattern, "...")
dir, _ := path.Split(pattern[:i])
// pattern begins with ./ or ../.
// path.Clean will discard the ./ but not the ../.
// We need to preserve the ./ for pattern matching
// and in the returned import paths.
prefix := ""
if strings.HasPrefix(pattern, "./") {
prefix = "./"
}
match := matchPattern(pattern)
var pkgs []string
filepath.Walk(dir, func(path string, fi os.FileInfo, err error) error {
if err != nil || !fi.IsDir() {
return nil
}
if path == dir {
// filepath.Walk starts at dir and recurses. For the recursive case,
// the path is the result of filepath.Join, which calls filepath.Clean.
// The initial case is not Cleaned, though, so we do this explicitly.
//
// This converts a path like "./io/" to "io". Without this step, running
// "cd $GOROOT/src/pkg; go list ./io/..." would incorrectly skip the io
// package, because prepending the prefix "./" to the unclean path would
// result in "././io", and match("././io") returns false.
path = filepath.Clean(path)
}
// Avoid .foo, _foo, and testdata directory trees, but do not avoid "." or "..".
_, elem := filepath.Split(path)
dot := strings.HasPrefix(elem, ".") && elem != "." && elem != ".."
if dot || strings.HasPrefix(elem, "_") || elem == "testdata" {
return filepath.SkipDir
}
name := prefix + filepath.ToSlash(path)
if !match(name) {
return nil
}
if _, err = build.ImportDir(path, 0); err != nil {
if _, noGo := err.(*build.NoGoError); !noGo {
log.Print(err)
}
return nil
}
pkgs = append(pkgs, name)
return nil
})
return pkgs
}
// stringList's arguments should be a sequence of string or []string values.
// stringList flattens them into a single []string.
func stringList(args ...interface{}) []string {
var x []string
for _, arg := range args {
switch arg := arg.(type) {
case []string:
x = append(x, arg...)
case string:
x = append(x, arg)
default:
panic("stringList: invalid argument")
}
}
return x
}
// toFold returns a string with the property that
// strings.EqualFold(s, t) iff toFold(s) == toFold(t)
// This lets us test a large set of strings for fold-equivalent
// duplicates without making a quadratic number of calls
// to EqualFold. Note that strings.ToUpper and strings.ToLower
// have the desired property in some corner cases.
func toFold(s string) string {
// Fast path: all ASCII, no upper case.
// Most paths look like this already.
for i := 0; i < len(s); i++ {
c := s[i]
if c >= utf8.RuneSelf || 'A' <= c && c <= 'Z' {
goto Slow
}
}
return s
Slow:
var buf bytes.Buffer
for _, r := range s {
// SimpleFold(x) cycles to the next equivalent rune > x
// or wraps around to smaller values. Iterate until it wraps,
// and we've found the minimum value.
for {
r0 := r
r = unicode.SimpleFold(r0)
if r <= r0 {
break
}
}
// Exception to allow fast path above: A-Z => a-z
if 'A' <= r && r <= 'Z' {
r += 'a' - 'A'
}
buf.WriteRune(r)
}
return buf.String()
}
// foldDup reports a pair of strings from the list that are
// equal according to strings.EqualFold.
// It returns "", "" if there are no such strings.
func foldDup(list []string) (string, string) {
clash := map[string]string{}
for _, s := range list {
fold := toFold(s)
if t := clash[fold]; t != "" {
if s > t {
s, t = t, s
}
return s, t
}
clash[fold] = s
}
return "", ""
}
// Copyright 2012 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 "testing"
var matchPatternTests = []stringPairTest{
{"...", "foo", true},
{"net", "net", true},
{"net", "net/http", false},
{"net/http", "net", false},
{"net/http", "net/http", true},
{"net...", "netchan", true},
{"net...", "net", true},
{"net...", "net/http", true},
{"net...", "not/http", false},
{"net/...", "netchan", false},
{"net/...", "net", true},
{"net/...", "net/http", true},
{"net/...", "not/http", false},
}
func TestMatchPattern(t *testing.T) {
testStringPairs(t, "matchPattern", matchPatternTests, func(pattern, name string) bool {
return matchPattern(pattern)(name)
})
}
var treeCanMatchPatternTests = []stringPairTest{
{"...", "foo", true},
{"net", "net", true},
{"net", "net/http", false},
{"net/http", "net", true},
{"net/http", "net/http", true},
{"net...", "netchan", true},
{"net...", "net", true},
{"net...", "net/http", true},
{"net...", "not/http", false},
{"net/...", "netchan", false},
{"net/...", "net", true},
{"net/...", "net/http", true},
{"net/...", "not/http", false},
{"abc.../def", "abcxyz", true},
{"abc.../def", "xyxabc", false},
{"x/y/z/...", "x", true},
{"x/y/z/...", "x/y", true},
{"x/y/z/...", "x/y/z", true},
{"x/y/z/...", "x/y/z/w", true},
{"x/y/z", "x", true},
{"x/y/z", "x/y", true},
{"x/y/z", "x/y/z", true},
{"x/y/z", "x/y/z/w", false},
{"x/.../y/z", "x/a/b/c", true},
{"x/.../y/z", "y/x/a/b/c", false},
}
func TestChildrenCanMatchPattern(t *testing.T) {
testStringPairs(t, "treeCanMatchPattern", treeCanMatchPatternTests, func(pattern, name string) bool {
return treeCanMatchPattern(pattern)(name)
})
}
var hasPathPrefixTests = []stringPairTest{
{"abc", "a", false},
{"a/bc", "a", true},
{"a", "a", true},
{"a/bc", "a/", true},
}
func TestHasPathPrefix(t *testing.T) {
testStringPairs(t, "hasPathPrefix", hasPathPrefixTests, hasPathPrefix)
}
type stringPairTest struct {
in1 string
in2 string
out bool
}
func testStringPairs(t *testing.T, name string, tests []stringPairTest, f func(string, string) bool) {
for _, tt := range tests {
if out := f(tt.in1, tt.in2); out != tt.out {
t.Errorf("%s(%q, %q) = %v, want %v", name, tt.in1, tt.in2, out, tt.out)
}
}
}
#!/bin/sh
# Copyright 2012 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.
go install # So the next line will produce updated documentation.
go help documentation > doc.go
gofmt -w doc.go
// Copyright 2011 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"
"errors"
"fmt"
"go/build"
"go/scanner"
"go/token"
"os"
pathpkg "path"
"path/filepath"
"sort"
"strings"
"time"
"unicode"
)
// 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.
// See list.go. It is okay to add fields, but not to change or
// remove existing ones. Keep in sync with list.go
Dir string `json:",omitempty"` // directory containing package sources
ImportPath string `json:",omitempty"` // import path of package in dir
Name string `json:",omitempty"` // package name
Doc string `json:",omitempty"` // package documentation string
Target string `json:",omitempty"` // install path
Goroot bool `json:",omitempty"` // is this package found in the Go root?
Standard bool `json:",omitempty"` // is this package part of the standard Go library?
Stale bool `json:",omitempty"` // would 'go install' do anything for this package?
Root string `json:",omitempty"` // Go root or Go path dir containing this package
ConflictDir string `json:",omitempty"` // Dir is hidden by this other directory
// Source files
GoFiles []string `json:",omitempty"` // .go source files (excluding CgoFiles, TestGoFiles, XTestGoFiles)
CgoFiles []string `json:",omitempty"` // .go sources files that import "C"
IgnoredGoFiles []string `json:",omitempty"` // .go sources ignored due to build constraints
CFiles []string `json:",omitempty"` // .c source files
CXXFiles []string `json:",omitempty"` // .cc, .cpp and .cxx source files
MFiles []string `json:",omitempty"` // .m source files
HFiles []string `json:",omitempty"` // .h, .hh, .hpp and .hxx source files
SFiles []string `json:",omitempty"` // .s source files
SwigFiles []string `json:",omitempty"` // .swig files
SwigCXXFiles []string `json:",omitempty"` // .swigcxx files
SysoFiles []string `json:",omitempty"` // .syso system object files added to package
// Cgo directives
CgoCFLAGS []string `json:",omitempty"` // cgo: flags for C compiler
CgoCPPFLAGS []string `json:",omitempty"` // cgo: flags for C preprocessor
CgoCXXFLAGS []string `json:",omitempty"` // cgo: flags for C++ compiler
CgoLDFLAGS []string `json:",omitempty"` // cgo: flags for linker
CgoPkgConfig []string `json:",omitempty"` // cgo: pkg-config names
// Dependency information
Imports []string `json:",omitempty"` // import paths used by this package
Deps []string `json:",omitempty"` // all (recursively) imported dependencies
// Error information
Incomplete bool `json:",omitempty"` // was there an error loading this package or dependencies?
Error *PackageError `json:",omitempty"` // error loading this package (not dependencies)
DepsErrors []*PackageError `json:",omitempty"` // errors loading dependencies
// Test information
TestGoFiles []string `json:",omitempty"` // _test.go files in package
TestImports []string `json:",omitempty"` // imports from TestGoFiles
XTestGoFiles []string `json:",omitempty"` // _test.go files outside package
XTestImports []string `json:",omitempty"` // imports from XTestGoFiles
// Unexported fields are not part of the public API.
build *build.Package
pkgdir string // overrides build.PkgDir
imports []*Package
deps []*Package
gofiles []string // GoFiles+CgoFiles+TestGoFiles+XTestGoFiles files, absolute paths
sfiles []string
allgofiles []string // gofiles + IgnoredGoFiles, absolute paths
target string // installed file for this package (may be executable)
fake bool // synthesized package
forceBuild bool // this package must be rebuilt
forceLibrary bool // this package is a library (even if named "main")
cmdline bool // defined by files listed on command line
local bool // imported via local path (./ or ../)
localPrefix string // interpret ./ and ../ imports relative to this prefix
exeName string // desired name for temporary executable
coverMode string // preprocess Go source files with the coverage tool in this mode
coverVars map[string]*CoverVar // variables created by coverage analysis
omitDWARF bool // tell linker not to write DWARF information
}
// CoverVar holds the name of the generated coverage variables targeting the named file.
type CoverVar struct {
File string // local file name
Var string // name of count struct
}
func (p *Package) copyBuild(pp *build.Package) {
p.build = pp
p.Dir = pp.Dir
p.ImportPath = pp.ImportPath
p.Name = pp.Name
p.Doc = pp.Doc
p.Root = pp.Root
p.ConflictDir = pp.ConflictDir
// TODO? Target
p.Goroot = pp.Goroot
p.Standard = p.Goroot && p.ImportPath != "" && !strings.Contains(p.ImportPath, ".")
p.GoFiles = pp.GoFiles
p.CgoFiles = pp.CgoFiles
p.IgnoredGoFiles = pp.IgnoredGoFiles
p.CFiles = pp.CFiles
p.CXXFiles = pp.CXXFiles
p.MFiles = pp.MFiles
p.HFiles = pp.HFiles
p.SFiles = pp.SFiles
p.SwigFiles = pp.SwigFiles
p.SwigCXXFiles = pp.SwigCXXFiles
p.SysoFiles = pp.SysoFiles
p.CgoCFLAGS = pp.CgoCFLAGS
p.CgoCPPFLAGS = pp.CgoCPPFLAGS
p.CgoCXXFLAGS = pp.CgoCXXFLAGS
p.CgoLDFLAGS = pp.CgoLDFLAGS
p.CgoPkgConfig = pp.CgoPkgConfig
p.Imports = pp.Imports
p.TestGoFiles = pp.TestGoFiles
p.TestImports = pp.TestImports
p.XTestGoFiles = pp.XTestGoFiles
p.XTestImports = pp.XTestImports
}
// A PackageError describes an error loading information about a package.
type PackageError struct {
ImportStack []string // shortest path from package named on command line to this one
Pos string // position of error
Err string // the error itself
isImportCycle bool // the error is an import cycle
hard bool // whether the error is soft or hard; soft errors are ignored in some places
}
func (p *PackageError) Error() string {
// Import cycles deserve special treatment.
if p.isImportCycle {
return fmt.Sprintf("%s\npackage %s\n", p.Err, strings.Join(p.ImportStack, "\n\timports "))
}
if p.Pos != "" {
// Omit import stack. The full path to the file where the error
// is the most important thing.
return p.Pos + ": " + p.Err
}
if len(p.ImportStack) == 0 {
return p.Err
}
return "package " + strings.Join(p.ImportStack, "\n\timports ") + ": " + p.Err
}
// An importStack is a stack of import paths.
type importStack []string
func (s *importStack) push(p string) {
*s = append(*s, p)
}
func (s *importStack) pop() {
*s = (*s)[0 : len(*s)-1]
}
func (s *importStack) copy() []string {
return append([]string{}, *s...)
}
// shorterThan returns true if sp is shorter than t.
// We use this to record the shortest import sequence
// that leads to a particular package.
func (sp *importStack) shorterThan(t []string) bool {
s := *sp
if len(s) != len(t) {
return len(s) < len(t)
}
// If they are the same length, settle ties using string ordering.
for i := range s {
if s[i] != t[i] {
return s[i] < t[i]
}
}
return false // they are equal
}
// packageCache is a lookup cache for loadPackage,
// so that if we look up a package multiple times
// we return the same pointer each time.
var packageCache = map[string]*Package{}
// reloadPackage is like loadPackage but makes sure
// not to use the package cache.
func reloadPackage(arg string, stk *importStack) *Package {
p := packageCache[arg]
if p != nil {
delete(packageCache, p.Dir)
delete(packageCache, p.ImportPath)
}
return loadPackage(arg, stk)
}
// dirToImportPath returns the pseudo-import path we use for a package
// outside the Go path. It begins with _/ and then contains the full path
// to the directory. If the package lives in c:\home\gopher\my\pkg then
// the pseudo-import path is _/c_/home/gopher/my/pkg.
// Using a pseudo-import path like this makes the ./ imports no longer
// a special case, so that all the code to deal with ordinary imports works
// automatically.
func dirToImportPath(dir string) string {
return pathpkg.Join("_", strings.Map(makeImportValid, filepath.ToSlash(dir)))
}
func makeImportValid(r rune) rune {
// Should match Go spec, compilers, and ../../pkg/go/parser/parser.go:/isValidImport.
const illegalChars = `!"#$%&'()*,:;<=>?[\]^{|}` + "`\uFFFD"
if !unicode.IsGraphic(r) || unicode.IsSpace(r) || strings.ContainsRune(illegalChars, r) {
return '_'
}
return r
}
// loadImport scans the directory named by path, which must be an import path,
// but possibly a local import path (an absolute file system path or one beginning
// with ./ or ../). A local relative path is interpreted relative to srcDir.
// It returns a *Package describing the package found in that directory.
func loadImport(path string, srcDir string, stk *importStack, importPos []token.Position) *Package {
stk.push(path)
defer stk.pop()
// Determine canonical identifier for this package.
// For a local import the identifier is the pseudo-import path
// we create from the full directory to the package.
// Otherwise it is the usual import path.
importPath := path
isLocal := build.IsLocalImport(path)
if isLocal {
importPath = dirToImportPath(filepath.Join(srcDir, path))
}
if p := packageCache[importPath]; p != nil {
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.
bp, err := buildContext.Import(path, srcDir, 0)
bp.ImportPath = importPath
if gobin != "" {
bp.BinDir = gobin
}
p.load(stk, bp, err)
if p.Error != nil && len(importPos) > 0 {
pos := importPos[0]
pos.Filename = shortPath(pos.Filename)
p.Error.Pos = pos.String()
}
return p
}
// reusePackage reuses package p to satisfy the import at the top
// of the import stack stk. If this use causes an import loop,
// reusePackage updates p's error information to record the loop.
func reusePackage(p *Package, stk *importStack) *Package {
// We use p.imports==nil to detect a package that
// is in the midst of its own loadPackage call
// (all the recursion below happens before p.imports gets set).
if p.imports == nil {
if p.Error == nil {
p.Error = &PackageError{
ImportStack: stk.copy(),
Err: "import cycle not allowed",
isImportCycle: true,
}
}
p.Incomplete = true
}
// Don't rewrite the import stack in the error if we have an import cycle.
// If we do, we'll lose the path that describes the cycle.
if p.Error != nil && !p.Error.isImportCycle && stk.shorterThan(p.Error.ImportStack) {
p.Error.ImportStack = stk.copy()
}
return p
}
type targetDir int
const (
toRoot targetDir = iota // to bin dir inside package root (default)
toTool // GOROOT/pkg/tool
toBin // GOROOT/bin
)
// goTools is a map of Go program import path to install target directory.
var goTools = map[string]targetDir{
"cmd/addr2line": toTool,
"cmd/api": toTool,
"cmd/cgo": toTool,
"cmd/fix": toTool,
"cmd/link": toTool,
"cmd/nm": toTool,
"cmd/objdump": toTool,
"cmd/pack": toTool,
"cmd/yacc": toTool,
"code.google.com/p/go.tools/cmd/cover": toTool,
"code.google.com/p/go.tools/cmd/godoc": toBin,
"code.google.com/p/go.tools/cmd/vet": toTool,
}
// expandScanner expands a scanner.List error into all the errors in the list.
// The default Error method only shows the first error.
func expandScanner(err error) error {
// Look for parser errors.
if err, ok := err.(scanner.ErrorList); ok {
// Prepare error with \n before each message.
// When printed in something like context: %v
// this will put the leading file positions each on
// its own line. It will also show all the errors
// instead of just the first, as err.Error does.
var buf bytes.Buffer
for _, e := range err {
e.Pos.Filename = shortPath(e.Pos.Filename)
buf.WriteString("\n")
buf.WriteString(e.Error())
}
return errors.New(buf.String())
}
return err
}
var raceExclude = map[string]bool{
"runtime/race": true,
"runtime/cgo": true,
"cmd/cgo": true,
"syscall": true,
"errors": true,
}
var cgoExclude = map[string]bool{
"runtime/cgo": true,
}
var cgoSyscallExclude = map[string]bool{
"runtime/cgo": true,
"runtime/race": true,
}
// load populates p using information from bp, err, which should
// be the result of calling build.Context.Import.
func (p *Package) load(stk *importStack, bp *build.Package, err error) *Package {
p.copyBuild(bp)
// The localPrefix is the path we interpret ./ imports relative to.
// Synthesized main packages sometimes override this.
p.localPrefix = dirToImportPath(p.Dir)
if err != nil {
p.Incomplete = true
err = expandScanner(err)
p.Error = &PackageError{
ImportStack: stk.copy(),
Err: err.Error(),
}
return p
}
if p.Name == "main" {
_, elem := filepath.Split(p.Dir)
full := buildContext.GOOS + "_" + buildContext.GOARCH + "/" + elem
if buildContext.GOOS != toolGOOS || buildContext.GOARCH != toolGOARCH {
// Install cross-compiled binaries to subdirectories of bin.
elem = full
}
if p.build.BinDir != gobin && goTools[p.ImportPath] == toBin {
// Override BinDir.
// This is from a subrepo but installs to $GOROOT/bin
// by default anyway (like godoc).
p.target = filepath.Join(gorootBin, elem)
} else if p.build.BinDir != "" {
// Install to GOBIN or bin of GOPATH entry.
p.target = filepath.Join(p.build.BinDir, elem)
}
if goTools[p.ImportPath] == toTool {
// This is for 'go tool'.
// Override all the usual logic and force it into the tool directory.
p.target = filepath.Join(gorootPkg, "tool", full)
}
if p.target != "" && buildContext.GOOS == "windows" {
p.target += ".exe"
}
} else if p.local {
// Local import turned into absolute path.
// No permanent install target.
p.target = ""
} else {
p.target = p.build.PkgObj
}
importPaths := p.Imports
// Packages that use cgo import runtime/cgo implicitly.
// Packages that use cgo also import syscall implicitly,
// to wrap errno.
// Exclude certain packages to avoid circular dependencies.
if len(p.CgoFiles) > 0 && (!p.Standard || !cgoExclude[p.ImportPath]) {
importPaths = append(importPaths, "runtime/cgo")
}
if len(p.CgoFiles) > 0 && (!p.Standard || !cgoSyscallExclude[p.ImportPath]) {
importPaths = append(importPaths, "syscall")
}
// Everything depends on runtime, except runtime and unsafe.
if !p.Standard || (p.ImportPath != "runtime" && p.ImportPath != "unsafe") {
importPaths = append(importPaths, "runtime")
// When race detection enabled everything depends on runtime/race.
// Exclude certain packages to avoid circular dependencies.
if buildRace && (!p.Standard || !raceExclude[p.ImportPath]) {
importPaths = append(importPaths, "runtime/race")
}
}
// Build list of full paths to all Go files in the package,
// for use by commands like go fmt.
p.gofiles = stringList(p.GoFiles, p.CgoFiles, p.TestGoFiles, p.XTestGoFiles)
for i := range p.gofiles {
p.gofiles[i] = filepath.Join(p.Dir, p.gofiles[i])
}
sort.Strings(p.gofiles)
p.sfiles = stringList(p.SFiles)
for i := range p.sfiles {
p.sfiles[i] = filepath.Join(p.Dir, p.sfiles[i])
}
sort.Strings(p.sfiles)
p.allgofiles = stringList(p.IgnoredGoFiles)
for i := range p.allgofiles {
p.allgofiles[i] = filepath.Join(p.Dir, p.allgofiles[i])
}
p.allgofiles = append(p.allgofiles, p.gofiles...)
sort.Strings(p.allgofiles)
// Check for case-insensitive collision of input files.
// To avoid problems on case-insensitive files, we reject any package
// where two different input files have equal names under a case-insensitive
// comparison.
f1, f2 := foldDup(stringList(
p.GoFiles,
p.CgoFiles,
p.IgnoredGoFiles,
p.CFiles,
p.CXXFiles,
p.MFiles,
p.HFiles,
p.SFiles,
p.SysoFiles,
p.SwigFiles,
p.SwigCXXFiles,
p.TestGoFiles,
p.XTestGoFiles,
))
if f1 != "" {
p.Error = &PackageError{
ImportStack: stk.copy(),
Err: fmt.Sprintf("case-insensitive file name collision: %q and %q", f1, f2),
}
return p
}
// Build list of imported packages and full dependency list.
imports := make([]*Package, 0, len(p.Imports))
deps := make(map[string]bool)
for i, path := range importPaths {
if path == "C" {
continue
}
p1 := loadImport(path, p.Dir, stk, p.build.ImportPos[path])
if !reqPkgSrc && p1.Root == "" {
continue
}
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()
}
}
path = p1.ImportPath
importPaths[i] = path
}
deps[path] = true
imports = append(imports, p1)
for _, dep := range p1.Deps {
deps[dep] = true
}
if p1.Incomplete {
p.Incomplete = true
}
}
p.imports = imports
p.Deps = make([]string, 0, len(deps))
for dep := range deps {
p.Deps = append(p.Deps, dep)
}
sort.Strings(p.Deps)
for _, dep := range p.Deps {
p1 := packageCache[dep]
if p1 == nil {
panic("impossible: missing entry in package cache for " + dep + " imported by " + p.ImportPath)
}
p.deps = append(p.deps, p1)
if p1.Error != nil {
p.DepsErrors = append(p.DepsErrors, p1.Error)
}
}
// unsafe is a fake package.
if p.Standard && (p.ImportPath == "unsafe" || buildContext.Compiler == "gccgo") {
p.target = ""
}
p.Target = p.target
// In the absence of errors lower in the dependency tree,
// check for case-insensitive collisions of import paths.
if len(p.DepsErrors) == 0 {
dep1, dep2 := foldDup(p.Deps)
if dep1 != "" {
p.Error = &PackageError{
ImportStack: stk.copy(),
Err: fmt.Sprintf("case-insensitive import collision: %q and %q", dep1, dep2),
}
return p
}
}
return p
}
// usesSwig reports whether the package needs to run SWIG.
func (p *Package) usesSwig() bool {
return len(p.SwigFiles) > 0 || len(p.SwigCXXFiles) > 0
}
// usesCgo reports whether the package needs to run cgo
func (p *Package) usesCgo() bool {
return len(p.CgoFiles) > 0
}
// packageList returns the list of packages in the dag rooted at roots
// as visited in a depth-first post-order traversal.
func packageList(roots []*Package) []*Package {
seen := map[*Package]bool{}
all := []*Package{}
var walk func(*Package)
walk = func(p *Package) {
if seen[p] {
return
}
seen[p] = true
for _, p1 := range p.imports {
walk(p1)
}
all = append(all, p)
}
for _, root := range roots {
walk(root)
}
return all
}
// computeStale computes the Stale flag in the package dag that starts
// at the named pkgs (command-line arguments).
func computeStale(pkgs ...*Package) {
topRoot := map[string]bool{}
for _, p := range pkgs {
topRoot[p.Root] = true
}
for _, p := range packageList(pkgs) {
p.Stale = isStale(p, topRoot)
}
}
// isStale reports whether package p needs to be rebuilt.
func isStale(p *Package, topRoot map[string]bool) bool {
if p.Standard && (p.ImportPath == "unsafe" || buildContext.Compiler == "gccgo") {
// fake, builtin package
return false
}
if p.Error != nil {
return true
}
// A package without Go sources means we only found
// the installed .a file. Since we don't know how to rebuild
// it, it can't be stale, even if -a is set. This enables binary-only
// distributions of Go packages, although such binaries are
// only useful with the specific version of the toolchain that
// created them.
if len(p.gofiles) == 0 && !p.usesSwig() {
return false
}
if buildA || p.target == "" || p.Stale {
return true
}
// Package is stale if completely unbuilt.
var built time.Time
if fi, err := os.Stat(p.target); err == nil {
built = fi.ModTime()
}
if built.IsZero() {
return true
}
olderThan := func(file string) bool {
fi, err := os.Stat(file)
return err != nil || fi.ModTime().After(built)
}
// Package is stale if a dependency is, or if a dependency is newer.
for _, p1 := range p.deps {
if p1.Stale || p1.target != "" && olderThan(p1.target) {
return true
}
}
// As a courtesy to developers installing new versions of the compiler
// frequently, define that packages are stale if they are
// older than the compiler, and commands if they are older than
// the linker. This heuristic will not work if the binaries are
// back-dated, as some binary distributions may do, but it does handle
// a very common case.
// See issue 3036.
// Assume code in $GOROOT is up to date, since it may not be writeable.
// See issue 4106.
if p.Root != goroot {
if olderThan(buildToolchain.compiler()) {
return true
}
if p.build.IsCommand() && olderThan(buildToolchain.linker()) {
return true
}
}
// Have installed copy, probably built using current compilers,
// and built after its imported packages. The only reason now
// that we'd have to rebuild it is if the sources were newer than
// the package. If a package p is not in the same tree as any
// package named on the command-line, assume it is up-to-date
// no matter what the modification times on the source files indicate.
// This avoids rebuilding $GOROOT packages when people are
// working outside the Go root, and it effectively makes each tree
// listed in $GOPATH a separate compilation world.
// See issue 3149.
if p.Root != "" && !topRoot[p.Root] {
return false
}
srcs := stringList(p.GoFiles, p.CFiles, p.CXXFiles, p.MFiles, p.HFiles, p.SFiles, p.CgoFiles, p.SysoFiles, p.SwigFiles, p.SwigCXXFiles)
for _, src := range srcs {
if olderThan(filepath.Join(p.Dir, src)) {
return true
}
}
return false
}
var cwd, _ = os.Getwd()
var cmdCache = map[string]*Package{}
// loadPackage is like loadImport but is used for command-line arguments,
// not for paths found in import statements. In addition to ordinary import paths,
// loadPackage accepts pseudo-paths beginning with cmd/ to denote commands
// in the Go command directory, as well as paths to those directories.
func loadPackage(arg string, stk *importStack) *Package {
if build.IsLocalImport(arg) {
dir := arg
if !filepath.IsAbs(dir) {
if abs, err := filepath.Abs(dir); err == nil {
// interpret relative to current directory
dir = abs
}
}
if sub, ok := hasSubdir(gorootSrc, dir); ok && strings.HasPrefix(sub, "cmd/") && !strings.Contains(sub[4:], "/") {
arg = sub
}
}
if strings.HasPrefix(arg, "cmd/") {
if p := cmdCache[arg]; p != nil {
return p
}
stk.push(arg)
defer stk.pop()
if strings.Contains(arg[4:], "/") {
p := &Package{
Error: &PackageError{
ImportStack: stk.copy(),
Err: fmt.Sprintf("invalid import path: cmd/... is reserved for Go commands"),
hard: true,
},
}
return p
}
bp, err := buildContext.ImportDir(filepath.Join(gorootSrc, arg), 0)
bp.ImportPath = arg
bp.Goroot = true
bp.BinDir = gorootBin
if gobin != "" {
bp.BinDir = gobin
}
bp.Root = goroot
bp.SrcRoot = gorootSrc
p := new(Package)
cmdCache[arg] = p
p.load(stk, bp, err)
if p.Error == nil && p.Name != "main" {
p.Error = &PackageError{
ImportStack: stk.copy(),
Err: fmt.Sprintf("expected package main but found package %s in %s", p.Name, p.Dir),
}
}
return p
}
// Wasn't a command; must be a package.
// If it is a local import path but names a standard package,
// we treat it as if the user specified the standard package.
// This lets you run go test ./ioutil in package io and be
// referring to io/ioutil rather than a hypothetical import of
// "./ioutil".
if build.IsLocalImport(arg) {
bp, _ := buildContext.ImportDir(filepath.Join(cwd, arg), build.FindOnly)
if bp.ImportPath != "" && bp.ImportPath != "." {
arg = bp.ImportPath
}
}
return loadImport(arg, cwd, stk, nil)
}
// packages returns the packages named by the
// command line arguments 'args'. If a named package
// cannot be loaded at all (for example, if the directory does not exist),
// then packages prints an error and does not include that
// package in the results. However, if errors occur trying
// to load dependencies of a named package, the named
// package is still returned, with p.Incomplete = true
// and details in p.DepsErrors.
func packages(args []string) []*Package {
var pkgs []*Package
for _, pkg := range packagesAndErrors(args) {
if pkg.Error != nil {
errorf("can't load package: %s", pkg.Error)
continue
}
pkgs = append(pkgs, pkg)
}
return pkgs
}
// packagesAndErrors is like 'packages' but returns a
// *Package for every argument, even the ones that
// cannot be loaded at all.
// The packages that fail to load will have p.Error != nil.
func packagesAndErrors(args []string) []*Package {
if len(args) > 0 && strings.HasSuffix(args[0], ".go") {
return []*Package{goFilesPackage(args)}
}
args = importPaths(args)
var pkgs []*Package
var stk importStack
var set = make(map[string]bool)
for _, arg := range args {
if !set[arg] {
pkgs = append(pkgs, loadPackage(arg, &stk))
set[arg] = true
}
}
computeStale(pkgs...)
return pkgs
}
// packagesForBuild is like 'packages' but fails if any of
// the packages or their dependencies have errors
// (cannot be built).
func packagesForBuild(args []string) []*Package {
pkgs := packagesAndErrors(args)
printed := map[*PackageError]bool{}
for _, pkg := range pkgs {
if pkg.Error != nil {
errorf("can't load package: %s", pkg.Error)
}
for _, err := range pkg.DepsErrors {
// Since these are errors in dependencies,
// the same error might show up multiple times,
// once in each package that depends on it.
// Only print each once.
if !printed[err] {
printed[err] = true
errorf("%s", err)
}
}
}
exitIfErrors()
return pkgs
}
// hasSubdir reports whether dir is a subdirectory of
// (possibly multiple levels below) root.
// If so, it sets rel to the path fragment that must be
// appended to root to reach dir.
func hasSubdir(root, dir string) (rel string, ok bool) {
if p, err := filepath.EvalSymlinks(root); err == nil {
root = p
}
if p, err := filepath.EvalSymlinks(dir); err == nil {
dir = p
}
const sep = string(filepath.Separator)
root = filepath.Clean(root)
if !strings.HasSuffix(root, sep) {
root += sep
}
dir = filepath.Clean(dir)
if !strings.HasPrefix(dir, root) {
return "", false
}
return filepath.ToSlash(dir[len(root):]), true
}
// Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package main
import (
"reflect"
"strings"
"testing"
)
var foldDupTests = []struct {
list []string
f1, f2 string
}{
{stringList("math/rand", "math/big"), "", ""},
{stringList("math", "strings"), "", ""},
{stringList("strings"), "", ""},
{stringList("strings", "strings"), "strings", "strings"},
{stringList("Rand", "rand", "math", "math/rand", "math/Rand"), "Rand", "rand"},
}
func TestFoldDup(t *testing.T) {
for _, tt := range foldDupTests {
f1, f2 := foldDup(tt.list)
if f1 != tt.f1 || f2 != tt.f2 {
t.Errorf("foldDup(%q) = %q, %q, want %q, %q", tt.list, f1, f2, tt.f1, tt.f2)
}
}
}
var parseMetaGoImportsTests = []struct {
in string
out []metaImport
}{
{
`<meta name="go-import" content="foo/bar git https://github.com/rsc/foo/bar">`,
[]metaImport{{"foo/bar", "git", "https://github.com/rsc/foo/bar"}},
},
{
`<meta name="go-import" content="foo/bar git https://github.com/rsc/foo/bar">
<meta name="go-import" content="baz/quux git http://github.com/rsc/baz/quux">`,
[]metaImport{
{"foo/bar", "git", "https://github.com/rsc/foo/bar"},
{"baz/quux", "git", "http://github.com/rsc/baz/quux"},
},
},
{
`<head>
<meta name="go-import" content="foo/bar git https://github.com/rsc/foo/bar">
</head>`,
[]metaImport{{"foo/bar", "git", "https://github.com/rsc/foo/bar"}},
},
{
`<meta name="go-import" content="foo/bar git https://github.com/rsc/foo/bar">
<body>`,
[]metaImport{{"foo/bar", "git", "https://github.com/rsc/foo/bar"}},
},
}
func TestParseMetaGoImports(t *testing.T) {
for i, tt := range parseMetaGoImportsTests {
out, err := parseMetaGoImports(strings.NewReader(tt.in))
if err != nil {
t.Errorf("test#%d: %v", i, err)
continue
}
if !reflect.DeepEqual(out, tt.out) {
t.Errorf("test#%d:\n\thave %q\n\twant %q", i, out, tt.out)
}
}
}
// Copyright 2011 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 (
"fmt"
"os"
"os/exec"
"runtime"
"strings"
)
var execCmd []string // -exec flag, for run and test
func findExecCmd() []string {
if execCmd != nil {
return execCmd
}
execCmd = []string{} // avoid work the second time
if goos == runtime.GOOS && goarch == runtime.GOARCH {
return execCmd
}
path, err := exec.LookPath(fmt.Sprintf("go_%s_%s_exec", goos, goarch))
if err == nil {
execCmd = []string{path}
}
return execCmd
}
var cmdRun = &Command{
UsageLine: "run [build flags] [-exec xprog] gofiles... [arguments...]",
Short: "compile and run Go program",
Long: `
Run compiles and runs the main package comprising the named Go source files.
A Go source file is defined to be a file ending in a literal ".go" suffix.
By default, 'go run' runs the compiled binary directly: 'a.out arguments...'.
If the -exec flag is given, 'go run' invokes the binary using xprog: 'xprog a.out arguments...'.
If the -exec flag is not given, GOOS or GOARCH is different from the system
default, and a program named go_$GOOS_$GOARCH_exec can be found
on the current search path, 'go run' invokes the binary using that program,
for example 'go_nacl_386_exec a.out arguments...'. This allows execution of
cross-compiled programs when a simulator or other execution method is
available.
For more about build flags, see 'go help build'.
See also: go build.
`,
}
func init() {
cmdRun.Run = runRun // break init loop
addBuildFlags(cmdRun)
cmdRun.Flag.Var((*stringsFlag)(&execCmd), "exec", "")
}
func printStderr(args ...interface{}) (int, error) {
return fmt.Fprint(os.Stderr, args...)
}
func runRun(cmd *Command, args []string) {
raceInit()
var b builder
b.init()
b.print = printStderr
i := 0
for i < len(args) && strings.HasSuffix(args[i], ".go") {
i++
}
files, cmdArgs := args[:i], args[i:]
if len(files) == 0 {
fatalf("go run: no go files listed")
}
for _, file := range files {
if strings.HasSuffix(file, "_test.go") {
// goFilesPackage is going to assign this to TestGoFiles.
// Reject since it won't be part of the build.
fatalf("go run: cannot run *_test.go files (%s)", file)
}
}
p := goFilesPackage(files)
if p.Error != nil {
fatalf("%s", p.Error)
}
p.omitDWARF = true
for _, err := range p.DepsErrors {
errorf("%s", err)
}
exitIfErrors()
if p.Name != "main" {
fatalf("go run: cannot run non-main package")
}
p.target = "" // must build - not up to date
var src string
if len(p.GoFiles) > 0 {
src = p.GoFiles[0]
} else if len(p.CgoFiles) > 0 {
src = p.CgoFiles[0]
} else {
// this case could only happen if the provided source uses cgo
// while cgo is disabled.
hint := ""
if !buildContext.CgoEnabled {
hint = " (cgo is disabled)"
}
fatalf("go run: no suitable source files%s", hint)
}
p.exeName = src[:len(src)-len(".go")] // name temporary executable for first go file
a1 := b.action(modeBuild, modeBuild, p)
a := &action{f: (*builder).runProgram, args: cmdArgs, deps: []*action{a1}}
b.do(a)
}
// runProgram is the action for running a binary that has already
// been compiled. We ignore exit status.
func (b *builder) runProgram(a *action) error {
cmdline := stringList(findExecCmd(), a.deps[0].target, a.args)
if buildN || buildX {
b.showcmd("", "%s", strings.Join(cmdline, " "))
if buildN {
return nil
}
}
runStdin(cmdline)
return nil
}
// runStdin is like run, but connects Stdin.
func runStdin(cmdline []string) {
cmd := exec.Command(cmdline[0], cmdline[1:]...)
cmd.Stdin = os.Stdin
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
startSigHandlers()
if err := cmd.Run(); err != nil {
errorf("%v", err)
}
}
#!/bin/sh
x() {
echo '--- ' "$@"
"$@"
echo '---'
echo
}
x go help
x go help build
x go help clean
x go help install
x go help fix
x go help fmt
x go help get
x go help list
x go help test
x go help version
x go help vet
x go help gopath
x go help importpath
x go help remote
--- go help
usage: go command [arguments]
go manages Go source code.
The commands are:
build compile and install packages and dependencies
clean remove intermediate objects
fix run gofix on packages
fmt run gofmt -w on packages
get download and install packages and dependencies
install install packages and dependencies
list list packages
test test packages
version print Go version
vet run govet on packages
Use "go help [command]" for more information about a command.
Additional help topics:
gopath GOPATH environment variable
importpath description of import paths
remote remote import path syntax
Use "go help [topic]" for more information about that topic.
---
--- go help build
usage: go build [-n] [-v] [importpath...]
Build compiles the packages named by the import paths,
along with their dependencies, but it does not install the results.
The -n flag prints the commands but does not run them.
The -v flag prints the commands.
For more about import paths, see 'go help importpath'.
See also: go install, go get, go clean.
---
--- go help clean
usage: go clean [-nuke] [importpath...]
Clean removes intermediate object files generated during
the compilation of the packages named by the import paths,
but by default it does not remove the installed package binaries.
The -nuke flag causes clean to remove the installed package binaries too.
TODO: Clean does not clean dependencies of the packages.
For more about import paths, see 'go help importpath'.
---
--- go help install
usage: go install [-n] [-v] [importpath...]
Install compiles and installs the packages named by the import paths,
along with their dependencies.
The -n flag prints the commands but does not run them.
The -v flag prints the commands.
For more about import paths, see 'go help importpath'.
See also: go build, go get, go clean.
---
--- go help fix
usage: go fix [importpath...]
Fix runs the gofix command on the packages named by the import paths.
For more about gofix, see 'godoc gofix'.
For more about import paths, see 'go help importpath'.
To run gofix with specific options, run gofix itself.
See also: go fmt, go vet.
---
--- go help fmt
usage: go fmt [importpath...]
Fmt runs the command 'gofmt -w' on the packages named by the import paths.
For more about gofmt, see 'godoc gofmt'.
For more about import paths, see 'go help importpath'.
To run gofmt with specific options, run gofmt itself.
See also: go fix, go vet.
---
--- go help get
usage: go get [importpath...]
Get downloads and installs the packages named by the import paths,
along with their dependencies.
After downloading the code, 'go get' looks for a tag beginning
with "go." that corresponds to the local Go version.
For Go "release.r58" it looks for a tag named "go.r58".
For "weekly.2011-06-03" it looks for "go.weekly.2011-06-03".
If the specific "go.X" tag is not found, it uses the latest earlier
version it can find. Otherwise, it uses the default version for
the version control system: HEAD for git, tip for Mercurial,
and so on.
TODO: Explain versions better.
For more about import paths, see 'go help importpath'.
For more about how 'go get' finds source code to
download, see 'go help remote'.
See also: go build, go install, go clean.
---
--- go help list
usage: go list [-f format] [-json] [importpath...]
List lists the packages named by the import paths.
The default output shows the package name and file system location:
books /home/you/src/google-api-go-client.googlecode.com/hg/books/v1
oauth /home/you/src/goauth2.googlecode.com/hg/oauth
sqlite /home/you/src/gosqlite.googlecode.com/hg/sqlite
The -f flag specifies an alternate format for the list,
using the syntax of package template. The default output
is equivalent to -f '{{.Name}} {{.Dir}}' The struct
being passed to the template is:
type Package struct {
Name string // package name
Doc string // package documentation string
GoFiles []string // names of Go source files in package
ImportPath string // import path denoting package
Imports []string // import paths used by this package
Deps []string // all (recursively) imported dependencies
Dir string // directory containing package sources
Version string // version of installed package
}
The -json flag causes the package data to be printed in JSON format.
For more about import paths, see 'go help importpath'.
---
--- go help test
usage: go test [importpath...]
Test runs gotest to test the packages named by the import paths.
It prints a summary of the test results in the format:
test archive/tar
FAIL archive/zip
test compress/gzip
...
followed by gotest output for each failed package.
For more about import paths, see 'go help importpath'.
See also: go build, go compile, go vet.
---
--- go help version
usage: go version
Version prints the Go version, as reported by runtime.Version.
---
--- go help vet
usage: go vet [importpath...]
Vet runs the govet command on the packages named by the import paths.
For more about govet, see 'godoc govet'.
For more about import paths, see 'go help importpath'.
To run govet with specific options, run govet itself.
See also: go fmt, go fix.
---
--- go help gopath
The GOPATH environment variable lists places to look for Go code.
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 build and install packages outside the
standard Go tree.
Each directory listed in GOPATH must have a prescribed structure:
The src/ directory holds source code. The path below 'src'
determines the import path or executable name.
The pkg/ directory holds installed package objects.
As in the Go tree, each target operating system and
architecture pair has its own subdirectory of pkg
(pkg/GOOS_GOARCH).
If DIR is a directory listed in the GOPATH, a package with
source in DIR/src/foo/bar can be imported as "foo/bar" and
has its compiled form installed to "DIR/pkg/GOOS_GOARCH/foo/bar.a".
The bin/ directory holds compiled commands.
Each command is named for its source directory, but only
the final element, not the entire path. That is, the
command with source in DIR/src/foo/quux is installed into
DIR/bin/quux, not DIR/bin/foo/quux. The foo/ is stripped
so that you can add DIR/bin to your PATH to get at the
installed commands.
Here's an example directory layout:
GOPATH=/home/user/gocode
/home/user/gocode/
src/
foo/
bar/ (go code in package bar)
x.go
quux/ (go code in package main)
y.go
bin/
quux (installed command)
pkg/
linux_amd64/
foo/
bar.a (installed package object)
Go searches each directory listed in GOPATH to find source code,
but new packages are always downloaded into the first directory
in the list.
---
--- go help importpath
Many commands apply to a set of packages named by import paths:
go action [importpath...]
An import path that is a rooted path or that begins with
a . or .. element is interpreted as a file system path and
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').
If no import paths are given, the action applies to the
package in the current directory.
The special import path "all" expands to all package directories
found in all the GOPATH trees. For example, 'go list all'
lists all the packages on the local system.
An import path can also name a package to be downloaded from
a remote repository. Run 'go help remote' for details.
Every package in a program must have a unique import path.
By convention, this is arranged by starting each path with a
unique prefix that belongs to you. For example, paths used
internally at Google all begin with 'google', and paths
denoting remote repositories begin with the path to the code,
such as 'project.googlecode.com/'.
---
--- go help remote
An import path (see 'go help importpath') denotes a package
stored in the local file system. Certain import paths also
describe how to obtain the source code for the package using
a revision control system.
A few common code hosting sites have special syntax:
BitBucket (Mercurial)
import "bitbucket.org/user/project"
import "bitbucket.org/user/project/sub/directory"
GitHub (Git)
import "github.com/user/project"
import "github.com/user/project/sub/directory"
Google Code Project Hosting (Git, Mercurial, Subversion)
import "project.googlecode.com/git"
import "project.googlecode.com/git/sub/directory"
import "project.googlecode.com/hg"
import "project.googlecode.com/hg/sub/directory"
import "project.googlecode.com/svn/trunk"
import "project.googlecode.com/svn/trunk/sub/directory"
Launchpad (Bazaar)
import "launchpad.net/project"
import "launchpad.net/project/series"
import "launchpad.net/project/series/sub/directory"
import "launchpad.net/~user/project/branch"
import "launchpad.net/~user/project/branch/sub/directory"
For code hosted on other servers, an import path of the form
repository.vcs/path
specifies the given repository, with or without the .vcs suffix,
using the named version control system, and then the path inside
that repository. The supported version control systems are:
Bazaar .bzr
Git .git
Mercurial .hg
Subversion .svn
For example,
import "example.org/user/foo.hg"
denotes the root directory of the Mercurial repository at
example.org/user/foo or foo.hg, and
import "example.org/repo.git/foo/bar"
denotes the foo/bar directory of the Git repository at
example.com/repo or repo.git.
When a version control system supports multiple protocols,
each is tried in turn when downloading. For example, a Git
download tries git://, then https://, then http://.
New downloaded packages are written to the first directory
listed in the GOPATH environment variable (see 'go help gopath').
The go command attempts to download the version of the
package appropriate for the Go release being used.
Run 'go help install' for more.
---
// Copyright 2012 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"
"os/signal"
"sync"
)
// interrupted is closed, if go process is interrupted.
var interrupted = make(chan struct{})
// processSignals setups signal handler.
func processSignals() {
sig := make(chan os.Signal)
signal.Notify(sig, signalsToIgnore...)
go func() {
<-sig
close(interrupted)
}()
}
var onceProcessSignals sync.Once
// startSigHandlers start signal handlers.
func startSigHandlers() {
onceProcessSignals.Do(processSignals)
}
// Copyright 2012 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 plan9 windows
package main
import (
"os"
)
var signalsToIgnore = []os.Signal{os.Interrupt}
// signalTrace is the signal to send to make a Go program
// crash with a stack trace.
var signalTrace os.Signal = nil
// Copyright 2012 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 darwin dragonfly freebsd linux nacl netbsd openbsd solaris
package main
import (
"os"
"syscall"
)
var signalsToIgnore = []os.Signal{os.Interrupt, syscall.SIGQUIT}
// signalTrace is the signal to send to make a Go program
// crash with a stack trace.
var signalTrace os.Signal = syscall.SIGQUIT
// Copyright 2011 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 "testing"
var selectTagTestTags = []string{
"go.r58",
"go.r58.1",
"go.r59",
"go.r59.1",
"go.r61",
"go.r61.1",
"go.weekly.2010-01-02",
"go.weekly.2011-10-12",
"go.weekly.2011-10-12.1",
"go.weekly.2011-10-14",
"go.weekly.2011-11-01",
"go1",
"go1.0.1",
"go1.999",
"go1.9.2",
"go5",
// these should be ignored:
"release.r59",
"release.r59.1",
"release",
"weekly.2011-10-12",
"weekly.2011-10-12.1",
"weekly",
"foo",
"bar",
"go.f00",
"go!r60",
"go.1999-01-01",
"go.2x",
"go.20000000000000",
"go.2.",
"go.2.0",
"go2x",
"go20000000000000",
"go2.",
"go2.0",
}
var selectTagTests = []struct {
version string
selected string
}{
/*
{"release.r57", ""},
{"release.r58.2", "go.r58.1"},
{"release.r59", "go.r59"},
{"release.r59.1", "go.r59.1"},
{"release.r60", "go.r59.1"},
{"release.r60.1", "go.r59.1"},
{"release.r61", "go.r61"},
{"release.r66", "go.r61.1"},
{"weekly.2010-01-01", ""},
{"weekly.2010-01-02", "go.weekly.2010-01-02"},
{"weekly.2010-01-02.1", "go.weekly.2010-01-02"},
{"weekly.2010-01-03", "go.weekly.2010-01-02"},
{"weekly.2011-10-12", "go.weekly.2011-10-12"},
{"weekly.2011-10-12.1", "go.weekly.2011-10-12.1"},
{"weekly.2011-10-13", "go.weekly.2011-10-12.1"},
{"weekly.2011-10-14", "go.weekly.2011-10-14"},
{"weekly.2011-10-14.1", "go.weekly.2011-10-14"},
{"weekly.2011-11-01", "go.weekly.2011-11-01"},
{"weekly.2014-01-01", "go.weekly.2011-11-01"},
{"weekly.3000-01-01", "go.weekly.2011-11-01"},
{"go1", "go1"},
{"go1.1", "go1.0.1"},
{"go1.998", "go1.9.2"},
{"go1.1000", "go1.999"},
{"go6", "go5"},
// faulty versions:
{"release.f00", ""},
{"weekly.1999-01-01", ""},
{"junk", ""},
{"", ""},
{"go2x", ""},
{"go200000000000", ""},
{"go2.", ""},
{"go2.0", ""},
*/
{"anything", "go1"},
}
func TestSelectTag(t *testing.T) {
for _, c := range selectTagTests {
selected := selectTag(c.version, selectTagTestTags)
if selected != c.selected {
t.Errorf("selectTag(%q) = %q, want %q", c.version, selected, c.selected)
}
}
}
#!/bin/bash
# Copyright 2012 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.
set -e
go build -o testgo
go() {
echo TEST ERROR: ran go, not testgo: go "$@" >&2
exit 2
}
started=false
TEST() {
if $started; then
stop
fi
echo TEST: "$@"
started=true
ok=true
}
stop() {
if ! $started; then
echo TEST ERROR: stop missing start >&2
exit 2
fi
started=false
if $ok; then
echo PASS
else
echo FAIL
allok=false
fi
}
ok=true
allok=true
unset GOBIN
unset GOPATH
unset GOROOT
TEST 'file:line in error messages'
# Test that error messages have file:line information at beginning of
# the line. Also test issue 4917: that the error is on stderr.
d=$(TMPDIR=/var/tmp mktemp -d -t testgoXXX)
fn=$d/err.go
echo "package main" > $fn
echo 'import "bar"' >> $fn
./testgo run $fn 2>$d/err.out || true
if ! grep -q "^$fn:" $d/err.out; then
echo "missing file:line in error message"
cat $d/err.out
ok=false
fi
rm -r $d
# Test local (./) imports.
testlocal() {
local="$1"
TEST local imports $2 '(easy)'
./testgo build -o hello "testdata/$local/easy.go"
./hello >hello.out
if ! grep -q '^easysub\.Hello' hello.out; then
echo "testdata/$local/easy.go did not generate expected output"
cat hello.out
ok=false
fi
TEST local imports $2 '(easysub)'
./testgo build -o hello "testdata/$local/easysub/main.go"
./hello >hello.out
if ! grep -q '^easysub\.Hello' hello.out; then
echo "testdata/$local/easysub/main.go did not generate expected output"
cat hello.out
ok=false
fi
TEST local imports $2 '(hard)'
./testgo build -o hello "testdata/$local/hard.go"
./hello >hello.out
if ! grep -q '^sub\.Hello' hello.out || ! grep -q '^subsub\.Hello' hello.out ; then
echo "testdata/$local/hard.go did not generate expected output"
cat hello.out
ok=false
fi
rm -f hello.out hello
# Test that go install x.go fails.
TEST local imports $2 '(go install should fail)'
if ./testgo install "testdata/$local/easy.go" >/dev/null 2>&1; then
echo "go install testdata/$local/easy.go succeeded"
ok=false
fi
}
# Test local imports
testlocal local ''
# Test local imports again, with bad characters in the directory name.
bad='#$%:, &()*;<=>?\^{}'
rm -rf "testdata/$bad"
cp -R testdata/local "testdata/$bad"
testlocal "$bad" 'with bad characters in path'
rm -rf "testdata/$bad"
TEST error message for syntax error in test go file says FAIL
export GOPATH=$(pwd)/testdata
if ./testgo test syntaxerror 2>testdata/err; then
echo 'go test syntaxerror succeeded'
ok=false
elif ! grep FAIL testdata/err >/dev/null; then
echo 'go test did not say FAIL:'
cat testdata/err
ok=false
fi
rm -f ./testdata/err
unset GOPATH
TEST wildcards do not look in useless directories
export GOPATH=$(pwd)/testdata
if ./testgo list ... >testdata/err 2>&1; then
echo "go list ... succeeded"
ok=false
elif ! grep badpkg testdata/err >/dev/null; then
echo "go list ... failure does not mention badpkg"
cat testdata/err
ok=false
elif ! ./testgo list m... >testdata/err 2>&1; then
echo "go list m... failed"
ok=false
fi
rm -rf ./testdata/err
unset GOPATH
# Test tests with relative imports.
TEST relative imports '(go test)'
if ! ./testgo test ./testdata/testimport; then
echo "go test ./testdata/testimport failed"
ok=false
fi
# Test installation with relative imports.
TEST relative imports '(go test -i)'
if ! ./testgo test -i ./testdata/testimport; then
echo "go test -i ./testdata/testimport failed"
ok=false
fi
# Test tests with relative imports in packages synthesized
# from Go files named on the command line.
TEST relative imports in command-line package
if ! ./testgo test ./testdata/testimport/*.go; then
echo "go test ./testdata/testimport/*.go failed"
ok=false
fi
TEST version control error message includes correct directory
export GOPATH=$(pwd)/testdata/shadow/root1
if ./testgo get -u foo 2>testdata/err; then
echo "go get -u foo succeeded unexpectedly"
ok=false
elif ! grep testdata/shadow/root1/src/foo testdata/err >/dev/null; then
echo "go get -u error does not mention shadow/root1/src/foo:"
cat testdata/err
ok=false
fi
unset GOPATH
TEST go install fails with no buildable files
export GOPATH=$(pwd)/testdata
export CGO_ENABLED=0
if ./testgo install cgotest 2>testdata/err; then
echo "go install cgotest succeeded unexpectedly"
elif ! grep 'no buildable Go source files' testdata/err >/dev/null; then
echo "go install cgotest did not report 'no buildable Go source files'"
cat testdata/err
ok=false
fi
unset CGO_ENABLED
unset GOPATH
# Test that without $GOBIN set, binaries get installed
# into the GOPATH bin directory.
TEST install into GOPATH
rm -rf testdata/bin
if ! GOPATH=$(pwd)/testdata ./testgo install go-cmd-test; then
echo "go install go-cmd-test failed"
ok=false
elif ! test -x testdata/bin/go-cmd-test; then
echo "go install go-cmd-test did not write to testdata/bin/go-cmd-test"
ok=false
fi
TEST package main_test imports archive not binary
export GOBIN=$(pwd)/testdata/bin
mkdir -p $GOBIN
export GOPATH=$(pwd)/testdata
touch ./testdata/src/main_test/m.go
if ! ./testgo test main_test; then
echo "go test main_test failed without install"
ok=false
elif ! ./testgo install main_test; then
echo "go test main_test failed"
ok=false
elif [ "$(./testgo list -f '{{.Stale}}' main_test)" != false ]; then
echo "after go install, main listed as stale"
ok=false
elif ! ./testgo test main_test; then
echo "go test main_test failed after install"
ok=false
fi
rm -rf $GOBIN
unset GOBIN
# And with $GOBIN set, binaries get installed to $GOBIN.
TEST install into GOBIN
if ! GOBIN=$(pwd)/testdata/bin1 GOPATH=$(pwd)/testdata ./testgo install go-cmd-test; then
echo "go install go-cmd-test failed"
ok=false
elif ! test -x testdata/bin1/go-cmd-test; then
echo "go install go-cmd-test did not write to testdata/bin1/go-cmd-test"
ok=false
fi
# Without $GOBIN set, installing a program outside $GOPATH should fail
# (there is nowhere to install it).
TEST install without destination fails
if ./testgo install testdata/src/go-cmd-test/helloworld.go 2>testdata/err; then
echo "go install testdata/src/go-cmd-test/helloworld.go should have failed, did not"
ok=false
elif ! grep 'no install location for .go files listed on command line' testdata/err; then
echo "wrong error:"
cat testdata/err
ok=false
fi
rm -f testdata/err
# With $GOBIN set, should install there.
TEST install to GOBIN '(command-line package)'
if ! GOBIN=$(pwd)/testdata/bin1 ./testgo install testdata/src/go-cmd-test/helloworld.go; then
echo "go install testdata/src/go-cmd-test/helloworld.go failed"
ok=false
elif ! test -x testdata/bin1/helloworld; then
echo "go install testdata/src/go-cmd-test/helloworld.go did not write testdata/bin1/helloworld"
ok=false
fi
TEST godoc installs into GOBIN
d=$(mktemp -d -t testgoXXX)
export GOPATH=$d
mkdir $d/gobin
GOBIN=$d/gobin ./testgo get code.google.com/p/go.tools/cmd/godoc
if [ ! -x $d/gobin/godoc ]; then
echo did not install godoc to '$GOBIN'
GOBIN=$d/gobin ./testgo list -f 'Target: {{.Target}}' code.google.com/p/go.tools/cmd/godoc
ok=false
fi
TEST godoc installs into GOROOT
GOROOT=$(./testgo env GOROOT)
rm -f $GOROOT/bin/godoc
./testgo install code.google.com/p/go.tools/cmd/godoc
if [ ! -x $GOROOT/bin/godoc ]; then
echo did not install godoc to '$GOROOT/bin'
./testgo list -f 'Target: {{.Target}}' code.google.com/p/go.tools/cmd/godoc
ok=false
fi
TEST cmd/fix installs into tool
GOOS=$(./testgo env GOOS)
GOARCH=$(./testgo env GOARCH)
rm -f $GOROOT/pkg/tool/${GOOS}_${GOARCH}/fix
./testgo install cmd/fix
if [ ! -x $GOROOT/pkg/tool/${GOOS}_${GOARCH}/fix ]; then
echo 'did not install cmd/fix to $GOROOT/pkg/tool'
GOBIN=$d/gobin ./testgo list -f 'Target: {{.Target}}' cmd/fix
ok=false
fi
rm -f $GOROOT/pkg/tool/${GOOS}_${GOARCH}/fix
GOBIN=$d/gobin ./testgo install cmd/fix
if [ ! -x $GOROOT/pkg/tool/${GOOS}_${GOARCH}/fix ]; then
echo 'did not install cmd/fix to $GOROOT/pkg/tool with $GOBIN set'
GOBIN=$d/gobin ./testgo list -f 'Target: {{.Target}}' cmd/fix
ok=false
fi
TEST gopath program installs into GOBIN
mkdir $d/src/progname
echo 'package main; func main() {}' >$d/src/progname/p.go
GOBIN=$d/gobin ./testgo install progname
if [ ! -x $d/gobin/progname ]; then
echo 'did not install progname to $GOBIN/progname'
./testgo list -f 'Target: {{.Target}}' cmd/api
ok=false
fi
rm -f $d/gobin/progname $d/bin/progname
TEST gopath program installs into GOPATH/bin
./testgo install progname
if [ ! -x $d/bin/progname ]; then
echo 'did not install progname to $GOPATH/bin/progname'
./testgo list -f 'Target: {{.Target}}' progname
ok=false
fi
unset GOPATH
rm -rf $d
# Reject relative paths in GOPATH.
TEST reject relative paths in GOPATH '(command-line package)'
if GOPATH=. ./testgo build testdata/src/go-cmd-test/helloworld.go; then
echo 'GOPATH="." go build should have failed, did not'
ok=false
fi
TEST reject relative paths in GOPATH
if GOPATH=:$(pwd)/testdata:. ./testgo build go-cmd-test; then
echo 'GOPATH=":$(pwd)/testdata:." go build should have failed, did not'
ok=false
fi
# issue 4104
TEST go test with package listed multiple times
if [ $(./testgo test fmt fmt fmt fmt fmt | wc -l) -ne 1 ] ; then
echo 'go test fmt fmt fmt fmt fmt tested the same package multiple times'
ok=false
fi
# ensure that output of 'go list' is consistent between runs
TEST go list is consistent
./testgo list std > test_std.list
if ! ./testgo list std | cmp -s test_std.list - ; then
echo "go list std ordering is inconsistent"
ok=false
fi
rm -f test_std.list
# issue 4096. Validate the output of unsuccessful go install foo/quxx
TEST unsuccessful go install should mention missing package
if [ $(./testgo install 'foo/quxx' 2>&1 | grep -c 'cannot find package "foo/quxx" in any of') -ne 1 ] ; then
echo 'go install foo/quxx expected error: .*cannot find package "foo/quxx" in any of'
ok=false
fi
# test GOROOT search failure is reported
TEST GOROOT search failure reporting
if [ $(./testgo install 'foo/quxx' 2>&1 | egrep -c 'foo/quxx \(from \$GOROOT\)$') -ne 1 ] ; then
echo 'go install foo/quxx expected error: .*foo/quxx (from $GOROOT)'
ok=false
fi
# test multiple GOPATH entries are reported separately
TEST multiple GOPATH entries reported separately
if [ $(GOPATH=$(pwd)/testdata/a:$(pwd)/testdata/b ./testgo install 'foo/quxx' 2>&1 | egrep -c 'testdata/./src/foo/quxx') -ne 2 ] ; then
echo 'go install foo/quxx expected error: .*testdata/a/src/foo/quxx (from $GOPATH)\n.*testdata/b/src/foo/quxx'
ok=false
fi
# test (from $GOPATH) annotation is reported for the first GOPATH entry
TEST mention GOPATH in first GOPATH entry
if [ $(GOPATH=$(pwd)/testdata/a:$(pwd)/testdata/b ./testgo install 'foo/quxx' 2>&1 | egrep -c 'testdata/a/src/foo/quxx \(from \$GOPATH\)$') -ne 1 ] ; then
echo 'go install foo/quxx expected error: .*testdata/a/src/foo/quxx (from $GOPATH)'
ok=false
fi
# but not on the second
TEST but not the second entry
if [ $(GOPATH=$(pwd)/testdata/a:$(pwd)/testdata/b ./testgo install 'foo/quxx' 2>&1 | egrep -c 'testdata/b/src/foo/quxx$') -ne 1 ] ; then
echo 'go install foo/quxx expected error: .*testdata/b/src/foo/quxx'
ok=false
fi
# test missing GOPATH is reported
TEST missing GOPATH is reported
if [ $(GOPATH= ./testgo install 'foo/quxx' 2>&1 | egrep -c '\(\$GOPATH not set\)$') -ne 1 ] ; then
echo 'go install foo/quxx expected error: ($GOPATH not set)'
ok=false
fi
# issue 4186. go get cannot be used to download packages to $GOROOT
# Test that without GOPATH set, go get should fail
TEST without GOPATH, go get fails
d=$(mktemp -d -t testgoXXX)
mkdir -p $d/src/pkg
if GOPATH= GOROOT=$d ./testgo get -d code.google.com/p/go.codereview/cmd/hgpatch ; then
echo 'go get code.google.com/p/go.codereview/cmd/hgpatch should not succeed with $GOPATH unset'
ok=false
fi
rm -rf $d
# Test that with GOPATH=$GOROOT, go get should fail
TEST with GOPATH=GOROOT, go get fails
d=$(mktemp -d -t testgoXXX)
mkdir -p $d/src/pkg
if GOPATH=$d GOROOT=$d ./testgo get -d code.google.com/p/go.codereview/cmd/hgpatch ; then
echo 'go get code.google.com/p/go.codereview/cmd/hgpatch should not succeed with GOPATH=$GOROOT'
ok=false
fi
rm -rf $d
TEST ldflags arguments with spaces '(issue 3941)'
d=$(mktemp -d -t testgoXXX)
cat >$d/main.go<<EOF
package main
var extern string
func main() {
println(extern)
}
EOF
./testgo run -ldflags '-X main.extern "hello world"' $d/main.go 2>hello.out
if ! grep -q '^hello world' hello.out; then
echo "ldflags -X main.extern 'hello world' failed. Output:"
cat hello.out
ok=false
fi
rm -rf $d hello.out
TEST go test -cpuprofile leaves binary behind
./testgo test -cpuprofile strings.prof strings || ok=false
if [ ! -x strings.test ]; then
echo "go test -cpuprofile did not create strings.test"
ok=false
fi
rm -f strings.prof strings.test
TEST symlinks do not confuse go list '(issue 4568)'
old=$(pwd)
tmp=$(cd /tmp && pwd -P)
d=$(TMPDIR=$tmp mktemp -d -t testgoXXX)
mkdir -p $d/src
(
ln -s $d $d/src/dir1
cd $d/src
echo package p >dir1/p.go
export GOPATH=$d
if [ "$($old/testgo list -f '{{.Root}}' dir1)" != "$d" ]; then
echo Confused by symlinks.
echo "Package in current directory $(pwd) should have Root $d"
env|grep WD
$old/testgo list -json . dir1
touch $d/failed
fi
)
if [ -f $d/failed ]; then
ok=false
fi
rm -rf $d
TEST 'install with tags (issue 4515)'
d=$(TMPDIR=/var/tmp mktemp -d -t testgoXXX)
mkdir -p $d/src/example/a $d/src/example/b $d/bin
cat >$d/src/example/a/main.go <<EOF
package main
func main() {}
EOF
cat >$d/src/example/b/main.go <<EOF
// +build mytag
package main
func main() {}
EOF
GOPATH=$d ./testgo install -tags mytag example/a example/b || ok=false
if [ ! -x $d/bin/a -o ! -x $d/bin/b ]; then
echo go install example/a example/b did not install binaries
ok=false
fi
rm -f $d/bin/*
GOPATH=$d ./testgo install -tags mytag example/... || ok=false
if [ ! -x $d/bin/a -o ! -x $d/bin/b ]; then
echo go install example/... did not install binaries
ok=false
fi
rm -f $d/bin/*go
export GOPATH=$d
if [ "$(./testgo list -tags mytag example/b...)" != "example/b" ]; then
echo go list example/b did not find example/b
ok=false
fi
unset GOPATH
rm -rf $d
TEST case collisions '(issue 4773)'
d=$(TMPDIR=/var/tmp mktemp -d -t testgoXXX)
export GOPATH=$d
mkdir -p $d/src/example/{a/pkg,a/Pkg,b}
cat >$d/src/example/a/a.go <<EOF
package p
import (
_ "example/a/pkg"
_ "example/a/Pkg"
)
EOF
cat >$d/src/example/a/pkg/pkg.go <<EOF
package pkg
EOF
cat >$d/src/example/a/Pkg/pkg.go <<EOF
package pkg
EOF
if ./testgo list example/a 2>$d/out; then
echo go list example/a should have failed, did not.
ok=false
elif ! grep "case-insensitive import collision" $d/out >/dev/null; then
echo go list example/a did not report import collision.
ok=false
fi
cat >$d/src/example/b/file.go <<EOF
package b
EOF
cat >$d/src/example/b/FILE.go <<EOF
package b
EOF
if [ $(ls $d/src/example/b | wc -l) = 2 ]; then
# case-sensitive file system, let directory read find both files
args="example/b"
else
# case-insensitive file system, list files explicitly on command line.
args="$d/src/example/b/file.go $d/src/example/b/FILE.go"
fi
if ./testgo list $args 2>$d/out; then
echo go list example/b should have failed, did not.
ok=false
elif ! grep "case-insensitive file name collision" $d/out >/dev/null; then
echo go list example/b did not report file name collision.
ok=false
fi
TEST go get cover
./testgo get code.google.com/p/go.tools/cmd/cover || ok=false
unset GOPATH
rm -rf $d
TEST shadowing logic
export GOPATH=$(pwd)/testdata/shadow/root1:$(pwd)/testdata/shadow/root2
# The math in root1 is not "math" because the standard math is.
cdir=$(./testgo list -f '({{.ImportPath}}) ({{.ConflictDir}})' ./testdata/shadow/root1/src/math)
if [ "$cdir" != "(_$(pwd)/testdata/shadow/root1/src/math) ($GOROOT/src/pkg/math)" ]; then
echo shadowed math is not shadowed: "$cdir"
ok=false
fi
# The foo in root1 is "foo".
cdir=$(./testgo list -f '({{.ImportPath}}) ({{.ConflictDir}})' ./testdata/shadow/root1/src/foo)
if [ "$cdir" != "(foo) ()" ]; then
echo unshadowed foo is shadowed: "$cdir"
ok=false
fi
# The foo in root2 is not "foo" because the foo in root1 got there first.
cdir=$(./testgo list -f '({{.ImportPath}}) ({{.ConflictDir}})' ./testdata/shadow/root2/src/foo)
if [ "$cdir" != "(_$(pwd)/testdata/shadow/root2/src/foo) ($(pwd)/testdata/shadow/root1/src/foo)" ]; then
echo shadowed foo is not shadowed: "$cdir"
ok=false
fi
# The error for go install should mention the conflicting directory.
err=$(! ./testgo install ./testdata/shadow/root2/src/foo 2>&1)
if [ "$err" != "go install: no install location for $(pwd)/testdata/shadow/root2/src/foo: hidden by $(pwd)/testdata/shadow/root1/src/foo" ]; then
echo wrong shadowed install error: "$err"
ok=false
fi
# Only succeeds if source order is preserved.
TEST source file name order preserved
./testgo test testdata/example[12]_test.go || ok=false
# Check that coverage analysis works at all.
# Don't worry about the exact numbers but require not 0.0%.
checkcoverage() {
if grep '[^0-9]0\.0%' testdata/cover.txt >/dev/null; then
echo 'some coverage results are 0.0%'
ok=false
fi
cat testdata/cover.txt
rm -f testdata/cover.txt
}
TEST coverage runs
./testgo test -short -coverpkg=strings strings regexp >testdata/cover.txt 2>&1 || ok=false
./testgo test -short -cover strings math regexp >>testdata/cover.txt 2>&1 || ok=false
checkcoverage
# Check that coverage analysis uses set mode.
TEST coverage uses set mode
if ./testgo test -short -cover encoding/binary -coverprofile=testdata/cover.out >testdata/cover.txt 2>&1; then
if ! grep -q 'mode: set' testdata/cover.out; then
ok=false
fi
checkcoverage
else
ok=false
fi
rm -f testdata/cover.out testdata/cover.txt
TEST coverage uses atomic mode for -race.
if ./testgo test -short -race -cover encoding/binary -coverprofile=testdata/cover.out >testdata/cover.txt 2>&1; then
if ! grep -q 'mode: atomic' testdata/cover.out; then
ok=false
fi
checkcoverage
else
ok=false
fi
rm -f testdata/cover.out
TEST coverage uses actual setting to override even for -race.
if ./testgo test -short -race -cover encoding/binary -covermode=count -coverprofile=testdata/cover.out >testdata/cover.txt 2>&1; then
if ! grep -q 'mode: count' testdata/cover.out; then
ok=false
fi
checkcoverage
else
ok=false
fi
rm -f testdata/cover.out
TEST coverage with cgo
d=$(TMPDIR=/var/tmp mktemp -d -t testgoXXX)
./testgo test -short -cover ./testdata/cgocover >testdata/cover.txt 2>&1 || ok=false
checkcoverage
TEST cgo depends on syscall
rm -rf $GOROOT/pkg/*_race
d=$(TMPDIR=/var/tmp mktemp -d -t testgoXXX)
export GOPATH=$d
mkdir -p $d/src/foo
echo '
package foo
//#include <stdio.h>
import "C"
' >$d/src/foo/foo.go
./testgo build -race foo || ok=false
rm -rf $d
unset GOPATH
TEST cgo shows full path names
d=$(TMPDIR=/var/tmp mktemp -d -t testgoXXX)
export GOPATH=$d
mkdir -p $d/src/x/y/dirname
echo '
package foo
import "C"
func f() {
' >$d/src/x/y/dirname/foo.go
if ./testgo build x/y/dirname >$d/err 2>&1; then
echo build succeeded unexpectedly.
ok=false
elif ! grep x/y/dirname $d/err >/dev/null; then
echo error did not use full path.
cat $d/err
ok=false
fi
rm -rf $d
unset GOPATH
TEST 'cgo handles -Wl,$ORIGIN'
d=$(TMPDIR=/var/tmp mktemp -d -t testgoXXX)
export GOPATH=$d
mkdir -p $d/src/origin
echo '
package origin
// #cgo !darwin LDFLAGS: -Wl,-rpath -Wl,$ORIGIN
// void f(void) {}
import "C"
func f() { C.f() }
' >$d/src/origin/origin.go
if ! ./testgo build origin; then
echo build failed
ok=false
fi
rm -rf $d
unset GOPATH
TEST 'Issue 6480: "go test -c -test.bench=XXX fmt" should not hang'
if ! ./testgo test -c -test.bench=XXX fmt; then
echo build test failed
ok=false
fi
rm -f fmt.test
TEST 'Issue 7573: cmd/cgo: undefined reference when linking a C-library using gccgo'
d=$(mktemp -d -t testgoXXX)
export GOPATH=$d
mkdir -p $d/src/cgoref
ldflags="-L alibpath -lalib"
echo "
package main
// #cgo LDFLAGS: $ldflags
// void f(void) {}
import \"C\"
func main() { C.f() }
" >$d/src/cgoref/cgoref.go
go_cmds="$(./testgo build -n -compiler gccgo cgoref 2>&1 1>/dev/null)"
ldflags_count="$(echo "$go_cmds" | egrep -c "^gccgo.*$(echo $ldflags | sed -e 's/-/\\-/g')" || true)"
if [ "$ldflags_count" -lt 1 ]; then
echo "No Go-inline "#cgo LDFLAGS:" (\"$ldflags\") passed to gccgo linking stage."
ok=false
fi
rm -rf $d
unset ldflags_count
unset go_cmds
unset ldflags
unset GOPATH
TEST list template can use context function
if ! ./testgo list -f "GOARCH: {{context.GOARCH}}"; then
echo unable to use context in list template
ok=false
fi
TEST 'Issue 7108: cmd/go: "go test" should fail if package does not build'
export GOPATH=$(pwd)/testdata
if ./testgo test notest >/dev/null 2>&1; then
echo 'go test notest succeeded, but should fail'
ok=false
fi
unset GOPATH
TEST 'Issue 6844: cmd/go: go test -a foo does not rebuild regexp'
if ! ./testgo test -x -a -c testdata/dep_test.go 2>deplist; then
echo "go test -x -a -c testdata/dep_test.go failed"
ok=false
elif ! grep -q regexp deplist; then
echo "go test -x -a -c testdata/dep_test.go did not rebuild regexp"
ok=false
fi
rm -f deplist
rm -f deps.test
TEST list template can use context function
if ! ./testgo list -f "GOARCH: {{context.GOARCH}}"; then
echo unable to use context in list template
ok=false
fi
TEST build -i installs dependencies
d=$(TMPDIR=/var/tmp mktemp -d -t testgoXXX)
export GOPATH=$d
mkdir -p $d/src/x/y/foo $d/src/x/y/bar
echo '
package foo
func F() {}
' >$d/src/x/y/foo/foo.go
echo '
package bar
import "x/y/foo"
func F() { foo.F() }
' >$d/src/x/y/bar/bar.go
if ! ./testgo build -v -i x/y/bar &> $d/err; then
echo build -i failed
cat $d/err
ok=false
elif ! grep x/y/foo $d/err >/dev/null; then
echo first build -i did not build x/y/foo
cat $d/err
ok=false
fi
if ! ./testgo build -v -i x/y/bar &> $d/err; then
echo second build -i failed
cat $d/err
ok=false
elif grep x/y/foo $d/err >/dev/null; then
echo second build -i built x/y/foo
cat $d/err
ok=false
fi
rm -rf $d
unset GOPATH
TEST 'go build in test-only directory fails with a good error'
if ./testgo build ./testdata/testonly 2>testdata/err.out; then
echo "go build ./testdata/testonly succeeded, should have failed"
ok=false
elif ! grep 'no buildable Go' testdata/err.out >/dev/null; then
echo "go build ./testdata/testonly produced unexpected error:"
cat testdata/err.out
ok=false
fi
rm -f testdata/err.out
TEST 'go test detects test-only import cycles'
export GOPATH=$(pwd)/testdata
if ./testgo test -c testcycle/p3 2>testdata/err.out; then
echo "go test testcycle/p3 succeeded, should have failed"
ok=false
elif ! grep 'import cycle not allowed in test' testdata/err.out >/dev/null; then
echo "go test testcycle/p3 produced unexpected error:"
cat testdata/err.out
ok=false
fi
rm -f testdata/err.out
unset GOPATH
TEST 'go test foo_test.go works'
if ! ./testgo test testdata/standalone_test.go; then
echo "go test testdata/standalone_test.go failed"
ok=false
fi
TEST 'go test xtestonly works'
export GOPATH=$(pwd)/testdata
./testgo clean -i xtestonly
if ! ./testgo test xtestonly >/dev/null; then
echo "go test xtestonly failed"
ok=false
fi
unset GOPATH
# clean up
if $started; then stop; fi
rm -rf testdata/bin testdata/bin1
rm -f testgo
if $allok; then
echo PASS
else
echo FAIL
exit 1
fi
// Copyright 2011 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"
"go/ast"
"go/build"
"go/doc"
"go/parser"
"go/token"
"log"
"os"
"os/exec"
"path"
"path/filepath"
"regexp"
"runtime"
"sort"
"strings"
"text/template"
"time"
"unicode"
"unicode/utf8"
)
// Break init loop.
func init() {
cmdTest.Run = runTest
}
var cmdTest = &Command{
CustomFlags: true,
UsageLine: "test [-c] [-i] [build and test flags] [packages] [flags for test binary]",
Short: "test packages",
Long: `
'Go test' automates testing the packages named by the import paths.
It prints a summary of the test results in the format:
ok archive/tar 0.011s
FAIL archive/zip 0.022s
ok compress/gzip 0.033s
...
followed by detailed output for each failed package.
'Go test' recompiles each package along with any files with names matching
the file pattern "*_test.go".
Files whose names begin with "_" (including "_test.go") or "." are ignored.
These additional files can contain test functions, benchmark functions, and
example functions. See 'go help testfunc' for more.
Each listed package causes the execution of a separate test binary.
Test files that declare a package with the suffix "_test" will be compiled as a
separate package, and then linked and run with the main test binary.
By default, go test needs no arguments. It compiles and tests the package
with source in the current directory, including tests, and runs the tests.
The package is built in a temporary directory so it does not interfere with the
non-test installation.
In addition to the build flags, the flags handled by 'go test' itself are:
-c Compile the test binary to pkg.test but do not run it.
(Where pkg is the last element of the package's import path.)
-i
Install packages that are dependencies of the test.
Do not run the test.
-exec xprog
Run the test binary using xprog. The behavior is the same as
in 'go run'. See 'go help run' for details.
The test binary also accepts flags that control execution of the test; these
flags are also accessible by 'go test'. See 'go help testflag' for details.
If the test binary needs any other flags, they should be presented after the
package names. The go tool treats as a flag the first argument that begins with
a minus sign that it does not recognize itself; that argument and all subsequent
arguments are passed as arguments to the test binary.
For more about build flags, see 'go help build'.
For more about specifying packages, see 'go help packages'.
See also: go build, go vet.
`,
}
var helpTestflag = &Command{
UsageLine: "testflag",
Short: "description of testing flags",
Long: `
The 'go test' command takes both flags that apply to 'go test' itself
and flags that apply to the resulting test binary.
Several of the flags control profiling and write an execution profile
suitable for "go tool pprof"; run "go tool pprof help" for more
information. The --alloc_space, --alloc_objects, and --show_bytes
options of pprof control how the information is presented.
The following flags are recognized by the 'go test' command and
control the execution of any test:
-bench regexp
Run benchmarks matching the regular expression.
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.
-blockprofilerate n
Control the detail provided in goroutine blocking profiles by
calling runtime.SetBlockProfileRate with n.
See 'godoc 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.
-cover
Enable coverage analysis.
-covermode set,count,atomic
Set the mode for coverage analysis for the package[s]
being tested. The default is "set" unless -race is enabled,
in which case it is "atomic".
The values:
set: bool: does this statement run?
count: int: how many times does this statement run?
atomic: int: count, but correct in multithreaded tests;
significantly more expensive.
Sets -cover.
-coverpkg pkg1,pkg2,pkg3
Apply coverage analysis in each test to the given list of packages.
The default is for each test to analyze only the package being tested.
Packages are specified as import paths.
Sets -cover.
-coverprofile cover.out
Write a coverage profile to the specified 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.
-memprofile mem.out
Write a memory profile to the specified file after all tests
have passed.
-memprofilerate n
Enable more precise (and expensive) memory profiles by setting
runtime.MemProfileRate. See 'godoc runtime MemProfileRate'.
To profile all memory allocations, use -test.memprofilerate=1
and 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
simultaneously; by default, it is set to the value of GOMAXPROCS.
-run regexp
Run only those tests and examples matching the regular
expression.
-short
Tell long-running tests to shorten their run time.
It is off by default but set during all.bash so that installing
the Go tree can run a sanity check but not spend time running
exhaustive tests.
-timeout t
If a test runs longer than t, panic.
-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 test binary, called pkg.test where pkg is the name of the
directory containing the package sources, can be invoked directly
after building it with 'go test -c'. When invoking the test binary
directly, each of the standard flag names must be prefixed with 'test.',
as in -test.run=TestMyFunc or -test.v.
When running 'go test', flags not listed above are passed through
unaltered. For instance, the command
go test -x -v -cpuprofile=prof.out -dir=testdata -update
will compile the test binary and then run it as
pkg.test -test.v -test.cpuprofile=prof.out -dir=testdata -update
The test flags that generate profiles (other than for coverage) also
leave the test binary in pkg.test for use when analyzing the profiles.
Flags not recognized by 'go test' must be placed after any specified packages.
`,
}
var helpTestfunc = &Command{
UsageLine: "testfunc",
Short: "description of testing functions",
Long: `
The 'go test' command expects to find test, benchmark, and example functions
in the "*_test.go" files corresponding to the package under test.
A test function is one named TestXXX (where XXX is any alphanumeric string
not starting with a lower case letter) and should have the signature,
func TestXXX(t *testing.T) { ... }
A benchmark function is one named BenchmarkXXX and should have the signature,
func BenchmarkXXX(b *testing.B) { ... }
An example function is similar to a test function but, instead of using
*testing.T to report success or failure, prints output to os.Stdout.
That output is compared against the function's "Output:" comment, which
must be the last comment in the function body (see example below). An
example with no such comment, or with no text after "Output:" is compiled
but not executed.
Godoc displays the body of ExampleXXX to demonstrate the use
of the function, constant, or variable XXX. An example of a method M with
receiver type T or *T is named ExampleT_M. There may be multiple examples
for a given function, constant, or variable, distinguished by a trailing _xxx,
where xxx is a suffix not beginning with an upper case letter.
Here is an example of an example:
func ExamplePrintln() {
Println("The output of\nthis example.")
// Output: The output of
// this example.
}
The entire test file is presented as the example when it contains a single
example function, at least one other function, type, variable, or constant
declaration, and no test or benchmark functions.
See the documentation of the testing package for more information.
`,
}
var (
testC bool // -c flag
testCover bool // -cover flag
testCoverMode string // -covermode flag
testCoverPaths []string // -coverpkg flag
testCoverPkgs []*Package // -coverpkg flag
testProfile bool // some profiling flag
testNeedBinary bool // profile needs to keep binary around
testV bool // -v flag
testFiles []string // -file flag(s) TODO: not respected
testTimeout string // -timeout flag
testArgs []string
testBench bool
testStreamOutput bool // show output as it is generated
testShowPass bool // show passing output
testKillTimeout = 10 * time.Minute
)
var testMainDeps = map[string]bool{
// Dependencies for testmain.
"testing": true,
"regexp": true,
}
func runTest(cmd *Command, args []string) {
var pkgArgs []string
pkgArgs, testArgs = testFlags(args)
findExecCmd() // initialize cached result
raceInit()
pkgs := packagesForBuild(pkgArgs)
if len(pkgs) == 0 {
fatalf("no packages to test")
}
if testC && len(pkgs) != 1 {
fatalf("cannot use -c flag with multiple packages")
}
if testProfile && len(pkgs) != 1 {
fatalf("cannot use test profile flag with multiple packages")
}
// If a test timeout was given and is parseable, set our kill timeout
// to that timeout plus one minute. This is a backup alarm in case
// the test wedges with a goroutine spinning and its background
// timer does not get a chance to fire.
if dt, err := time.ParseDuration(testTimeout); err == nil && dt > 0 {
testKillTimeout = dt + 1*time.Minute
}
// show passing test output (after buffering) with -v flag.
// must buffer because tests are running in parallel, and
// otherwise the output will get mixed.
testShowPass = testV
// stream test output (no buffering) when no package has
// been given on the command line (implicit current directory)
// or when benchmarking.
// Also stream if we're showing output anyway with a
// single package under test. In that case, streaming the
// output produces the same result as not streaming,
// just more immediately.
testStreamOutput = len(pkgArgs) == 0 || testBench ||
(len(pkgs) <= 1 && testShowPass)
var b builder
b.init()
if buildI {
buildV = testV
deps := make(map[string]bool)
for dep := range testMainDeps {
deps[dep] = true
}
for _, p := range pkgs {
// Dependencies for each test.
for _, path := range p.Imports {
deps[path] = true
}
for _, path := range p.TestImports {
deps[path] = true
}
for _, path := range p.XTestImports {
deps[path] = true
}
}
// translate C to runtime/cgo
if deps["C"] {
delete(deps, "C")
deps["runtime/cgo"] = true
if buildContext.GOOS == runtime.GOOS && buildContext.GOARCH == runtime.GOARCH {
deps["cmd/cgo"] = true
}
}
// Ignore pseudo-packages.
delete(deps, "unsafe")
all := []string{}
if reqPkgSrc {
for path := range deps {
if !build.IsLocalImport(path) {
all = append(all, path)
}
}
}
sort.Strings(all)
a := &action{}
for _, p := range packagesForBuild(all) {
a.deps = append(a.deps, b.action(modeInstall, modeInstall, p))
}
b.do(a)
if !testC || a.failed {
return
}
b.init()
}
var builds, runs, prints []*action
if testCoverPaths != nil {
// Load packages that were asked about for coverage.
// packagesForBuild exits if the packages cannot be loaded.
testCoverPkgs = packagesForBuild(testCoverPaths)
// Warn about -coverpkg arguments that are not actually used.
used := make(map[string]bool)
for _, p := range pkgs {
used[p.ImportPath] = true
for _, dep := range p.Deps {
used[dep] = true
}
}
for _, p := range testCoverPkgs {
if !used[p.ImportPath] {
log.Printf("warning: no packages being tested depend on %s", p.ImportPath)
}
}
// Mark all the coverage packages for rebuilding with coverage.
for _, p := range testCoverPkgs {
p.Stale = true // rebuild
p.fake = true // do not warn about rebuild
p.coverMode = testCoverMode
var coverFiles []string
coverFiles = append(coverFiles, p.GoFiles...)
coverFiles = append(coverFiles, p.CgoFiles...)
coverFiles = append(coverFiles, p.TestGoFiles...)
p.coverVars = declareCoverVars(p.ImportPath, coverFiles...)
}
}
// Prepare build + run + print actions for all packages being tested.
for _, p := range pkgs {
buildTest, runTest, printTest, err := b.test(p)
if err != nil {
str := err.Error()
if strings.HasPrefix(str, "\n") {
str = str[1:]
}
failed := fmt.Sprintf("FAIL\t%s [setup failed]\n", p.ImportPath)
if p.ImportPath != "" {
errorf("# %s\n%s\n%s", p.ImportPath, str, failed)
} else {
errorf("%s\n%s", str, failed)
}
continue
}
builds = append(builds, buildTest)
runs = append(runs, runTest)
prints = append(prints, printTest)
}
// Ultimately the goal is to print the output.
root := &action{deps: prints}
// Force the printing of results to happen in order,
// one at a time.
for i, a := range prints {
if i > 0 {
a.deps = append(a.deps, prints[i-1])
}
}
// Force benchmarks to run in serial.
if !testC && testBench {
// The first run must wait for all builds.
// Later runs must wait for the previous run's print.
for i, run := range runs {
if i == 0 {
run.deps = append(run.deps, builds...)
} else {
run.deps = append(run.deps, prints[i-1])
}
}
}
// If we are building any out-of-date packages other
// than those under test, warn.
okBuild := map[*Package]bool{}
for _, p := range pkgs {
okBuild[p] = true
}
warned := false
for _, a := range actionList(root) {
if a.p == nil || okBuild[a.p] {
continue
}
okBuild[a.p] = true // warn at most once
// Don't warn about packages being rebuilt because of
// things like coverage analysis.
for _, p1 := range a.p.imports {
if p1.fake {
a.p.fake = true
}
}
if a.f != nil && !okBuild[a.p] && !a.p.fake && !a.p.local {
if !warned {
fmt.Fprintf(os.Stderr, "warning: building out-of-date packages:\n")
warned = true
}
fmt.Fprintf(os.Stderr, "\t%s\n", a.p.ImportPath)
}
}
if warned {
args := strings.Join(pkgArgs, " ")
if args != "" {
args = " " + args
}
extraOpts := ""
if buildRace {
extraOpts = "-race "
}
fmt.Fprintf(os.Stderr, "installing these packages with 'go test %s-i%s' will speed future tests.\n\n", extraOpts, args)
}
b.do(root)
}
func contains(x []string, s string) bool {
for _, t := range x {
if t == s {
return true
}
}
return false
}
func (b *builder) test(p *Package) (buildAction, runAction, printAction *action, err error) {
if len(p.TestGoFiles)+len(p.XTestGoFiles) == 0 {
build := b.action(modeBuild, modeBuild, p)
run := &action{p: p, deps: []*action{build}}
print := &action{f: (*builder).notest, p: p, deps: []*action{run}}
return build, run, print, nil
}
// Build Package structs describing:
// ptest - package + test files
// pxtest - package of external test files
// pmain - pkg.test binary
var ptest, pxtest, pmain *Package
var imports, ximports []*Package
var stk importStack
stk.push(p.ImportPath + " (test)")
for _, path := range p.TestImports {
p1 := loadImport(path, p.Dir, &stk, p.build.TestImportPos[path])
if !reqPkgSrc && p1.Root == "" {
continue
}
if p1.Error != nil {
return nil, nil, nil, p1.Error
}
if contains(p1.Deps, p.ImportPath) {
// Same error that loadPackage returns (via reusePackage) in pkg.go.
// Can't change that code, because that code is only for loading the
// non-test copy of a package.
err := &PackageError{
ImportStack: testImportStack(stk[0], p1, p.ImportPath),
Err: "import cycle not allowed in test",
isImportCycle: true,
}
return nil, nil, nil, err
}
imports = append(imports, p1)
}
stk.pop()
stk.push(p.ImportPath + "_test")
pxtestNeedsPtest := false
for _, path := range p.XTestImports {
if path == p.ImportPath {
pxtestNeedsPtest = true
continue
}
p1 := loadImport(path, p.Dir, &stk, p.build.XTestImportPos[path])
if !reqPkgSrc && p1.Root == "" {
continue
}
if p1.Error != nil {
return nil, nil, nil, p1.Error
}
ximports = append(ximports, p1)
}
stk.pop()
// Use last element of import path, not package name.
// They differ when package name is "main".
// But if the import path is "command-line-arguments",
// like it is during 'go run', use the package name.
var elem string
if p.ImportPath == "command-line-arguments" {
elem = p.Name
} else {
_, elem = path.Split(p.ImportPath)
}
testBinary := elem + ".test"
// The ptest package needs to be importable under the
// same import path that p has, but we cannot put it in
// the usual place in the temporary tree, because then
// other tests will see it as the real package.
// Instead we make a _test directory under the import path
// and then repeat the import path there. We tell the
// compiler and linker to look in that _test directory first.
//
// That is, if the package under test is unicode/utf8,
// then the normal place to write the package archive is
// $WORK/unicode/utf8.a, but we write the test package archive to
// $WORK/unicode/utf8/_test/unicode/utf8.a.
// We write the external test package archive to
// $WORK/unicode/utf8/_test/unicode/utf8_test.a.
testDir := filepath.Join(b.work, filepath.FromSlash(p.ImportPath+"/_test"))
ptestObj := buildToolchain.pkgpath(testDir, p)
// Create the directory for the .a files.
ptestDir, _ := filepath.Split(ptestObj)
if err := b.mkdir(ptestDir); err != nil {
return nil, nil, nil, err
}
// Should we apply coverage analysis locally,
// only for this package and only for this test?
// Yes, if -cover is on but -coverpkg has not specified
// a list of packages for global coverage.
localCover := testCover && testCoverPaths == nil
// Test package.
if len(p.TestGoFiles) > 0 || localCover || p.Name == "main" {
ptest = new(Package)
*ptest = *p
ptest.GoFiles = nil
ptest.GoFiles = append(ptest.GoFiles, p.GoFiles...)
ptest.GoFiles = append(ptest.GoFiles, p.TestGoFiles...)
ptest.target = ""
ptest.Imports = stringList(p.Imports, p.TestImports)
ptest.imports = append(append([]*Package{}, p.imports...), imports...)
ptest.pkgdir = testDir
ptest.fake = true
ptest.forceLibrary = true
ptest.Stale = true
ptest.build = new(build.Package)
*ptest.build = *p.build
m := map[string][]token.Position{}
for k, v := range p.build.ImportPos {
m[k] = append(m[k], v...)
}
for k, v := range p.build.TestImportPos {
m[k] = append(m[k], v...)
}
ptest.build.ImportPos = m
if localCover {
ptest.coverMode = testCoverMode
var coverFiles []string
coverFiles = append(coverFiles, ptest.GoFiles...)
coverFiles = append(coverFiles, ptest.CgoFiles...)
ptest.coverVars = declareCoverVars(ptest.ImportPath, coverFiles...)
}
} else {
ptest = p
}
// External test package.
if len(p.XTestGoFiles) > 0 {
pxtest = &Package{
Name: p.Name + "_test",
ImportPath: p.ImportPath + "_test",
localPrefix: p.localPrefix,
Root: p.Root,
Dir: p.Dir,
GoFiles: p.XTestGoFiles,
Imports: p.XTestImports,
build: &build.Package{
ImportPos: p.build.XTestImportPos,
},
imports: ximports,
pkgdir: testDir,
fake: true,
Stale: true,
}
if pxtestNeedsPtest {
pxtest.imports = append(pxtest.imports, ptest)
}
}
// Action for building pkg.test.
pmain = &Package{
Name: "main",
Dir: testDir,
GoFiles: []string{"_testmain.go"},
ImportPath: "testmain",
Root: p.Root,
build: &build.Package{Name: "main"},
pkgdir: testDir,
fake: true,
Stale: true,
omitDWARF: !testC && !testNeedBinary,
}
// The generated main also imports testing and regexp.
stk.push("testmain")
for dep := range testMainDeps {
if dep == ptest.ImportPath {
pmain.imports = append(pmain.imports, ptest)
} else {
p1 := loadImport(dep, "", &stk, nil)
if !reqPkgSrc && p1.Root == "" {
continue
}
if p1.Error != nil {
return nil, nil, nil, p1.Error
}
pmain.imports = append(pmain.imports, p1)
}
}
if testCoverPkgs != nil {
// Add imports, but avoid duplicates.
seen := map[*Package]bool{p: true, ptest: true}
for _, p1 := range pmain.imports {
seen[p1] = true
}
for _, p1 := range testCoverPkgs {
if !seen[p1] {
seen[p1] = true
pmain.imports = append(pmain.imports, p1)
}
}
}
// Do initial scan for metadata needed for writing _testmain.go
// Use that metadata to update the list of imports for package main.
// The list of imports is used by recompileForTest and by the loop
// afterward that gathers t.Cover information.
t, err := loadTestFuncs(ptest)
if err != nil {
return nil, nil, nil, err
}
if t.NeedTest || ptest.coverMode != "" {
pmain.imports = append(pmain.imports, ptest)
}
if t.NeedXtest {
pmain.imports = append(pmain.imports, pxtest)
}
if ptest != p && localCover {
// We have made modifications to the package p being tested
// and are rebuilding p (as ptest), writing it to the testDir tree.
// Arrange to rebuild, writing to that same tree, all packages q
// such that the test depends on q, and q depends on p.
// This makes sure that q sees the modifications to p.
// Strictly speaking, the rebuild is only necessary if the
// modifications to p change its export metadata, but
// determining that is a bit tricky, so we rebuild always.
//
// This will cause extra compilation, so for now we only do it
// when testCover is set. The conditions are more general, though,
// and we may find that we need to do it always in the future.
recompileForTest(pmain, p, ptest, testDir)
}
for _, cp := range pmain.imports {
if len(cp.coverVars) > 0 {
t.Cover = append(t.Cover, coverInfo{cp, cp.coverVars})
}
}
// writeTestmain writes _testmain.go. This must happen after recompileForTest,
// because recompileForTest modifies XXX.
if err := writeTestmain(filepath.Join(testDir, "_testmain.go"), t); err != nil {
return nil, nil, nil, err
}
computeStale(pmain)
if ptest != p {
a := b.action(modeBuild, modeBuild, ptest)
a.objdir = testDir + string(filepath.Separator) + "_obj_test" + string(filepath.Separator)
a.objpkg = ptestObj
a.target = ptestObj
a.link = false
}
if pxtest != nil {
a := b.action(modeBuild, modeBuild, pxtest)
a.objdir = testDir + string(filepath.Separator) + "_obj_xtest" + string(filepath.Separator)
a.objpkg = buildToolchain.pkgpath(testDir, pxtest)
a.target = a.objpkg
}
a := b.action(modeBuild, modeBuild, pmain)
a.objdir = testDir + string(filepath.Separator)
a.objpkg = filepath.Join(testDir, "main.a")
a.target = filepath.Join(testDir, testBinary) + exeSuffix
pmainAction := a
if testC || testNeedBinary {
// -c or profiling flag: create action to copy binary to ./test.out.
runAction = &action{
f: (*builder).install,
deps: []*action{pmainAction},
p: pmain,
target: filepath.Join(cwd, testBinary+exeSuffix),
}
pmainAction = runAction // in case we are running the test
}
if testC {
printAction = &action{p: p, deps: []*action{runAction}} // nop
} else {
// run test
runAction = &action{
f: (*builder).runTest,
deps: []*action{pmainAction},
p: p,
ignoreFail: true,
}
cleanAction := &action{
f: (*builder).cleanTest,
deps: []*action{runAction},
p: p,
}
printAction = &action{
f: (*builder).printTest,
deps: []*action{cleanAction},
p: p,
}
}
return pmainAction, runAction, printAction, nil
}
func testImportStack(top string, p *Package, target string) []string {
stk := []string{top, p.ImportPath}
Search:
for p.ImportPath != target {
for _, p1 := range p.imports {
if p1.ImportPath == target || contains(p1.Deps, target) {
stk = append(stk, p1.ImportPath)
p = p1
continue Search
}
}
// Can't happen, but in case it does...
stk = append(stk, "<lost path to cycle>")
break
}
return stk
}
func recompileForTest(pmain, preal, ptest *Package, testDir string) {
// The "test copy" of preal is ptest.
// For each package that depends on preal, make a "test copy"
// that depends on ptest. And so on, up the dependency tree.
testCopy := map[*Package]*Package{preal: ptest}
for _, p := range packageList([]*Package{pmain}) {
// Copy on write.
didSplit := false
split := func() {
if didSplit {
return
}
didSplit = true
if p.pkgdir != testDir {
p1 := new(Package)
testCopy[p] = p1
*p1 = *p
p1.imports = make([]*Package, len(p.imports))
copy(p1.imports, p.imports)
p = p1
p.pkgdir = testDir
p.target = ""
p.fake = true
p.Stale = true
}
}
// Update p.deps and p.imports to use at test copies.
for i, dep := range p.deps {
if p1 := testCopy[dep]; p1 != nil && p1 != dep {
split()
p.deps[i] = p1
}
}
for i, imp := range p.imports {
if p1 := testCopy[imp]; p1 != nil && p1 != imp {
split()
p.imports[i] = p1
}
}
}
}
var coverIndex = 0
// isTestFile reports whether the source file is a set of tests and should therefore
// be excluded from coverage analysis.
func isTestFile(file string) bool {
// We don't cover tests, only the code they test.
return strings.HasSuffix(file, "_test.go")
}
// declareCoverVars attaches the required cover variables names
// to the files, to be used when annotating the files.
func declareCoverVars(importPath string, files ...string) map[string]*CoverVar {
coverVars := make(map[string]*CoverVar)
for _, file := range files {
if isTestFile(file) {
continue
}
coverVars[file] = &CoverVar{
File: filepath.Join(importPath, file),
Var: fmt.Sprintf("GoCover_%d", coverIndex),
}
coverIndex++
}
return coverVars
}
// runTest is the action for running a test binary.
func (b *builder) runTest(a *action) error {
args := stringList(findExecCmd(), a.deps[0].target, testArgs)
a.testOutput = new(bytes.Buffer)
if buildN || buildX {
b.showcmd("", "%s", strings.Join(args, " "))
if buildN {
return nil
}
}
if a.failed {
// We were unable to build the binary.
a.failed = false
fmt.Fprintf(a.testOutput, "FAIL\t%s [build failed]\n", a.p.ImportPath)
setExitStatus(1)
return nil
}
cmd := exec.Command(args[0], args[1:]...)
cmd.Dir = a.p.Dir
cmd.Env = envForDir(cmd.Dir)
var buf bytes.Buffer
if testStreamOutput {
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
} else {
cmd.Stdout = &buf
cmd.Stderr = &buf
}
// If there are any local SWIG dependencies, we want to load
// the shared library from the build directory.
if a.p.usesSwig() {
env := cmd.Env
found := false
prefix := "LD_LIBRARY_PATH="
for i, v := range env {
if strings.HasPrefix(v, prefix) {
env[i] = v + ":."
found = true
break
}
}
if !found {
env = append(env, "LD_LIBRARY_PATH=.")
}
cmd.Env = env
}
t0 := time.Now()
err := cmd.Start()
// This is a last-ditch deadline to detect and
// stop wedged test binaries, to keep the builders
// running.
if err == nil {
tick := time.NewTimer(testKillTimeout)
startSigHandlers()
done := make(chan error)
go func() {
done <- cmd.Wait()
}()
Outer:
select {
case err = <-done:
// ok
case <-tick.C:
if signalTrace != nil {
// Send a quit signal in the hope that the program will print
// a stack trace and exit. Give it five seconds before resorting
// to Kill.
cmd.Process.Signal(signalTrace)
select {
case err = <-done:
fmt.Fprintf(&buf, "*** Test killed with %v: ran too long (%v).\n", signalTrace, testKillTimeout)
break Outer
case <-time.After(5 * time.Second):
}
}
cmd.Process.Kill()
err = <-done
fmt.Fprintf(&buf, "*** Test killed: ran too long (%v).\n", testKillTimeout)
}
tick.Stop()
}
out := buf.Bytes()
t := fmt.Sprintf("%.3fs", time.Since(t0).Seconds())
if err == nil {
if testShowPass {
a.testOutput.Write(out)
}
fmt.Fprintf(a.testOutput, "ok \t%s\t%s%s\n", a.p.ImportPath, t, coveragePercentage(out))
return nil
}
setExitStatus(1)
if len(out) > 0 {
a.testOutput.Write(out)
// assume printing the test binary's exit status is superfluous
} else {
fmt.Fprintf(a.testOutput, "%s\n", err)
}
fmt.Fprintf(a.testOutput, "FAIL\t%s\t%s\n", a.p.ImportPath, t)
return nil
}
// coveragePercentage returns the coverage results (if enabled) for the
// test. It uncovers the data by scanning the output from the test run.
func coveragePercentage(out []byte) string {
if !testCover {
return ""
}
// The string looks like
// test coverage for encoding/binary: 79.9% of statements
// Extract the piece from the percentage to the end of the line.
re := regexp.MustCompile(`coverage: (.*)\n`)
matches := re.FindSubmatch(out)
if matches == nil {
// Probably running "go test -cover" not "go test -cover fmt".
// The coverage output will appear in the output directly.
return ""
}
return fmt.Sprintf("\tcoverage: %s", matches[1])
}
// cleanTest is the action for cleaning up after a test.
func (b *builder) cleanTest(a *action) error {
if buildWork {
return nil
}
run := a.deps[0]
testDir := filepath.Join(b.work, filepath.FromSlash(run.p.ImportPath+"/_test"))
os.RemoveAll(testDir)
return nil
}
// printTest is the action for printing a test result.
func (b *builder) printTest(a *action) error {
clean := a.deps[0]
run := clean.deps[0]
os.Stdout.Write(run.testOutput.Bytes())
run.testOutput = nil
return nil
}
// notest is the action for testing a package with no test files.
func (b *builder) notest(a *action) error {
fmt.Printf("? \t%s\t[no test files]\n", a.p.ImportPath)
return nil
}
// isTest tells whether name looks like a test (or benchmark, according to prefix).
// It is a Test (say) if there is a character after Test that is not a lower-case letter.
// We don't want TesticularCancer.
func isTest(name, prefix string) bool {
if !strings.HasPrefix(name, prefix) {
return false
}
if len(name) == len(prefix) { // "Test" is ok
return true
}
rune, _ := utf8.DecodeRuneInString(name[len(prefix):])
return !unicode.IsLower(rune)
}
type coverInfo struct {
Package *Package
Vars map[string]*CoverVar
}
// loadTestFuncs returns the testFuncs describing the tests that will be run.
func loadTestFuncs(ptest *Package) (*testFuncs, error) {
t := &testFuncs{
Package: ptest,
}
for _, file := range ptest.TestGoFiles {
if err := t.load(filepath.Join(ptest.Dir, file), "_test", &t.NeedTest); err != nil {
return nil, err
}
}
for _, file := range ptest.XTestGoFiles {
if err := t.load(filepath.Join(ptest.Dir, file), "_xtest", &t.NeedXtest); err != nil {
return nil, err
}
}
return t, nil
}
// writeTestmain writes the _testmain.go file for t to the file named out.
func writeTestmain(out string, t *testFuncs) error {
f, err := os.Create(out)
if err != nil {
return err
}
defer f.Close()
if err := testmainTmpl.Execute(f, t); err != nil {
return err
}
return nil
}
type testFuncs struct {
Tests []testFunc
Benchmarks []testFunc
Examples []testFunc
Package *Package
NeedTest bool
NeedXtest bool
Cover []coverInfo
}
func (t *testFuncs) CoverMode() string {
return testCoverMode
}
func (t *testFuncs) CoverEnabled() bool {
return testCover
}
// Covered returns a string describing which packages are being tested for coverage.
// If the covered package is the same as the tested package, it returns the empty string.
// Otherwise it is a comma-separated human-readable list of packages beginning with
// " in", ready for use in the coverage message.
func (t *testFuncs) Covered() string {
if testCoverPaths == nil {
return ""
}
return " in " + strings.Join(testCoverPaths, ", ")
}
// Tested returns the name of the package being tested.
func (t *testFuncs) Tested() string {
return t.Package.Name
}
type testFunc struct {
Package string // imported package name (_test or _xtest)
Name string // function name
Output string // output, for examples
}
var testFileSet = token.NewFileSet()
func (t *testFuncs) load(filename, pkg string, seen *bool) error {
f, err := parser.ParseFile(testFileSet, filename, nil, parser.ParseComments)
if err != nil {
return expandScanner(err)
}
for _, d := range f.Decls {
n, ok := d.(*ast.FuncDecl)
if !ok {
continue
}
if n.Recv != nil {
continue
}
name := n.Name.String()
switch {
case isTest(name, "Test"):
t.Tests = append(t.Tests, testFunc{pkg, name, ""})
*seen = true
case isTest(name, "Benchmark"):
t.Benchmarks = append(t.Benchmarks, testFunc{pkg, name, ""})
*seen = true
}
}
ex := doc.Examples(f)
sort.Sort(byOrder(ex))
for _, e := range ex {
if e.Output == "" && !e.EmptyOutput {
// Don't run examples with no output.
continue
}
t.Examples = append(t.Examples, testFunc{pkg, "Example" + e.Name, e.Output})
*seen = true
}
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
import (
"regexp"
"testing"
{{if .NeedTest}}
_test {{.Package.ImportPath | printf "%q"}}
{{end}}
{{if .NeedXtest}}
_xtest {{.Package.ImportPath | printf "%s_test" | printf "%q"}}
{{end}}
{{range $i, $p := .Cover}}
_cover{{$i}} {{$p.Package.ImportPath | printf "%q"}}
{{end}}
)
var tests = []testing.InternalTest{
{{range .Tests}}
{"{{.Name}}", {{.Package}}.{{.Name}}},
{{end}}
}
var benchmarks = []testing.InternalBenchmark{
{{range .Benchmarks}}
{"{{.Name}}", {{.Package}}.{{.Name}}},
{{end}}
}
var examples = []testing.InternalExample{
{{range .Examples}}
{"{{.Name}}", {{.Package}}.{{.Name}}, {{.Output | printf "%q"}}},
{{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.
var (
coverCounters = make(map[string][]uint32)
coverBlocks = make(map[string][]testing.CoverBlock)
)
func init() {
{{range $i, $p := .Cover}}
{{range $file, $cover := $p.Vars}}
coverRegisterFile({{printf "%q" $cover.File}}, _cover{{$i}}.{{$cover.Var}}.Count[:], _cover{{$i}}.{{$cover.Var}}.Pos[:], _cover{{$i}}.{{$cover.Var}}.NumStmt[:])
{{end}}
{{end}}
}
func coverRegisterFile(fileName string, counter []uint32, pos []uint32, numStmts []uint16) {
if 3*len(counter) != len(pos) || len(counter) != len(numStmts) {
panic("coverage: mismatched sizes")
}
if coverCounters[fileName] != nil {
// Already registered.
return
}
coverCounters[fileName] = counter
block := make([]testing.CoverBlock, len(counter))
for i := range counter {
block[i] = testing.CoverBlock{
Line0: pos[3*i+0],
Col0: uint16(pos[3*i+2]),
Line1: pos[3*i+1],
Col1: uint16(pos[3*i+2]>>16),
Stmts: numStmts[i],
}
}
coverBlocks[fileName] = block
}
{{end}}
func main() {
{{if .CoverEnabled}}
testing.RegisterCover(testing.Cover{
Mode: {{printf "%q" .CoverMode}},
Counters: coverCounters,
Blocks: coverBlocks,
CoveredPackages: {{printf "%q" .Covered}},
})
{{end}}
testing.Main(matchString, tests, benchmarks, examples)
}
`))
package p
/*
void
f(void)
{
}
*/
import "C"
var b bool
func F() {
if b {
for {
}
}
C.f()
}
package p
import "testing"
func TestF(t *testing.T) {
F()
}
// Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package deps
import _ "testing"
// Copyright 2013 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.
// Make sure that go test runs Example_Z before Example_A, preserving source order.
package p
import "fmt"
var n int
func Example_Z() {
n++
fmt.Println(n)
// Output: 1
}
func Example_A() {
n++
fmt.Println(n)
// Output: 2
}
// Copyright 2013 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.
// Make sure that go test runs Example_Y before Example_B, preserving source order.
package p
import "fmt"
func Example_Y() {
n++
fmt.Println(n)
// Output: 3
}
func Example_B() {
n++
fmt.Println(n)
// Output: 4
}
package main
import "./easysub"
func main() {
easysub.Hello()
}
package easysub
import "fmt"
func Hello() {
fmt.Println("easysub.Hello")
}
// +build ignore
package main
import "."
func main() {
easysub.Hello()
}
package main
import "./sub"
func main() {
sub.Hello()
}
package sub
import (
"fmt"
subsub "./sub"
)
func Hello() {
fmt.Println("sub.Hello")
subsub.Hello()
}
package subsub
import "fmt"
func Hello() {
fmt.Println("subsub.Hello")
}
package cgotest
import "C"
var _ C.int
package main
func main() {
println("hello world")
}
package main
func F() {}
func main() {}
package main_test
import (
. "main_test"
"testing"
)
func Test1(t *testing.T) {
F()
}
package notest
func hello() {
println("hello world")
}
Hello world
package p
func f() (x.y, z int) {
}
package p1
import _ "testcycle/p2"
func init() {
println("p1 init")
}
package p1
import "testing"
func Test(t *testing.T) {
}
package p2
import _ "testcycle/p3"
func init() {
println("p2 init")
}
package p3
func init() {
println("p3 init")
}
package p3
import (
"testing"
_ "testcycle/p1"
)
func Test(t *testing.T) {
}
package xtestonly
func F() int { return 42 }
package xtestonly_test
import (
"testing"
"xtestonly"
)
func TestF(t *testing.T) {
if x := xtestonly.F(); x != 42 {
t.Errorf("f.F() = %d, want 42", x)
}
}
package standalone_test
import "testing"
func Test(t *testing.T) {
}
package p
func F() int { return 1 }
package p1
func F() int { return 1 }
package p2
func F() int { return 1 }
package p
import (
"./p1"
"testing"
)
func TestF(t *testing.T) {
if F() != p1.F() {
t.Fatal(F())
}
}
package p_test
import (
. "../testimport"
"./p2"
"testing"
)
func TestF1(t *testing.T) {
if F() != p2.F() {
t.Fatal(F())
}
}
// Copyright 2011 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 (
"fmt"
"os"
"strconv"
"strings"
)
// The flag handling part of go test is large and distracting.
// We can't use the flag package because some of the flags from
// our command line are for us, and some are for 6.out, and
// some are for both.
var usageMessage = `Usage of go test:
-c=false: compile but do not run the test binary
-file=file_test.go: specify file to use for tests;
use multiple times for multiple files
-p=n: build and test up to n packages in parallel
-x=false: print command lines as they are executed
// These flags can be passed with or without a "test." prefix: -v or -test.v.
-bench="": passes -test.bench to test
-benchmem=false: print memory allocation statistics for benchmarks
-benchtime=1s: passes -test.benchtime to test
-cover=false: enable coverage analysis
-covermode="set": specifies mode for coverage analysis
-coverpkg="": comma-separated list of packages for coverage analysis
-coverprofile="": passes -test.coverprofile to test if -cover
-cpu="": passes -test.cpu to test
-cpuprofile="": passes -test.cpuprofile to test
-memprofile="": passes -test.memprofile to test
-memprofilerate=0: passes -test.memprofilerate to test
-blockprofile="": pases -test.blockprofile to test
-blockprofilerate=0: passes -test.blockprofilerate to test
-outputdir=$PWD: passes -test.outputdir to test
-parallel=0: passes -test.parallel to test
-run="": passes -test.run to test
-short=false: passes -test.short to test
-timeout=0: passes -test.timeout to test
-v=false: passes -test.v to test
`
// usage prints a usage message and exits.
func testUsage() {
fmt.Fprint(os.Stderr, usageMessage)
setExitStatus(2)
exit()
}
// testFlagSpec defines a flag we know about.
type testFlagSpec struct {
name string
boolVar *bool
passToTest bool // pass to Test
multiOK bool // OK to have multiple instances
present bool // flag has been seen
}
// testFlagDefn is the set of flags we process.
var testFlagDefn = []*testFlagSpec{
// local.
{name: "c", boolVar: &testC},
{name: "file", multiOK: true},
{name: "cover", boolVar: &testCover},
{name: "coverpkg"},
// build flags.
{name: "a", boolVar: &buildA},
{name: "n", boolVar: &buildN},
{name: "p"},
{name: "x", boolVar: &buildX},
{name: "i", boolVar: &buildI},
{name: "work", boolVar: &buildWork},
{name: "ccflags"},
{name: "gcflags"},
{name: "exec"},
{name: "ldflags"},
{name: "gccgoflags"},
{name: "tags"},
{name: "compiler"},
{name: "race", boolVar: &buildRace},
{name: "installsuffix"},
// passed to 6.out, adding a "test." prefix to the name if necessary: -v becomes -test.v.
{name: "bench", passToTest: true},
{name: "benchmem", boolVar: new(bool), passToTest: true},
{name: "benchtime", passToTest: true},
{name: "covermode"},
{name: "coverprofile", passToTest: true},
{name: "cpu", passToTest: true},
{name: "cpuprofile", passToTest: true},
{name: "memprofile", passToTest: true},
{name: "memprofilerate", passToTest: true},
{name: "blockprofile", passToTest: true},
{name: "blockprofilerate", passToTest: true},
{name: "outputdir", passToTest: true},
{name: "parallel", passToTest: true},
{name: "run", passToTest: true},
{name: "short", boolVar: new(bool), passToTest: true},
{name: "timeout", passToTest: true},
{name: "v", boolVar: &testV, passToTest: true},
}
// testFlags processes the command line, grabbing -x and -c, rewriting known flags
// to have "test" before them, and reading the command line for the 6.out.
// Unfortunately for us, we need to do our own flag processing because go test
// grabs some flags but otherwise its command line is just a holding place for
// pkg.test's arguments.
// We allow known flags both before and after the package name list,
// to allow both
// go test fmt -custom-flag-for-fmt-test
// go test -x math
func testFlags(args []string) (packageNames, passToTest []string) {
inPkg := false
outputDir := ""
for i := 0; i < len(args); i++ {
if !strings.HasPrefix(args[i], "-") {
if !inPkg && packageNames == nil {
// First package name we've seen.
inPkg = true
}
if inPkg {
packageNames = append(packageNames, args[i])
continue
}
}
if inPkg {
// Found an argument beginning with "-"; end of package list.
inPkg = false
}
f, value, extraWord := testFlag(args, i)
if f == nil {
// This is a flag we do not know; we must assume
// that any args we see after this might be flag
// arguments, not package names.
inPkg = false
if packageNames == nil {
// make non-nil: we have seen the empty package list
packageNames = []string{}
}
passToTest = append(passToTest, args[i])
continue
}
var err error
switch f.name {
// bool flags.
case "a", "c", "i", "n", "x", "v", "race", "cover", "work":
setBoolFlag(f.boolVar, value)
case "p":
setIntFlag(&buildP, value)
case "exec":
execCmd, err = splitQuotedFields(value)
if err != nil {
fatalf("invalid flag argument for -%s: %v", f.name, err)
}
case "ccflags":
buildCcflags, err = splitQuotedFields(value)
if err != nil {
fatalf("invalid flag argument for -%s: %v", f.name, err)
}
case "gcflags":
buildGcflags, err = splitQuotedFields(value)
if err != nil {
fatalf("invalid flag argument for -%s: %v", f.name, err)
}
case "ldflags":
buildLdflags, err = splitQuotedFields(value)
if err != nil {
fatalf("invalid flag argument for -%s: %v", f.name, err)
}
case "gccgoflags":
buildGccgoflags, err = splitQuotedFields(value)
if err != nil {
fatalf("invalid flag argument for -%s: %v", f.name, err)
}
case "tags":
buildContext.BuildTags = strings.Fields(value)
case "compiler":
buildCompiler{}.Set(value)
case "file":
testFiles = append(testFiles, value)
case "bench":
// record that we saw the flag; don't care about the value
testBench = true
case "timeout":
testTimeout = value
case "blockprofile", "cpuprofile", "memprofile":
testProfile = true
testNeedBinary = true
case "coverpkg":
testCover = true
if value == "" {
testCoverPaths = nil
} else {
testCoverPaths = strings.Split(value, ",")
}
case "coverprofile":
testCover = true
testProfile = true
case "covermode":
switch value {
case "set", "count", "atomic":
testCoverMode = value
default:
fatalf("invalid flag argument for -cover: %q", value)
}
testCover = true
case "outputdir":
outputDir = value
}
if extraWord {
i++
}
if f.passToTest {
passToTest = append(passToTest, "-test."+f.name+"="+value)
}
}
if testCoverMode == "" {
testCoverMode = "set"
if buildRace {
// Default coverage mode is atomic when -race is set.
testCoverMode = "atomic"
}
}
// Tell the test what directory we're running in, so it can write the profiles there.
if testProfile && outputDir == "" {
dir, err := os.Getwd()
if err != nil {
fatalf("error from os.Getwd: %s", err)
}
passToTest = append(passToTest, "-test.outputdir", dir)
}
return
}
// testFlag sees if argument i is a known flag and returns its definition, value, and whether it consumed an extra word.
func testFlag(args []string, i int) (f *testFlagSpec, value string, extra bool) {
arg := args[i]
if strings.HasPrefix(arg, "--") { // reduce two minuses to one
arg = arg[1:]
}
switch arg {
case "-?", "-h", "-help":
usage()
}
if arg == "" || arg[0] != '-' {
return
}
name := arg[1:]
// If there's already "test.", drop it for now.
name = strings.TrimPrefix(name, "test.")
equals := strings.Index(name, "=")
if equals >= 0 {
value = name[equals+1:]
name = name[:equals]
}
for _, f = range testFlagDefn {
if name == f.name {
// Booleans are special because they have modes -x, -x=true, -x=false.
if f.boolVar != nil {
if equals < 0 { // otherwise, it's been set and will be verified in setBoolFlag
value = "true"
} else {
// verify it parses
setBoolFlag(new(bool), value)
}
} else { // Non-booleans must have a value.
extra = equals < 0
if extra {
if i+1 >= len(args) {
testSyntaxError("missing argument for flag " + f.name)
}
value = args[i+1]
}
}
if f.present && !f.multiOK {
testSyntaxError(f.name + " flag may be set only once")
}
f.present = true
return
}
}
f = nil
return
}
// setBoolFlag sets the addressed boolean to the value.
func setBoolFlag(flag *bool, value string) {
x, err := strconv.ParseBool(value)
if err != nil {
testSyntaxError("illegal bool flag value " + value)
}
*flag = x
}
// setIntFlag sets the addressed integer to the value.
func setIntFlag(flag *int, value string) {
x, err := strconv.Atoi(value)
if err != nil {
testSyntaxError("illegal int flag value " + value)
}
*flag = x
}
func testSyntaxError(msg string) {
fmt.Fprintf(os.Stderr, "go test: %s\n", msg)
fmt.Fprintf(os.Stderr, `run "go help test" or "go help testflag" for more information`+"\n")
os.Exit(2)
}
// Copyright 2011 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 (
"fmt"
"go/build"
"os"
"os/exec"
"path/filepath"
"runtime"
"sort"
"strings"
)
var cmdTool = &Command{
Run: runTool,
UsageLine: "tool [-n] command [args...]",
Short: "run specified go tool",
Long: `
Tool runs the go tool command identified by the arguments.
With no arguments it prints the list of known tools.
The -n flag causes tool to print the command that would be
executed but not execute it.
For more about each tool command, see 'go tool command -h'.
`,
}
var (
toolGOOS = runtime.GOOS
toolGOARCH = runtime.GOARCH
toolIsWindows = toolGOOS == "windows"
toolDir = build.ToolDir
toolN bool
)
func init() {
cmdTool.Flag.BoolVar(&toolN, "n", false, "")
}
const toolWindowsExtension = ".exe"
func tool(toolName string) string {
toolPath := filepath.Join(toolDir, toolName)
if toolIsWindows && toolName != "pprof" {
toolPath += toolWindowsExtension
}
// Give a nice message if there is no tool with that name.
if _, err := os.Stat(toolPath); err != nil {
if isInGoToolsRepo(toolName) {
fmt.Fprintf(os.Stderr, "go tool: no such tool %q; to install:\n\tgo get code.google.com/p/go.tools/cmd/%s\n", toolName, toolName)
} else {
fmt.Fprintf(os.Stderr, "go tool: no such tool %q\n", toolName)
}
setExitStatus(3)
exit()
}
return toolPath
}
func isInGoToolsRepo(toolName string) bool {
switch toolName {
case "cover", "vet":
return true
}
return false
}
func runTool(cmd *Command, args []string) {
if len(args) == 0 {
listTools()
return
}
toolName := args[0]
// The tool name must be lower-case letters, numbers or underscores.
for _, c := range toolName {
switch {
case 'a' <= c && c <= 'z', '0' <= c && c <= '9', c == '_':
default:
fmt.Fprintf(os.Stderr, "go tool: bad tool name %q\n", toolName)
setExitStatus(2)
return
}
}
toolPath := tool(toolName)
if toolPath == "" {
return
}
if toolIsWindows && toolName == "pprof" {
args = append([]string{"perl", toolPath}, args[1:]...)
var err error
toolPath, err = exec.LookPath("perl")
if err != nil {
fmt.Fprintf(os.Stderr, "go tool: perl not found\n")
setExitStatus(3)
return
}
}
if toolN {
fmt.Printf("%s %s\n", toolPath, strings.Join(args[1:], " "))
return
}
toolCmd := &exec.Cmd{
Path: toolPath,
Args: args,
Stdin: os.Stdin,
Stdout: os.Stdout,
Stderr: os.Stderr,
}
err := toolCmd.Run()
if err != nil {
// Only print about the exit status if the command
// didn't even run (not an ExitError) or it didn't exit cleanly
// or we're printing command lines too (-x mode).
// Assume if command exited cleanly (even with non-zero status)
// it printed any messages it wanted to print.
if e, ok := err.(*exec.ExitError); !ok || !e.Exited() || buildX {
fmt.Fprintf(os.Stderr, "go tool %s: %s\n", toolName, err)
}
setExitStatus(1)
return
}
}
// listTools prints a list of the available tools in the tools directory.
func listTools() {
f, err := os.Open(toolDir)
if err != nil {
fmt.Fprintf(os.Stderr, "go tool: no tool directory: %s\n", err)
setExitStatus(2)
return
}
defer f.Close()
names, err := f.Readdirnames(-1)
if err != nil {
fmt.Fprintf(os.Stderr, "go tool: can't read directory: %s\n", err)
setExitStatus(2)
return
}
sort.Strings(names)
for _, name := range names {
// Unify presentation by going to lower case.
name = strings.ToLower(name)
// If it's windows, don't show the .exe suffix.
if toolIsWindows && strings.HasSuffix(name, toolWindowsExtension) {
name = name[:len(name)-len(toolWindowsExtension)]
}
fmt.Println(name)
}
}
// Copyright 2012 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"
"encoding/json"
"errors"
"fmt"
"log"
"os"
"os/exec"
"path/filepath"
"regexp"
"strings"
)
// A vcsCmd describes how to use a version control system
// like Mercurial, Git, or Subversion.
type vcsCmd struct {
name string
cmd string // name of binary to invoke command
createCmd string // command to download a fresh copy of a repository
downloadCmd string // command to download updates into an existing repository
tagCmd []tagCmd // commands to list tags
tagLookupCmd []tagCmd // commands to lookup tags before running tagSyncCmd
tagSyncCmd string // command to sync to specific tag
tagSyncDefault string // command to sync to default tag
scheme []string
pingCmd string
}
// A tagCmd describes a command to list available tags
// that can be passed to tagSyncCmd.
type tagCmd struct {
cmd string // command to list tags
pattern string // regexp to extract tags from list
}
// vcsList lists the known version control systems
var vcsList = []*vcsCmd{
vcsHg,
vcsGit,
vcsSvn,
vcsBzr,
}
// vcsByCmd returns the version control system for the given
// command name (hg, git, svn, bzr).
func vcsByCmd(cmd string) *vcsCmd {
for _, vcs := range vcsList {
if vcs.cmd == cmd {
return vcs
}
}
return nil
}
// vcsHg describes how to use Mercurial.
var vcsHg = &vcsCmd{
name: "Mercurial",
cmd: "hg",
createCmd: "clone -U {repo} {dir}",
downloadCmd: "pull",
// We allow both tag and branch names as 'tags'
// for selecting a version. This lets people have
// a go.release.r60 branch and a go1 branch
// and make changes in both, without constantly
// editing .hgtags.
tagCmd: []tagCmd{
{"tags", `^(\S+)`},
{"branches", `^(\S+)`},
},
tagSyncCmd: "update -r {tag}",
tagSyncDefault: "update default",
scheme: []string{"https", "http", "ssh"},
pingCmd: "identify {scheme}://{repo}",
}
// vcsGit describes how to use Git.
var vcsGit = &vcsCmd{
name: "Git",
cmd: "git",
createCmd: "clone {repo} {dir}",
downloadCmd: "pull --ff-only",
tagCmd: []tagCmd{
// tags/xxx matches a git tag named xxx
// origin/xxx matches a git branch named xxx on the default remote repository
{"show-ref", `(?:tags|origin)/(\S+)$`},
},
tagLookupCmd: []tagCmd{
{"show-ref tags/{tag} origin/{tag}", `((?:tags|origin)/\S+)$`},
},
tagSyncCmd: "checkout {tag}",
tagSyncDefault: "checkout master",
scheme: []string{"git", "https", "http", "git+ssh"},
pingCmd: "ls-remote {scheme}://{repo}",
}
// vcsBzr describes how to use Bazaar.
var vcsBzr = &vcsCmd{
name: "Bazaar",
cmd: "bzr",
createCmd: "branch {repo} {dir}",
// Without --overwrite bzr will not pull tags that changed.
// Replace by --overwrite-tags after http://pad.lv/681792 goes in.
downloadCmd: "pull --overwrite",
tagCmd: []tagCmd{{"tags", `^(\S+)`}},
tagSyncCmd: "update -r {tag}",
tagSyncDefault: "update -r revno:-1",
scheme: []string{"https", "http", "bzr", "bzr+ssh"},
pingCmd: "info {scheme}://{repo}",
}
// vcsSvn describes how to use Subversion.
var vcsSvn = &vcsCmd{
name: "Subversion",
cmd: "svn",
createCmd: "checkout {repo} {dir}",
downloadCmd: "update",
// There is no tag command in subversion.
// The branch information is all in the path names.
scheme: []string{"https", "http", "svn", "svn+ssh"},
pingCmd: "info {scheme}://{repo}",
}
func (v *vcsCmd) String() string {
return v.name
}
// run runs the command line cmd in the given directory.
// keyval is a list of key, value pairs. run expands
// instances of {key} in cmd into value, but only after
// splitting cmd into individual arguments.
// If an error occurs, run prints the command line and the
// command's combined stdout+stderr to standard error.
// Otherwise run discards the command's output.
func (v *vcsCmd) run(dir string, cmd string, keyval ...string) error {
_, err := v.run1(dir, cmd, keyval, true)
return err
}
// runVerboseOnly is like run but only generates error output to standard error in verbose mode.
func (v *vcsCmd) runVerboseOnly(dir string, cmd string, keyval ...string) error {
_, err := v.run1(dir, cmd, keyval, false)
return err
}
// runOutput is like run but returns the output of the command.
func (v *vcsCmd) runOutput(dir string, cmd string, keyval ...string) ([]byte, error) {
return v.run1(dir, cmd, keyval, true)
}
// run1 is the generalized implementation of run and runOutput.
func (v *vcsCmd) run1(dir string, cmdline string, keyval []string, verbose bool) ([]byte, error) {
m := make(map[string]string)
for i := 0; i < len(keyval); i += 2 {
m[keyval[i]] = keyval[i+1]
}
args := strings.Fields(cmdline)
for i, arg := range args {
args[i] = expand(m, arg)
}
_, err := exec.LookPath(v.cmd)
if err != nil {
fmt.Fprintf(os.Stderr,
"go: missing %s command. See http://golang.org/s/gogetcmd\n",
v.name)
return nil, err
}
cmd := exec.Command(v.cmd, args...)
cmd.Dir = dir
cmd.Env = envForDir(cmd.Dir)
if buildX {
fmt.Printf("cd %s\n", dir)
fmt.Printf("%s %s\n", v.cmd, strings.Join(args, " "))
}
var buf bytes.Buffer
cmd.Stdout = &buf
cmd.Stderr = &buf
err = cmd.Run()
out := buf.Bytes()
if err != nil {
if verbose || buildV {
fmt.Fprintf(os.Stderr, "# cd %s; %s %s\n", dir, v.cmd, strings.Join(args, " "))
os.Stderr.Write(out)
}
return nil, err
}
return out, nil
}
// ping pings to determine scheme to use.
func (v *vcsCmd) ping(scheme, repo string) error {
return v.runVerboseOnly(".", v.pingCmd, "scheme", scheme, "repo", repo)
}
// create creates a new copy of repo in dir.
// The parent of dir must exist; dir must not.
func (v *vcsCmd) create(dir, repo string) error {
return v.run(".", v.createCmd, "dir", dir, "repo", repo)
}
// download downloads any new changes for the repo in dir.
func (v *vcsCmd) download(dir string) error {
if err := v.fixDetachedHead(dir); err != nil {
return err
}
return v.run(dir, v.downloadCmd)
}
// fixDetachedHead switches a Git repository in dir from a detached head to the master branch.
// Go versions before 1.2 downloaded Git repositories in an unfortunate way
// that resulted in the working tree state being on a detached head.
// That meant the repository was not usable for normal Git operations.
// Go 1.2 fixed that, but we can't pull into a detached head, so if this is
// a Git repository we check for being on a detached head and switch to the
// real branch, almost always called "master".
// TODO(dsymonds): Consider removing this for Go 1.3.
func (v *vcsCmd) fixDetachedHead(dir string) error {
if v != vcsGit {
return nil
}
// "git symbolic-ref HEAD" succeeds iff we are not on a detached head.
if err := v.runVerboseOnly(dir, "symbolic-ref HEAD"); err == nil {
// not on a detached head
return nil
}
if buildV {
log.Printf("%s on detached head; repairing", dir)
}
return v.run(dir, "checkout master")
}
// tags returns the list of available tags for the repo in dir.
func (v *vcsCmd) tags(dir string) ([]string, error) {
var tags []string
for _, tc := range v.tagCmd {
out, err := v.runOutput(dir, tc.cmd)
if err != nil {
return nil, err
}
re := regexp.MustCompile(`(?m-s)` + tc.pattern)
for _, m := range re.FindAllStringSubmatch(string(out), -1) {
tags = append(tags, m[1])
}
}
return tags, nil
}
// tagSync syncs the repo in dir to the named tag,
// which either is a tag returned by tags or is v.tagDefault.
func (v *vcsCmd) tagSync(dir, tag string) error {
if v.tagSyncCmd == "" {
return nil
}
if tag != "" {
for _, tc := range v.tagLookupCmd {
out, err := v.runOutput(dir, tc.cmd, "tag", tag)
if err != nil {
return err
}
re := regexp.MustCompile(`(?m-s)` + tc.pattern)
m := re.FindStringSubmatch(string(out))
if len(m) > 1 {
tag = m[1]
break
}
}
}
if tag == "" && v.tagSyncDefault != "" {
return v.run(dir, v.tagSyncDefault)
}
return v.run(dir, v.tagSyncCmd, "tag", tag)
}
// A vcsPath describes how to convert an import path into a
// version control system and repository name.
type vcsPath struct {
prefix string // prefix this description applies to
re string // pattern for import path
repo string // repository to use (expand with match of re)
vcs string // version control system to use (expand with match of re)
check func(match map[string]string) error // additional checks
ping bool // ping for scheme to use to download repo
regexp *regexp.Regexp // cached compiled form of re
}
// vcsForDir inspects dir and its parents to determine the
// version control system and code repository to use.
// On return, root is the import path
// corresponding to the root of the repository
// (thus root is a prefix of importPath).
func vcsForDir(p *Package) (vcs *vcsCmd, root string, err error) {
// Clean and double-check that dir is in (a subdirectory of) srcRoot.
dir := filepath.Clean(p.Dir)
srcRoot := filepath.Clean(p.build.SrcRoot)
if len(dir) <= len(srcRoot) || dir[len(srcRoot)] != filepath.Separator {
return nil, "", fmt.Errorf("directory %q is outside source root %q", dir, srcRoot)
}
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() {
return vcs, dir[len(srcRoot)+1:], nil
}
}
// Move to parent.
ndir := filepath.Dir(dir)
if len(ndir) >= len(dir) {
// Shouldn't happen, but just in case, stop.
break
}
dir = ndir
}
return nil, "", fmt.Errorf("directory %q is not using a known version control system", origDir)
}
// repoRoot represents a version control system, a repo, and a root of
// where to put it on disk.
type repoRoot struct {
vcs *vcsCmd
// repo is the repository URL, including scheme
repo string
// root is the import path corresponding to the root of the
// repository
root string
}
var httpPrefixRE = regexp.MustCompile(`^https?:`)
// repoRootForImportPath analyzes importPath to determine the
// version control system, and code repository to use.
func repoRootForImportPath(importPath string) (*repoRoot, error) {
rr, err := repoRootForImportPathStatic(importPath, "")
if err == errUnknownSite {
rr, err = repoRootForImportDynamic(importPath)
// repoRootForImportDynamic returns error detail
// that is irrelevant if the user didn't intend to use a
// dynamic import in the first place.
// Squelch it.
if err != nil {
if buildV {
log.Printf("import %q: %v", importPath, err)
}
err = fmt.Errorf("unrecognized import path %q", importPath)
}
}
if err == nil && strings.Contains(importPath, "...") && strings.Contains(rr.root, "...") {
// Do not allow wildcards in the repo root.
rr = nil
err = fmt.Errorf("cannot expand ... in %q", importPath)
}
return rr, err
}
var errUnknownSite = errors.New("dynamic lookup required to find mapping")
// repoRootForImportPathStatic attempts to map importPath to a
// repoRoot using the commonly-used VCS hosting sites in vcsPaths
// (github.com/user/dir), or from a fully-qualified importPath already
// containing its VCS type (foo.com/repo.git/dir)
//
// If scheme is non-empty, that scheme is forced.
func repoRootForImportPathStatic(importPath, scheme string) (*repoRoot, error) {
// A common error is to use https://packagepath because that's what
// hg and git require. Diagnose this helpfully.
if loc := httpPrefixRE.FindStringIndex(importPath); loc != nil {
// The importPath has been cleaned, so has only one slash. The pattern
// ignores the slashes; the error message puts them back on the RHS at least.
return nil, fmt.Errorf("%q not allowed in import path", importPath[loc[0]:loc[1]]+"//")
}
for _, srv := range vcsPaths {
if !strings.HasPrefix(importPath, srv.prefix) {
continue
}
m := srv.regexp.FindStringSubmatch(importPath)
if m == nil {
if srv.prefix != "" {
return nil, fmt.Errorf("invalid %s import path %q", srv.prefix, importPath)
}
continue
}
// Build map of named subexpression matches for expand.
match := map[string]string{
"prefix": srv.prefix,
"import": importPath,
}
for i, name := range srv.regexp.SubexpNames() {
if name != "" && match[name] == "" {
match[name] = m[i]
}
}
if srv.vcs != "" {
match["vcs"] = expand(match, srv.vcs)
}
if srv.repo != "" {
match["repo"] = expand(match, srv.repo)
}
if srv.check != nil {
if err := srv.check(match); err != nil {
return nil, err
}
}
vcs := vcsByCmd(match["vcs"])
if vcs == nil {
return nil, fmt.Errorf("unknown version control system %q", match["vcs"])
}
if srv.ping {
if scheme != "" {
match["repo"] = scheme + "://" + match["repo"]
} else {
for _, scheme := range vcs.scheme {
if vcs.ping(scheme, match["repo"]) == nil {
match["repo"] = scheme + "://" + match["repo"]
break
}
}
}
}
rr := &repoRoot{
vcs: vcs,
repo: match["repo"],
root: match["root"],
}
return rr, nil
}
return nil, errUnknownSite
}
// repoRootForImportDynamic finds a *repoRoot for a custom domain that's not
// statically known by repoRootForImportPathStatic.
//
// This handles "vanity import paths" like "name.tld/pkg/foo".
func repoRootForImportDynamic(importPath string) (*repoRoot, error) {
slash := strings.Index(importPath, "/")
if slash < 0 {
return nil, errors.New("import path doesn't contain a slash")
}
host := importPath[:slash]
if !strings.Contains(host, ".") {
return nil, errors.New("import path doesn't contain a hostname")
}
urlStr, body, err := httpsOrHTTP(importPath)
if err != nil {
return nil, fmt.Errorf("http/https fetch: %v", err)
}
defer body.Close()
imports, err := parseMetaGoImports(body)
if err != nil {
return nil, fmt.Errorf("parsing %s: %v", importPath, err)
}
metaImport, err := matchGoImport(imports, importPath)
if err != nil {
if err != errNoMatch {
return nil, fmt.Errorf("parse %s: %v", urlStr, err)
}
return nil, fmt.Errorf("parse %s: no go-import meta tags", urlStr)
}
if buildV {
log.Printf("get %q: found meta tag %#v at %s", importPath, metaImport, urlStr)
}
// If the import was "uni.edu/bob/project", which said the
// prefix was "uni.edu" and the RepoRoot was "evilroot.com",
// make sure we don't trust Bob and check out evilroot.com to
// "uni.edu" yet (possibly overwriting/preempting another
// non-evil student). Instead, first verify the root and see
// if it matches Bob's claim.
if metaImport.Prefix != importPath {
if buildV {
log.Printf("get %q: verifying non-authoritative meta tag", importPath)
}
urlStr0 := urlStr
urlStr, body, err = httpsOrHTTP(metaImport.Prefix)
if err != nil {
return nil, fmt.Errorf("fetch %s: %v", urlStr, err)
}
imports, err := parseMetaGoImports(body)
if err != nil {
return nil, fmt.Errorf("parsing %s: %v", importPath, err)
}
if len(imports) == 0 {
return nil, fmt.Errorf("fetch %s: no go-import meta tag", urlStr)
}
metaImport2, err := matchGoImport(imports, importPath)
if err != nil || metaImport != metaImport2 {
return nil, fmt.Errorf("%s and %s disagree about go-import for %s", urlStr0, urlStr, metaImport.Prefix)
}
}
if !strings.Contains(metaImport.RepoRoot, "://") {
return nil, fmt.Errorf("%s: invalid repo root %q; no scheme", urlStr, metaImport.RepoRoot)
}
rr := &repoRoot{
vcs: vcsByCmd(metaImport.VCS),
repo: metaImport.RepoRoot,
root: metaImport.Prefix,
}
if rr.vcs == nil {
return nil, fmt.Errorf("%s: unknown vcs %q", urlStr, metaImport.VCS)
}
return rr, nil
}
// metaImport represents the parsed <meta name="go-import"
// content="prefix vcs reporoot" /> tags from HTML files.
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")
// 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) {
match := -1
for i, im := range imports {
if !strings.HasPrefix(importPath, im.Prefix) {
continue
}
if match != -1 {
err = fmt.Errorf("multiple meta tags match import path %q", importPath)
return
}
match = i
}
if match == -1 {
err = errNoMatch
return
}
return imports[match], nil
}
// expand rewrites s to replace {k} with match[k] for each key k in match.
func expand(match map[string]string, s string) string {
for k, v := range match {
s = strings.Replace(s, "{"+k+"}", v, -1)
}
return s
}
// vcsPaths lists the known vcs paths.
var vcsPaths = []*vcsPath{
// Google Code - new syntax
{
prefix: "code.google.com/",
re: `^(?P<root>code\.google\.com/p/(?P<project>[a-z0-9\-]+)(\.(?P<subrepo>[a-z0-9\-]+))?)(/[A-Za-z0-9_.\-]+)*$`,
repo: "https://{root}",
check: googleCodeVCS,
},
// Google Code - old syntax
{
re: `^(?P<project>[a-z0-9_\-.]+)\.googlecode\.com/(git|hg|svn)(?P<path>/.*)?$`,
check: oldGoogleCode,
},
// Github
{
prefix: "github.com/",
re: `^(?P<root>github\.com/[A-Za-z0-9_.\-]+/[A-Za-z0-9_.\-]+)(/[A-Za-z0-9_.\-]+)*$`,
vcs: "git",
repo: "https://{root}",
check: noVCSSuffix,
},
// Bitbucket
{
prefix: "bitbucket.org/",
re: `^(?P<root>bitbucket\.org/(?P<bitname>[A-Za-z0-9_.\-]+/[A-Za-z0-9_.\-]+))(/[A-Za-z0-9_.\-]+)*$`,
repo: "https://{root}",
check: bitbucketVCS,
},
// Launchpad
{
prefix: "launchpad.net/",
re: `^(?P<root>launchpad\.net/((?P<project>[A-Za-z0-9_.\-]+)(?P<series>/[A-Za-z0-9_.\-]+)?|~[A-Za-z0-9_.\-]+/(\+junk|[A-Za-z0-9_.\-]+)/[A-Za-z0-9_.\-]+))(/[A-Za-z0-9_.\-]+)*$`,
vcs: "bzr",
repo: "https://{root}",
check: launchpadVCS,
},
// General syntax for any server.
{
re: `^(?P<root>(?P<repo>([a-z0-9.\-]+\.)+[a-z0-9.\-]+(:[0-9]+)?/[A-Za-z0-9_.\-/]*?)\.(?P<vcs>bzr|git|hg|svn))(/[A-Za-z0-9_.\-]+)*$`,
ping: true,
},
}
func init() {
// fill in cached regexps.
// Doing this eagerly discovers invalid regexp syntax
// without having to run a command that needs that regexp.
for _, srv := range vcsPaths {
srv.regexp = regexp.MustCompile(srv.re)
}
}
// noVCSSuffix checks that the repository name does not
// end in .foo for any version control system foo.
// The usual culprit is ".git".
func noVCSSuffix(match map[string]string) error {
repo := match["repo"]
for _, vcs := range vcsList {
if strings.HasSuffix(repo, "."+vcs.cmd) {
return fmt.Errorf("invalid version control suffix in %s path", match["prefix"])
}
}
return nil
}
var googleCheckout = regexp.MustCompile(`id="checkoutcmd">(hg|git|svn)`)
// googleCodeVCS determines the version control system for
// a code.google.com repository, by scraping the project's
// /source/checkout page.
func googleCodeVCS(match map[string]string) error {
if err := noVCSSuffix(match); err != nil {
return err
}
data, err := httpGET(expand(match, "https://code.google.com/p/{project}/source/checkout?repo={subrepo}"))
if err != nil {
return err
}
if m := googleCheckout.FindSubmatch(data); m != nil {
if vcs := vcsByCmd(string(m[1])); vcs != nil {
// Subversion requires the old URLs.
// TODO: Test.
if vcs == vcsSvn {
if match["subrepo"] != "" {
return fmt.Errorf("sub-repositories not supported in Google Code Subversion projects")
}
match["repo"] = expand(match, "https://{project}.googlecode.com/svn")
}
match["vcs"] = vcs.cmd
return nil
}
}
return fmt.Errorf("unable to detect version control system for code.google.com/ path")
}
// oldGoogleCode is invoked for old-style foo.googlecode.com paths.
// It prints an error giving the equivalent new path.
func oldGoogleCode(match map[string]string) error {
return fmt.Errorf("invalid Google Code import path: use %s instead",
expand(match, "code.google.com/p/{project}{path}"))
}
// bitbucketVCS determines the version control system for a
// Bitbucket repository, by using the Bitbucket API.
func bitbucketVCS(match map[string]string) error {
if err := noVCSSuffix(match); err != nil {
return err
}
var resp struct {
SCM string `json:"scm"`
}
url := expand(match, "https://api.bitbucket.org/1.0/repositories/{bitname}")
data, err := httpGET(url)
if err != nil {
return err
}
if err := json.Unmarshal(data, &resp); err != nil {
return fmt.Errorf("decoding %s: %v", url, err)
}
if vcsByCmd(resp.SCM) != nil {
match["vcs"] = resp.SCM
if resp.SCM == "git" {
match["repo"] += ".git"
}
return nil
}
return fmt.Errorf("unable to detect version control system for bitbucket.org/ path")
}
// launchpadVCS solves the ambiguity for "lp.net/project/foo". In this case,
// "foo" could be a series name registered in Launchpad with its own branch,
// and it could also be the name of a directory within the main project
// branch one level up.
func launchpadVCS(match map[string]string) error {
if match["project"] == "" || match["series"] == "" {
return nil
}
_, err := httpGET(expand(match, "https://code.launchpad.net/{project}{series}/.bzr/branch-format"))
if err != nil {
match["root"] = expand(match, "launchpad.net/{project}")
match["repo"] = expand(match, "https://{root}")
}
return nil
}
// Copyright 2011 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 (
"fmt"
"runtime"
)
var cmdVersion = &Command{
Run: runVersion,
UsageLine: "version",
Short: "print Go version",
Long: `Version prints the Go version, as reported by runtime.Version.`,
}
func runVersion(cmd *Command, args []string) {
if len(args) != 0 {
cmd.Usage()
}
fmt.Printf("go version %s %s/%s\n", runtime.Version(), runtime.GOOS, runtime.GOARCH)
}
// Copyright 2011 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
func init() {
addBuildFlagsNX(cmdVet)
}
var cmdVet = &Command{
Run: runVet,
UsageLine: "vet [-n] [-x] [packages]",
Short: "run go tool vet on packages",
Long: `
Vet runs the Go vet command on the packages named by the import paths.
For more about vet, see 'godoc code.google.com/p/go.tools/cmd/vet'.
For more about specifying packages, see 'go help packages'.
To run the vet tool with specific options, run 'go tool vet'.
The -n flag prints commands that would be executed.
The -x flag prints commands as they are executed.
See also: go fmt, go fix.
`,
}
func runVet(cmd *Command, args []string) {
for _, pkg := range packages(args) {
// Use pkg.gofiles instead of pkg.Dir so that
// the command only applies to this package,
// not to packages in subdirectories.
run(tool("vet"), relPaths(stringList(pkg.gofiles, pkg.sfiles)))
}
}
// Copyright 2009 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.
/*
Gofmt formats Go programs.
It uses tabs (width = 8) for indentation and blanks for alignment.
Without an explicit path, it processes the standard input. Given a file,
it operates on that file; given a directory, it operates on all .go files in
that directory, recursively. (Files starting with a period are ignored.)
By default, gofmt prints the reformatted sources to standard output.
Usage:
gofmt [flags] [path ...]
The flags are:
-d
Do not print reformatted sources to standard output.
If a file's formatting is different than gofmt's, print diffs
to standard output.
-e
Print all (including spurious) errors.
-l
Do not print reformatted sources to standard output.
If a file's formatting is different from gofmt's, print its name
to standard output.
-r rule
Apply the rewrite rule to the source before reformatting.
-s
Try to simplify code (after applying the rewrite rule, if any).
-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.
Debugging support:
-cpuprofile filename
Write cpu profile to the specified file.
The rewrite rule specified with the -r flag must be a string of the form:
pattern -> replacement
Both pattern and replacement must be valid Go expressions.
In the pattern, single-character lowercase identifiers serve as
wildcards matching arbitrary sub-expressions; those expressions
will be substituted for the same identifiers in the replacement.
When gofmt reads from standard input, it accepts either a full Go program
or a program fragment. A program fragment must be a syntactically
valid declaration list, statement list, or expression. When formatting
such a fragment, gofmt preserves leading indentation as well as leading
and trailing spaces, so that individual sections of a Go program can be
formatted by piping them through gofmt.
Examples
To check files for unnecessary parentheses:
gofmt -r '(a) -> a' -l *.go
To remove the parentheses:
gofmt -r '(a) -> a' -w *.go
To convert the package tree from explicit slice upper bounds to implicit ones:
gofmt -r 'α[β:len(α)] -> α[β:]' -w $GOROOT/src/pkg
The simplify command
When invoked with -s gofmt will make the following source transformations where possible.
An array, slice, or map composite literal of the form:
[]T{T{}, T{}}
will be simplified to:
[]T{{}, {}}
A slice expression of the form:
s[a:len(s)]
will be simplified to:
s[a:]
A range of the form:
for x, _ = range v {...}
will be simplified to:
for x = range v {...}
*/
package main
// BUG(rsc): The implementation of -r is a bit slow.
// Copyright 2009 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"
"flag"
"fmt"
"go/ast"
"go/parser"
"go/printer"
"go/scanner"
"go/token"
"io"
"io/ioutil"
"os"
"os/exec"
"path/filepath"
"runtime/pprof"
"strings"
)
var (
// main operation modes
list = flag.Bool("l", false, "list files whose formatting differs from gofmt's")
write = flag.Bool("w", false, "write result to (source) file instead of stdout")
rewriteRule = flag.String("r", "", "rewrite rule (e.g., 'a[b:len(a)] -> a[b:]')")
simplifyAST = flag.Bool("s", false, "simplify code")
doDiff = flag.Bool("d", false, "display diffs instead of rewriting files")
allErrors = flag.Bool("e", false, "report all errors (not just the first 10 on different lines)")
// debugging
cpuprofile = flag.String("cpuprofile", "", "write cpu profile to this file")
)
const (
tabWidth = 8
printerMode = printer.UseSpaces | printer.TabIndent
)
var (
fileSet = token.NewFileSet() // per process FileSet
exitCode = 0
rewrite func(*ast.File) *ast.File
parserMode parser.Mode
)
func report(err error) {
scanner.PrintError(os.Stderr, err)
exitCode = 2
}
func usage() {
fmt.Fprintf(os.Stderr, "usage: gofmt [flags] [path ...]\n")
flag.PrintDefaults()
os.Exit(2)
}
func initParserMode() {
parserMode = parser.ParseComments
if *allErrors {
parserMode |= parser.AllErrors
}
}
func isGoFile(f os.FileInfo) bool {
// ignore non-Go files
name := f.Name()
return !f.IsDir() && !strings.HasPrefix(name, ".") && strings.HasSuffix(name, ".go")
}
// 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 {
if in == nil {
f, err := os.Open(filename)
if err != nil {
return err
}
defer f.Close()
in = f
}
src, err := ioutil.ReadAll(in)
if err != nil {
return err
}
file, adjust, err := parse(fileSet, filename, src, stdin)
if err != nil {
return err
}
if rewrite != nil {
if adjust == nil {
file = rewrite(file)
} else {
fmt.Fprintf(os.Stderr, "warning: rewrite ignored for incomplete programs\n")
}
}
ast.SortImports(fileSet, file)
if *simplifyAST {
simplify(file)
}
var buf bytes.Buffer
err = (&printer.Config{Mode: printerMode, Tabwidth: tabWidth}).Fprint(&buf, fileSet, file)
if err != nil {
return err
}
res := buf.Bytes()
if adjust != nil {
res = adjust(src, res)
}
if !bytes.Equal(src, res) {
// formatting has changed
if *list {
fmt.Fprintln(out, filename)
}
if *write {
err = ioutil.WriteFile(filename, res, 0)
if err != nil {
return err
}
}
if *doDiff {
data, err := diff(src, res)
if err != nil {
return fmt.Errorf("computing diff: %s", err)
}
fmt.Printf("diff %s gofmt/%s\n", filename, filename)
out.Write(data)
}
}
if !*list && !*write && !*doDiff {
_, err = out.Write(res)
}
return err
}
func visitFile(path string, f os.FileInfo, err error) error {
if err == nil && isGoFile(f) {
err = processFile(path, nil, os.Stdout, false)
}
if err != nil {
report(err)
}
return nil
}
func walkDir(path string) {
filepath.Walk(path, visitFile)
}
func main() {
// call gofmtMain in a separate function
// so that it can use defer and have them
// run before the exit.
gofmtMain()
os.Exit(exitCode)
}
func gofmtMain() {
flag.Usage = usage
flag.Parse()
if *cpuprofile != "" {
f, err := os.Create(*cpuprofile)
if err != nil {
fmt.Fprintf(os.Stderr, "creating cpu profile: %s\n", err)
exitCode = 2
return
}
defer f.Close()
pprof.StartCPUProfile(f)
defer pprof.StopCPUProfile()
}
initParserMode()
initRewrite()
if flag.NArg() == 0 {
if err := processFile("<standard input>", os.Stdin, os.Stdout, true); err != nil {
report(err)
}
return
}
for i := 0; i < flag.NArg(); i++ {
path := flag.Arg(i)
switch dir, err := os.Stat(path); {
case err != nil:
report(err)
case dir.IsDir():
walkDir(path)
default:
if err := processFile(path, nil, os.Stdout, false); err != nil {
report(err)
}
}
}
}
func diff(b1, b2 []byte) (data []byte, err error) {
f1, err := ioutil.TempFile("", "gofmt")
if err != nil {
return
}
defer os.Remove(f1.Name())
defer f1.Close()
f2, err := ioutil.TempFile("", "gofmt")
if err != nil {
return
}
defer os.Remove(f2.Name())
defer f2.Close()
f1.Write(b1)
f2.Write(b2)
data, err = exec.Command("diff", "-u", f1.Name(), f2.Name()).CombinedOutput()
if len(data) > 0 {
// diff exits with a non-zero status when the files don't match.
// Ignore that failure as long as we get output.
err = nil
}
return
}
// parse parses src, which was read from filename,
// as a Go source file or statement list.
func parse(fset *token.FileSet, filename string, src []byte, stdin bool) (*ast.File, func(orig, src []byte) []byte, error) {
// Try as whole source file.
file, err := parser.ParseFile(fset, filename, src, parserMode)
if err == nil {
return file, nil, nil
}
// If the error is that the source file didn't begin with a
// package line and this is standard input, fall through to
// try as a source fragment. Stop and return on any other error.
if !stdin || !strings.Contains(err.Error(), "expected 'package'") {
return nil, nil, err
}
// If this is a declaration list, make it a source file
// by inserting a package clause.
// Insert using a ;, not a newline, so that the line numbers
// in psrc match the ones in src.
psrc := append([]byte("package p;"), src...)
file, err = parser.ParseFile(fset, filename, psrc, parserMode)
if err == nil {
adjust := func(orig, src []byte) []byte {
// Remove the package clause.
// Gofmt has turned the ; into a \n.
src = src[len("package p\n"):]
return matchSpace(orig, src)
}
return file, adjust, nil
}
// If the error is that the source file didn't begin with a
// declaration, fall through to try as a statement list.
// Stop and return on any other error.
if !strings.Contains(err.Error(), "expected declaration") {
return nil, nil, err
}
// If this is a statement list, make it a source file
// by inserting a package clause and turning the list
// into a function body. This handles expressions too.
// Insert using a ;, not a newline, so that the line numbers
// in fsrc match the ones in src.
fsrc := append(append([]byte("package p; func _() {"), src...), '}')
file, err = parser.ParseFile(fset, filename, fsrc, parserMode)
if err == nil {
adjust := func(orig, src []byte) []byte {
// Remove the wrapping.
// Gofmt has turned the ; into a \n\n.
src = src[len("package p\n\nfunc _() {"):]
src = src[:len(src)-len("}\n")]
// Gofmt has also indented the function body one level.
// Remove that indent.
src = bytes.Replace(src, []byte("\n\t"), []byte("\n"), -1)
return matchSpace(orig, src)
}
return file, adjust, nil
}
// Failed, and out of options.
return nil, nil, err
}
func cutSpace(b []byte) (before, middle, after []byte) {
i := 0
for i < len(b) && (b[i] == ' ' || b[i] == '\t' || b[i] == '\n') {
i++
}
j := len(b)
for j > 0 && (b[j-1] == ' ' || b[j-1] == '\t' || b[j-1] == '\n') {
j--
}
if i <= j {
return b[:i], b[i:j], b[j:]
}
return nil, nil, b[j:]
}
// matchSpace reformats src to use the same space context as orig.
// 1) If orig begins with blank lines, matchSpace inserts them at the beginning of src.
// 2) matchSpace copies the indentation of the first non-blank line in orig
// to every non-blank line in src.
// 3) matchSpace copies the trailing space from orig and uses it in place
// of src's trailing space.
func matchSpace(orig []byte, src []byte) []byte {
before, _, after := cutSpace(orig)
i := bytes.LastIndex(before, []byte{'\n'})
before, indent := before[:i+1], before[i+1:]
_, src, _ = cutSpace(src)
var b bytes.Buffer
b.Write(before)
for len(src) > 0 {
line := src
if i := bytes.IndexByte(line, '\n'); i >= 0 {
line, src = line[:i+1], line[i+1:]
} else {
src = nil
}
if len(line) > 0 && line[0] != '\n' { // not blank
b.Write(indent)
}
b.Write(line)
}
b.Write(after)
return b.Bytes()
}
// Copyright 2011 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"
"io/ioutil"
"path/filepath"
"strings"
"testing"
)
func runTest(t *testing.T, in, out, flags string) {
// process flags
*simplifyAST = false
*rewriteRule = ""
stdin := false
for _, flag := range strings.Split(flags, " ") {
elts := strings.SplitN(flag, "=", 2)
name := elts[0]
value := ""
if len(elts) == 2 {
value = elts[1]
}
switch name {
case "":
// no flags
case "-r":
*rewriteRule = value
case "-s":
*simplifyAST = true
case "-stdin":
// fake flag - pretend input is from stdin
stdin = true
default:
t.Errorf("unrecognized flag name: %s", name)
}
}
initParserMode()
initRewrite()
var buf bytes.Buffer
err := processFile(in, nil, &buf, stdin)
if err != nil {
t.Error(err)
return
}
expected, err := ioutil.ReadFile(out)
if err != nil {
t.Error(err)
return
}
if got := buf.Bytes(); !bytes.Equal(got, expected) {
t.Errorf("(gofmt %s) != %s (see %s.gofmt)", in, out, in)
d, err := diff(expected, got)
if err == nil {
t.Errorf("%s", d)
}
if err := ioutil.WriteFile(in+".gofmt", got, 0666); err != nil {
t.Error(err)
}
}
}
var tests = []struct {
in, flags string
}{
{"gofmt.go", ""},
{"gofmt_test.go", ""},
{"testdata/composites.input", "-s"},
{"testdata/slices1.input", "-s"},
{"testdata/slices2.input", "-s"},
{"testdata/old.input", ""},
{"testdata/rewrite1.input", "-r=Foo->Bar"},
{"testdata/rewrite2.input", "-r=int->bool"},
{"testdata/rewrite3.input", "-r=x->x"},
{"testdata/rewrite4.input", "-r=(x)->x"},
{"testdata/rewrite5.input", "-r=x+x->2*x"},
{"testdata/rewrite6.input", "-r=fun(x)->Fun(x)"},
{"testdata/rewrite7.input", "-r=fun(x...)->Fun(x)"},
{"testdata/rewrite8.input", "-r=interface{}->int"},
{"testdata/stdin*.input", "-stdin"},
{"testdata/comments.input", ""},
{"testdata/import.input", ""},
{"testdata/crlf.input", ""}, // test case for issue 3961; see also TestCRLF
{"testdata/typeswitch.input", ""}, // test case for issue 4470
}
func TestRewrite(t *testing.T) {
for _, test := range tests {
match, err := filepath.Glob(test.in)
if err != nil {
t.Error(err)
continue
}
for _, in := range match {
out := in
if strings.HasSuffix(in, ".input") {
out = in[:len(in)-len(".input")] + ".golden"
}
runTest(t, in, out, test.flags)
if in != out {
// Check idempotence.
runTest(t, out, out, test.flags)
}
}
}
}
func TestCRLF(t *testing.T) {
const input = "testdata/crlf.input" // must contain CR/LF's
const golden = "testdata/crlf.golden" // must not contain any CR's
data, err := ioutil.ReadFile(input)
if err != nil {
t.Error(err)
}
if bytes.Index(data, []byte("\r\n")) < 0 {
t.Errorf("%s contains no CR/LF's", input)
}
data, err = ioutil.ReadFile(golden)
if err != nil {
t.Error(err)
}
if bytes.Index(data, []byte("\r")) >= 0 {
t.Errorf("%s contains CR's", golden)
}
}
// Copyright 2011 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.
// This test applies gofmt to all Go files under -root.
// To test specific files provide a list of comma-separated
// filenames via the -files flag: go test -files=gofmt.go .
package main
import (
"bytes"
"flag"
"fmt"
"go/ast"
"go/printer"
"go/token"
"io"
"os"
"path/filepath"
"runtime"
"strings"
"testing"
)
var (
root = flag.String("root", runtime.GOROOT(), "test root directory")
files = flag.String("files", "", "comma-separated list of files to test")
ngo = flag.Int("n", runtime.NumCPU(), "number of goroutines used")
verbose = flag.Bool("verbose", false, "verbose mode")
nfiles int // number of files processed
)
func gofmt(fset *token.FileSet, filename string, src *bytes.Buffer) error {
f, _, err := parse(fset, filename, src.Bytes(), false)
if err != nil {
return err
}
ast.SortImports(fset, f)
src.Reset()
return (&printer.Config{Mode: printerMode, Tabwidth: tabWidth}).Fprint(src, fset, f)
}
func testFile(t *testing.T, b1, b2 *bytes.Buffer, filename string) {
// open file
f, err := os.Open(filename)
if err != nil {
t.Error(err)
return
}
// read file
b1.Reset()
_, err = io.Copy(b1, f)
f.Close()
if err != nil {
t.Error(err)
return
}
// exclude files w/ syntax errors (typically test cases)
fset := token.NewFileSet()
if _, _, err = parse(fset, filename, b1.Bytes(), false); err != nil {
if *verbose {
fmt.Fprintf(os.Stderr, "ignoring %s\n", err)
}
return
}
// gofmt file
if err = gofmt(fset, filename, b1); err != nil {
t.Errorf("1st gofmt failed: %v", err)
return
}
// make a copy of the result
b2.Reset()
b2.Write(b1.Bytes())
// gofmt result again
if err = gofmt(fset, filename, b2); err != nil {
t.Errorf("2nd gofmt failed: %v", err)
return
}
// the first and 2nd result should be identical
if !bytes.Equal(b1.Bytes(), b2.Bytes()) {
t.Errorf("gofmt %s not idempotent", filename)
}
}
func testFiles(t *testing.T, filenames <-chan string, done chan<- int) {
b1 := new(bytes.Buffer)
b2 := new(bytes.Buffer)
for filename := range filenames {
testFile(t, b1, b2, filename)
}
done <- 0
}
func genFilenames(t *testing.T, filenames chan<- string) {
defer close(filenames)
handleFile := func(filename string, fi os.FileInfo, err error) error {
if err != nil {
t.Error(err)
return nil
}
if isGoFile(fi) {
filenames <- filename
nfiles++
}
return nil
}
// test Go files provided via -files, if any
if *files != "" {
for _, filename := range strings.Split(*files, ",") {
fi, err := os.Stat(filename)
handleFile(filename, fi, err)
}
return // ignore files under -root
}
// otherwise, test all Go files under *root
filepath.Walk(*root, handleFile)
}
func TestAll(t *testing.T) {
if testing.Short() {
return
}
if *ngo < 1 {
*ngo = 1 // make sure test is run
}
if *verbose {
fmt.Printf("running test using %d goroutines\n", *ngo)
}
// generate filenames
filenames := make(chan string, 32)
go genFilenames(t, filenames)
// launch test goroutines
done := make(chan int)
for i := 0; i < *ngo; i++ {
go testFiles(t, filenames, done)
}
// wait for all test goroutines to complete
for i := 0; i < *ngo; i++ {
<-done
}
if *verbose {
fmt.Printf("processed %d files\n", nfiles)
}
}
// Copyright 2009 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 (
"fmt"
"go/ast"
"go/parser"
"go/token"
"os"
"reflect"
"strings"
"unicode"
"unicode/utf8"
)
func initRewrite() {
if *rewriteRule == "" {
rewrite = nil // disable any previous rewrite
return
}
f := strings.Split(*rewriteRule, "->")
if len(f) != 2 {
fmt.Fprintf(os.Stderr, "rewrite rule must be of the form 'pattern -> replacement'\n")
os.Exit(2)
}
pattern := parseExpr(f[0], "pattern")
replace := parseExpr(f[1], "replacement")
rewrite = func(p *ast.File) *ast.File { return rewriteFile(pattern, replace, p) }
}
// parseExpr parses s as an expression.
// It might make sense to expand this to allow statement patterns,
// but there are problems with preserving formatting and also
// with what a wildcard for a statement looks like.
func parseExpr(s, what string) ast.Expr {
x, err := parser.ParseExpr(s)
if err != nil {
fmt.Fprintf(os.Stderr, "parsing %s %s at %s\n", what, s, err)
os.Exit(2)
}
return x
}
// Keep this function for debugging.
/*
func dump(msg string, val reflect.Value) {
fmt.Printf("%s:\n", msg)
ast.Print(fileSet, val.Interface())
fmt.Println()
}
*/
// rewriteFile applies the rewrite rule 'pattern -> replace' to an entire file.
func rewriteFile(pattern, replace ast.Expr, p *ast.File) *ast.File {
cmap := ast.NewCommentMap(fileSet, p, p.Comments)
m := make(map[string]reflect.Value)
pat := reflect.ValueOf(pattern)
repl := reflect.ValueOf(replace)
var rewriteVal func(val reflect.Value) reflect.Value
rewriteVal = func(val reflect.Value) reflect.Value {
// don't bother if val is invalid to start with
if !val.IsValid() {
return reflect.Value{}
}
for k := range m {
delete(m, k)
}
val = apply(rewriteVal, val)
if match(m, pat, val) {
val = subst(m, repl, reflect.ValueOf(val.Interface().(ast.Node).Pos()))
}
return val
}
r := apply(rewriteVal, reflect.ValueOf(p)).Interface().(*ast.File)
r.Comments = cmap.Filter(r).Comments() // recreate comments list
return r
}
// set is a wrapper for x.Set(y); it protects the caller from panics if x cannot be changed to y.
func set(x, y reflect.Value) {
// don't bother if x cannot be set or y is invalid
if !x.CanSet() || !y.IsValid() {
return
}
defer func() {
if x := recover(); x != nil {
if s, ok := x.(string); ok &&
(strings.Contains(s, "type mismatch") || strings.Contains(s, "not assignable")) {
// x cannot be set to y - ignore this rewrite
return
}
panic(x)
}
}()
x.Set(y)
}
// Values/types for special cases.
var (
objectPtrNil = reflect.ValueOf((*ast.Object)(nil))
scopePtrNil = reflect.ValueOf((*ast.Scope)(nil))
identType = reflect.TypeOf((*ast.Ident)(nil))
objectPtrType = reflect.TypeOf((*ast.Object)(nil))
positionType = reflect.TypeOf(token.NoPos)
callExprType = reflect.TypeOf((*ast.CallExpr)(nil))
scopePtrType = reflect.TypeOf((*ast.Scope)(nil))
)
// apply replaces each AST field x in val with f(x), returning val.
// To avoid extra conversions, f operates on the reflect.Value form.
func apply(f func(reflect.Value) reflect.Value, val reflect.Value) reflect.Value {
if !val.IsValid() {
return reflect.Value{}
}
// *ast.Objects introduce cycles and are likely incorrect after
// rewrite; don't follow them but replace with nil instead
if val.Type() == objectPtrType {
return objectPtrNil
}
// similarly for scopes: they are likely incorrect after a rewrite;
// replace them with nil
if val.Type() == scopePtrType {
return scopePtrNil
}
switch v := reflect.Indirect(val); v.Kind() {
case reflect.Slice:
for i := 0; i < v.Len(); i++ {
e := v.Index(i)
set(e, f(e))
}
case reflect.Struct:
for i := 0; i < v.NumField(); i++ {
e := v.Field(i)
set(e, f(e))
}
case reflect.Interface:
e := v.Elem()
set(v, f(e))
}
return val
}
func isWildcard(s string) bool {
rune, size := utf8.DecodeRuneInString(s)
return size == len(s) && unicode.IsLower(rune)
}
// match returns true if pattern matches val,
// recording wildcard submatches in m.
// If m == nil, match checks whether pattern == val.
func match(m map[string]reflect.Value, pattern, val reflect.Value) bool {
// Wildcard matches any expression. If it appears multiple
// times in the pattern, it must match the same expression
// each time.
if m != nil && pattern.IsValid() && pattern.Type() == identType {
name := pattern.Interface().(*ast.Ident).Name
if isWildcard(name) && val.IsValid() {
// wildcards only match valid (non-nil) expressions.
if _, ok := val.Interface().(ast.Expr); ok && !val.IsNil() {
if old, ok := m[name]; ok {
return match(nil, old, val)
}
m[name] = val
return true
}
}
}
// Otherwise, pattern and val must match recursively.
if !pattern.IsValid() || !val.IsValid() {
return !pattern.IsValid() && !val.IsValid()
}
if pattern.Type() != val.Type() {
return false
}
// Special cases.
switch pattern.Type() {
case identType:
// For identifiers, only the names need to match
// (and none of the other *ast.Object information).
// This is a common case, handle it all here instead
// of recursing down any further via reflection.
p := pattern.Interface().(*ast.Ident)
v := val.Interface().(*ast.Ident)
return p == nil && v == nil || p != nil && v != nil && p.Name == v.Name
case objectPtrType, positionType:
// object pointers and token positions always match
return true
case callExprType:
// For calls, the Ellipsis fields (token.Position) must
// match since that is how f(x) and f(x...) are different.
// Check them here but fall through for the remaining fields.
p := pattern.Interface().(*ast.CallExpr)
v := val.Interface().(*ast.CallExpr)
if p.Ellipsis.IsValid() != v.Ellipsis.IsValid() {
return false
}
}
p := reflect.Indirect(pattern)
v := reflect.Indirect(val)
if !p.IsValid() || !v.IsValid() {
return !p.IsValid() && !v.IsValid()
}
switch p.Kind() {
case reflect.Slice:
if p.Len() != v.Len() {
return false
}
for i := 0; i < p.Len(); i++ {
if !match(m, p.Index(i), v.Index(i)) {
return false
}
}
return true
case reflect.Struct:
if p.NumField() != v.NumField() {
return false
}
for i := 0; i < p.NumField(); i++ {
if !match(m, p.Field(i), v.Field(i)) {
return false
}
}
return true
case reflect.Interface:
return match(m, p.Elem(), v.Elem())
}
// Handle token integers, etc.
return p.Interface() == v.Interface()
}
// subst returns a copy of pattern with values from m substituted in place
// of wildcards and pos used as the position of tokens from the pattern.
// if m == nil, subst returns a copy of pattern and doesn't change the line
// number information.
func subst(m map[string]reflect.Value, pattern reflect.Value, pos reflect.Value) reflect.Value {
if !pattern.IsValid() {
return reflect.Value{}
}
// Wildcard gets replaced with map value.
if m != nil && pattern.Type() == identType {
name := pattern.Interface().(*ast.Ident).Name
if isWildcard(name) {
if old, ok := m[name]; ok {
return subst(nil, old, reflect.Value{})
}
}
}
if pos.IsValid() && pattern.Type() == positionType {
// use new position only if old position was valid in the first place
if old := pattern.Interface().(token.Pos); !old.IsValid() {
return pattern
}
return pos
}
// Otherwise copy.
switch p := pattern; p.Kind() {
case reflect.Slice:
v := reflect.MakeSlice(p.Type(), p.Len(), p.Len())
for i := 0; i < p.Len(); i++ {
v.Index(i).Set(subst(m, p.Index(i), pos))
}
return v
case reflect.Struct:
v := reflect.New(p.Type()).Elem()
for i := 0; i < p.NumField(); i++ {
v.Field(i).Set(subst(m, p.Field(i), pos))
}
return v
case reflect.Ptr:
v := reflect.New(p.Type()).Elem()
if elem := p.Elem(); elem.IsValid() {
v.Set(subst(m, elem, pos).Addr())
}
return v
case reflect.Interface:
v := reflect.New(p.Type()).Elem()
if elem := p.Elem(); elem.IsValid() {
v.Set(subst(m, elem, pos))
}
return v
}
return pattern
}
// Copyright 2010 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package main
import (
"go/ast"
"go/token"
"reflect"
)
type simplifier struct {
hasDotImport bool // package file contains: import . "some/import/path"
}
func (s *simplifier) Visit(node ast.Node) ast.Visitor {
switch n := node.(type) {
case *ast.CompositeLit:
// array, slice, and map composite literals may be simplified
outer := n
var eltType ast.Expr
switch typ := outer.Type.(type) {
case *ast.ArrayType:
eltType = typ.Elt
case *ast.MapType:
eltType = typ.Value
}
if eltType != nil {
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 {
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 &
}
}
}
}
}
// node was simplified - stop walk (there are no subnodes to simplify)
return nil
}
case *ast.SliceExpr:
// a slice expression of the form: s[a:len(s)]
// can be simplified to: s[a:]
// if s is "simple enough" (for now we only accept identifiers)
if s.hasDotImport {
// if dot imports are present, we cannot be certain that an
// unresolved "len" identifier refers to the predefined len()
break
}
if s, _ := n.X.(*ast.Ident); s != nil && s.Obj != nil {
// the array/slice object is a single, resolved identifier
if call, _ := n.High.(*ast.CallExpr); call != nil && len(call.Args) == 1 && !call.Ellipsis.IsValid() {
// the high expression is a function call with a single argument
if fun, _ := call.Fun.(*ast.Ident); fun != nil && fun.Name == "len" && fun.Obj == nil {
// the function called is "len" and it is not locally defined; and
// because we don't have dot imports, it must be the predefined len()
if arg, _ := call.Args[0].(*ast.Ident); arg != nil && arg.Obj == s.Obj {
// the len argument is the array/slice object
n.High = nil
}
}
}
}
// Note: We could also simplify slice expressions of the form s[0:b] to s[:b]
// but we leave them as is since sometimes we want to be very explicit
// about the lower bound.
// An example where the 0 helps:
// x, y, z := b[0:2], b[2:4], b[4:6]
// An example where it does not:
// x, y := b[:n], b[n:]
case *ast.RangeStmt:
// a range of the form: for x, _ = range v {...}
// can be simplified to: for x = range v {...}
if ident, _ := n.Value.(*ast.Ident); ident != nil && ident.Name == "_" {
n.Value = nil
}
}
return s
}
func simplify(f *ast.File) {
var s simplifier
// determine if f contains dot imports
for _, imp := range f.Imports {
if imp.Name != nil && imp.Name.Name == "." {
s.hasDotImport = true
break
}
}
ast.Walk(&s, f)
}
package main
func main() {}
// comment here
func f() {}
//line foo.go:1
package main
func main() {}
// comment here
func f() {}
//line foo.go:1
package P
type T struct {
x, y int
}
var _ = [42]T{
{},
{1, 2},
{3, 4},
}
var _ = [...]T{
{},
{1, 2},
{3, 4},
}
var _ = []T{
{},
{1, 2},
{3, 4},
}
var _ = []T{
{},
10: {1, 2},
20: {3, 4},
}
var _ = []struct {
x, y int
}{
{},
10: {1, 2},
20: {3, 4},
}
var _ = []interface{}{
T{},
10: T{1, 2},
20: T{3, 4},
}
var _ = [][]int{
{},
{1, 2},
{3, 4},
}
var _ = [][]int{
([]int{}),
([]int{1, 2}),
{3, 4},
}
var _ = [][][]int{
{},
{
{},
{0, 1, 2, 3},
{4, 5},
},
}
var _ = map[string]T{
"foo": {},
"bar": {1, 2},
"bal": {3, 4},
}
var _ = map[string]struct {
x, y int
}{
"foo": {},
"bar": {1, 2},
"bal": {3, 4},
}
var _ = map[string]interface{}{
"foo": T{},
"bar": T{1, 2},
"bal": T{3, 4},
}
var _ = map[string][]int{
"foo": {},
"bar": {1, 2},
"bal": {3, 4},
}
var _ = map[string][]int{
"foo": ([]int{}),
"bar": ([]int{1, 2}),
"bal": {3, 4},
}
// from exp/4s/data.go
var pieces4 = []Piece{
{0, 0, Point{4, 1}, []Point{{0, 0}, {1, 0}, {1, 0}, {1, 0}}, nil, nil},
{1, 0, Point{1, 4}, []Point{{0, 0}, {0, 1}, {0, 1}, {0, 1}}, nil, nil},
{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 _ = [42]*T{
{},
{1, 2},
{3, 4},
}
var _ = [...]*T{
{},
{1, 2},
{3, 4},
}
var _ = []*T{
{},
{1, 2},
{3, 4},
}
var _ = []*T{
{},
10: {1, 2},
20: {3, 4},
}
var _ = []*struct {
x, y int
}{
{},
10: {1, 2},
20: {3, 4},
}
var _ = []interface{}{
&T{},
10: &T{1, 2},
20: &T{3, 4},
}
var _ = []*[]int{
{},
{1, 2},
{3, 4},
}
var _ = []*[]int{
(&[]int{}),
(&[]int{1, 2}),
{3, 4},
}
var _ = []*[]*[]int{
{},
{
{},
{0, 1, 2, 3},
{4, 5},
},
}
var _ = map[string]*T{
"foo": {},
"bar": {1, 2},
"bal": {3, 4},
}
var _ = map[string]*struct {
x, y int
}{
"foo": {},
"bar": {1, 2},
"bal": {3, 4},
}
var _ = map[string]interface{}{
"foo": &T{},
"bar": &T{1, 2},
"bal": &T{3, 4},
}
var _ = map[string]*[]int{
"foo": {},
"bar": {1, 2},
"bal": {3, 4},
}
var _ = map[string]*[]int{
"foo": (&[]int{}),
"bar": (&[]int{1, 2}),
"bal": {3, 4},
}
var pieces4 = []*Piece{
{0, 0, Point{4, 1}, []Point{{0, 0}, {1, 0}, {1, 0}, {1, 0}}, nil, nil},
{1, 0, Point{1, 4}, []Point{{0, 0}, {0, 1}, {0, 1}, {0, 1}}, nil, nil},
{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},
}
package P
type T struct {
x, y int
}
var _ = [42]T{
T{},
T{1, 2},
T{3, 4},
}
var _ = [...]T{
T{},
T{1, 2},
T{3, 4},
}
var _ = []T{
T{},
T{1, 2},
T{3, 4},
}
var _ = []T{
T{},
10: T{1, 2},
20: T{3, 4},
}
var _ = []struct {
x, y int
}{
struct{ x, y int }{},
10: struct{ x, y int }{1, 2},
20: struct{ x, y int }{3, 4},
}
var _ = []interface{}{
T{},
10: T{1, 2},
20: T{3, 4},
}
var _ = [][]int{
[]int{},
[]int{1, 2},
[]int{3, 4},
}
var _ = [][]int{
([]int{}),
([]int{1, 2}),
[]int{3, 4},
}
var _ = [][][]int{
[][]int{},
[][]int{
[]int{},
[]int{0, 1, 2, 3},
[]int{4, 5},
},
}
var _ = map[string]T{
"foo": T{},
"bar": T{1, 2},
"bal": T{3, 4},
}
var _ = map[string]struct {
x, y int
}{
"foo": struct{ x, y int }{},
"bar": struct{ x, y int }{1, 2},
"bal": struct{ x, y int }{3, 4},
}
var _ = map[string]interface{}{
"foo": T{},
"bar": T{1, 2},
"bal": T{3, 4},
}
var _ = map[string][]int{
"foo": []int{},
"bar": []int{1, 2},
"bal": []int{3, 4},
}
var _ = map[string][]int{
"foo": ([]int{}),
"bar": ([]int{1, 2}),
"bal": []int{3, 4},
}
// from exp/4s/data.go
var pieces4 = []Piece{
Piece{0, 0, Point{4, 1}, []Point{Point{0, 0}, Point{1, 0}, Point{1, 0}, Point{1, 0}}, nil, nil},
Piece{1, 0, Point{1, 4}, []Point{Point{0, 0}, Point{0, 1}, Point{0, 1}, Point{0, 1}}, nil, nil},
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 _ = [42]*T{
&T{},
&T{1, 2},
&T{3, 4},
}
var _ = [...]*T{
&T{},
&T{1, 2},
&T{3, 4},
}
var _ = []*T{
&T{},
&T{1, 2},
&T{3, 4},
}
var _ = []*T{
&T{},
10: &T{1, 2},
20: &T{3, 4},
}
var _ = []*struct {
x, y int
}{
&struct{ x, y int }{},
10: &struct{ x, y int }{1, 2},
20: &struct{ x, y int }{3, 4},
}
var _ = []interface{}{
&T{},
10: &T{1, 2},
20: &T{3, 4},
}
var _ = []*[]int{
&[]int{},
&[]int{1, 2},
&[]int{3, 4},
}
var _ = []*[]int{
(&[]int{}),
(&[]int{1, 2}),
&[]int{3, 4},
}
var _ = []*[]*[]int{
&[]*[]int{},
&[]*[]int{
&[]int{},
&[]int{0, 1, 2, 3},
&[]int{4, 5},
},
}
var _ = map[string]*T{
"foo": &T{},
"bar": &T{1, 2},
"bal": &T{3, 4},
}
var _ = map[string]*struct {
x, y int
}{
"foo": &struct{ x, y int }{},
"bar": &struct{ x, y int }{1, 2},
"bal": &struct{ x, y int }{3, 4},
}
var _ = map[string]interface{}{
"foo": &T{},
"bar": &T{1, 2},
"bal": &T{3, 4},
}
var _ = map[string]*[]int{
"foo": &[]int{},
"bar": &[]int{1, 2},
"bal": &[]int{3, 4},
}
var _ = map[string]*[]int{
"foo": (&[]int{}),
"bar": (&[]int{1, 2}),
"bal": &[]int{3, 4},
}
var pieces4 = []*Piece{
&Piece{0, 0, Point{4, 1}, []Point{Point{0, 0}, Point{1, 0}, Point{1, 0}, Point{1, 0}}, nil, nil},
&Piece{1, 0, Point{1, 4}, []Point{Point{0, 0}, Point{0, 1}, Point{0, 1}, Point{0, 1}}, nil, nil},
&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},
}
/*
Source containing CR/LF line endings.
The gofmt'ed output must only have LF
line endings.
*/
package main
func main() {
// line comment
println("hello, world!") // another line comment
println()
}
/*
Source containing CR/LF line endings.
The gofmt'ed output must only have LF
line endings.
*/
package main
func main() {
// line comment
println("hello, world!") // another line comment
println()
}
package main
import (
"errors"
"fmt"
"io"
"log"
"math"
)
import (
"fmt"
"math"
"log"
"errors"
"io"
)
import (
"errors"
"fmt"
"io"
"log"
"math"
"fmt"
"math"
"log"
"errors"
"io"
)
import (
// a block with comments
"errors"
"fmt" // for Printf
"io" // for Reader
"log" // for Fatal
"math"
)
import (
"fmt" // for Printf
"math"
"log" // for Fatal
"errors"
"io" // for Reader
)
import (
// for Printf
"fmt"
"math"
// for Fatal
"log"
"errors"
// for Reader
"io"
)
import (
"errors"
"fmt" // for Printf
"io" // for Reader
"log" // for Fatal
"math"
"fmt" // for Printf
"math"
"log" // for Fatal
"errors"
"io" // for Reader
)
import (
"fmt" // for Printf
"errors"
"io" // for Reader
"log" // for Fatal
"math"
"errors"
"fmt" // for Printf
"io" // for Reader
"log" // for Fatal
"math"
)
// Test deduping and extended sorting
import (
a "A" // aA
b "A" // bA1
b "A" // bA2
"B" // B
. "B" // .B
_ "B" // _b
"C"
a "D" // aD
)
import (
"dedup_by_group"
"dedup_by_group"
)
package main
import (
"fmt"
"math"
"log"
"errors"
"io"
)
import (
"fmt"
"math"
"log"
"errors"
"io"
)
import (
"fmt"
"math"
"log"
"errors"
"io"
"fmt"
"math"
"log"
"errors"
"io"
)
import (
// a block with comments
"fmt" // for Printf
"math"
"log" // for Fatal
"errors"
"io" // for Reader
)
import (
"fmt" // for Printf
"math"
"log" // for Fatal
"errors"
"io" // for Reader
)
import (
// for Printf
"fmt"
"math"
// for Fatal
"log"
"errors"
// for Reader
"io"
)
import (
"fmt" // for Printf
"math"
"log" // for Fatal
"errors"
"io" // for Reader
"fmt" // for Printf
"math"
"log" // for Fatal
"errors"
"io" // for Reader
)
import (
"fmt" // for Printf
"math"
"log" // for Fatal
"errors"
"io" // for Reader
"fmt" // for Printf
"math"
"log" // for Fatal
"errors"
"io" // for Reader
)
// Test deduping and extended sorting
import (
"B" // B
a "A" // aA
b "A" // bA2
b "A" // bA1
. "B" // .B
. "B"
"C"
"C"
"C"
a "D" // aD
"B"
_ "B" // _b
)
import (
"dedup_by_group"
"dedup_by_group"
"dedup_by_group"
)
package P
func f() {
if x {
y
} else {
z
}
}
package P
func f() {
if x {
y
} else
z
}
// Copyright 2011 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
type Bar int
func main() {
var a Bar
println(a)
}
// Copyright 2011 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
type Foo int
func main() {
var a Foo
println(a)
}
// Copyright 2011 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 p
// Slices have nil Len values in the corresponding ast.ArrayType
// node and reflect.NewValue(slice.Len) is an invalid reflect.Value.
// The rewriter must not crash in that case. Was issue 1696.
func f() []bool {}
// Copyright 2011 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 p
// Slices have nil Len values in the corresponding ast.ArrayType
// node and reflect.NewValue(slice.Len) is an invalid reflect.Value.
// The rewriter must not crash in that case. Was issue 1696.
func f() []int {}
// Copyright 2011 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
// Field tags are *ast.BasicLit nodes that are nil when the tag is
// absent. These nil nodes must not be mistaken for expressions,
// the rewriter should not try to dereference them. Was issue 2410.
type Foo struct {
Field int
}
// Copyright 2011 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
// Field tags are *ast.BasicLit nodes that are nil when the tag is
// absent. These nil nodes must not be mistaken for expressions,
// the rewriter should not try to dereference them. Was issue 2410.
type Foo struct {
Field int
}
// Copyright 2012 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.
// Rewriting of parenthesized expressions (x) -> x
// must not drop parentheses if that would lead to
// wrong association of the operands.
// Was issue 1847.
package main
// From example 1 of issue 1847.
func _() {
var t = (&T{1000}).Id()
}
// From example 2 of issue 1847.
func _() {
fmt.Println((*xpp).a)
}
// Some more test cases.
func _() {
_ = (-x).f
_ = (*x).f
_ = (&x).f
_ = (!x).f
_ = -x.f
_ = *x.f
_ = &x.f
_ = !x.f
(-x).f()
(*x).f()
(&x).f()
(!x).f()
_ = -x.f()
_ = *x.f()
_ = &x.f()
_ = !x.f()
_ = (-x).f
_ = (*x).f
_ = (&x).f
_ = (!x).f
_ = -x.f
_ = *x.f
_ = &x.f
_ = !x.f
(-x).f()
(*x).f()
(&x).f()
(!x).f()
_ = -x.f()
_ = *x.f()
_ = &x.f()
_ = !x.f()
_ = -x.f
_ = *x.f
_ = &x.f
_ = !x.f
_ = -x.f
_ = *x.f
_ = &x.f
_ = !x.f
_ = -x.f()
_ = *x.f()
_ = &x.f()
_ = !x.f()
_ = -x.f()
_ = *x.f()
_ = &x.f()
_ = !x.f()
}
// Copyright 2012 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.
// Rewriting of parenthesized expressions (x) -> x
// must not drop parentheses if that would lead to
// wrong association of the operands.
// Was issue 1847.
package main
// From example 1 of issue 1847.
func _() {
var t = (&T{1000}).Id()
}
// From example 2 of issue 1847.
func _() {
fmt.Println((*xpp).a)
}
// Some more test cases.
func _() {
_ = (-x).f
_ = (*x).f
_ = (&x).f
_ = (!x).f
_ = (-x.f)
_ = (*x.f)
_ = (&x.f)
_ = (!x.f)
(-x).f()
(*x).f()
(&x).f()
(!x).f()
_ = (-x.f())
_ = (*x.f())
_ = (&x.f())
_ = (!x.f())
_ = ((-x)).f
_ = ((*x)).f
_ = ((&x)).f
_ = ((!x)).f
_ = ((-x.f))
_ = ((*x.f))
_ = ((&x.f))
_ = ((!x.f))
((-x)).f()
((*x)).f()
((&x)).f()
((!x)).f()
_ = ((-x.f()))
_ = ((*x.f()))
_ = ((&x.f()))
_ = ((!x.f()))
_ = -(x).f
_ = *(x).f
_ = &(x).f
_ = !(x).f
_ = -x.f
_ = *x.f
_ = &x.f
_ = !x.f
_ = -(x).f()
_ = *(x).f()
_ = &(x).f()
_ = !(x).f()
_ = -x.f()
_ = *x.f()
_ = &x.f()
_ = !x.f()
}
// Copyright 2011 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.
// Rewriting of expressions containing nodes with associated comments to
// expressions without those nodes must also eliminate the associated
// comments.
package p
func f(x int) int {
_ = 2 * x // this comment remains in the rewrite
_ = 2 * x
return 2 * x
}
// Copyright 2011 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.
// Rewriting of expressions containing nodes with associated comments to
// expressions without those nodes must also eliminate the associated
// comments.
package p
func f(x int) int {
_ = x + x // this comment remains in the rewrite
_ = x /* this comment must not be in the rewrite */ + x
return x /* this comment must not be in the rewrite */ + x
}
// Copyright 2013 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.
// Rewriting of calls must take the ... (ellipsis)
// attribute for the last argument into account.
package p
func fun(x []int) {}
func g(x []int) {
Fun(x) // -r='fun(x)->Fun(x)' should rewrite this to Fun(x)
fun(x...) // -r='fun(x)->Fun(x)' should not rewrite this
}
// Copyright 2013 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.
// Rewriting of calls must take the ... (ellipsis)
// attribute for the last argument into account.
package p
func fun(x []int) {}
func g(x []int) {
fun(x) // -r='fun(x)->Fun(x)' should rewrite this to Fun(x)
fun(x...) // -r='fun(x)->Fun(x)' should not rewrite this
}
// Copyright 2013 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.
// Rewriting of calls must take the ... (ellipsis)
// attribute for the last argument into account.
package p
func fun(x []int) {}
func g(x []int) {
fun(x) // -r='fun(x...)->Fun(x)' should not rewrite this
Fun(x) // -r='fun(x...)->Fun(x)' should rewrite this to Fun(x)
}
// Copyright 2013 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.
// Rewriting of calls must take the ... (ellipsis)
// attribute for the last argument into account.
package p
func fun(x []int) {}
func g(x []int) {
fun(x) // -r='fun(x...)->Fun(x)' should not rewrite this
fun(x...) // -r='fun(x...)->Fun(x)' should rewrite this to Fun(x)
}
// Copyright 2013 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.
// Check that literal type expression rewrites are accepted.
// Was issue 4406.
package p
type T int
// Copyright 2013 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.
// Check that literal type expression rewrites are accepted.
// Was issue 4406.
package p
type T interface{}
// Test cases for slice expression simplification.
package p
var (
a [10]byte
b [20]float32
s []int
t struct {
s []byte
}
_ = a[0:]
_ = a[1:10]
_ = a[2:]
_ = a[3:(len(a))]
_ = a[len(a) : len(a)-1]
_ = a[0:len(b)]
_ = a[:]
_ = a[:10]
_ = a[:]
_ = a[:(len(a))]
_ = a[:len(a)-1]
_ = a[:len(b)]
_ = s[0:]
_ = s[1:10]
_ = s[2:]
_ = s[3:(len(s))]
_ = s[len(a) : len(s)-1]
_ = s[0:len(b)]
_ = s[:]
_ = s[:10]
_ = s[:]
_ = s[:(len(s))]
_ = s[:len(s)-1]
_ = s[:len(b)]
_ = t.s[0:]
_ = t.s[1:10]
_ = t.s[2:len(t.s)]
_ = t.s[3:(len(t.s))]
_ = t.s[len(a) : len(t.s)-1]
_ = t.s[0:len(b)]
_ = t.s[:]
_ = t.s[:10]
_ = t.s[:len(t.s)]
_ = t.s[:(len(t.s))]
_ = t.s[:len(t.s)-1]
_ = t.s[:len(b)]
)
func _() {
s := s[0:]
_ = s
}
// Test cases for slice expression simplification.
package p
var (
a [10]byte
b [20]float32
s []int
t struct {
s []byte
}
_ = a[0:]
_ = a[1:10]
_ = a[2:len(a)]
_ = a[3:(len(a))]
_ = a[len(a) : len(a)-1]
_ = a[0:len(b)]
_ = a[:]
_ = a[:10]
_ = a[:len(a)]
_ = a[:(len(a))]
_ = a[:len(a)-1]
_ = a[:len(b)]
_ = s[0:]
_ = s[1:10]
_ = s[2:len(s)]
_ = s[3:(len(s))]
_ = s[len(a) : len(s)-1]
_ = s[0:len(b)]
_ = s[:]
_ = s[:10]
_ = s[:len(s)]
_ = s[:(len(s))]
_ = s[:len(s)-1]
_ = s[:len(b)]
_ = t.s[0:]
_ = t.s[1:10]
_ = t.s[2:len(t.s)]
_ = t.s[3:(len(t.s))]
_ = t.s[len(a) : len(t.s)-1]
_ = t.s[0:len(b)]
_ = t.s[:]
_ = t.s[:10]
_ = t.s[:len(t.s)]
_ = t.s[:(len(t.s))]
_ = t.s[:len(t.s)-1]
_ = t.s[:len(b)]
)
func _() {
s := s[0:len(s)]
_ = s
}
// Test cases for slice expression simplification.
// Because of a dot import, these slices must remain untouched.
package p
import . "math"
var (
a [10]byte
b [20]float32
s []int
t struct {
s []byte
}
_ = a[0:]
_ = a[1:10]
_ = a[2:len(a)]
_ = a[3:(len(a))]
_ = a[len(a) : len(a)-1]
_ = a[0:len(b)]
_ = a[:]
_ = a[:10]
_ = a[:len(a)]
_ = a[:(len(a))]
_ = a[:len(a)-1]
_ = a[:len(b)]
_ = s[0:]
_ = s[1:10]
_ = s[2:len(s)]
_ = s[3:(len(s))]
_ = s[len(a) : len(s)-1]
_ = s[0:len(b)]
_ = s[:]
_ = s[:10]
_ = s[:len(s)]
_ = s[:(len(s))]
_ = s[:len(s)-1]
_ = s[:len(b)]
_ = t.s[0:]
_ = t.s[1:10]
_ = t.s[2:len(t.s)]
_ = t.s[3:(len(t.s))]
_ = t.s[len(a) : len(t.s)-1]
_ = t.s[0:len(b)]
_ = t.s[:]
_ = t.s[:10]
_ = t.s[:len(t.s)]
_ = t.s[:(len(t.s))]
_ = t.s[:len(t.s)-1]
_ = t.s[:len(b)]
)
func _() {
s := s[0:len(s)]
_ = s
}
// Test cases for slice expression simplification.
// Because of a dot import, these slices must remain untouched.
package p
import . "math"
var (
a [10]byte
b [20]float32
s []int
t struct {
s []byte
}
_ = a[0:]
_ = a[1:10]
_ = a[2:len(a)]
_ = a[3:(len(a))]
_ = a[len(a) : len(a)-1]
_ = a[0:len(b)]
_ = a[:]
_ = a[:10]
_ = a[:len(a)]
_ = a[:(len(a))]
_ = a[:len(a)-1]
_ = a[:len(b)]
_ = s[0:]
_ = s[1:10]
_ = s[2:len(s)]
_ = s[3:(len(s))]
_ = s[len(a) : len(s)-1]
_ = s[0:len(b)]
_ = s[:]
_ = s[:10]
_ = s[:len(s)]
_ = s[:(len(s))]
_ = s[:len(s)-1]
_ = s[:len(b)]
_ = t.s[0:]
_ = t.s[1:10]
_ = t.s[2:len(t.s)]
_ = t.s[3:(len(t.s))]
_ = t.s[len(a) : len(t.s)-1]
_ = t.s[0:len(b)]
_ = t.s[:]
_ = t.s[:10]
_ = t.s[:len(t.s)]
_ = t.s[:(len(t.s))]
_ = t.s[:len(t.s)-1]
_ = t.s[:len(b)]
)
func _() {
s := s[0:len(s)]
_ = s
}
var x int
func f() {
y := z
/* this is a comment */
// this is a comment too
}
var x int
func f() { y := z
/* this is a comment */
// this is a comment too
}
var x int
func f() {
y := z
/* this is a comment */
// this is a comment too
}
/* note: no newline at end of file */
for i := 0; i < 10; i++ {
s += i
}
\ No newline at end of file
/* note: no newline at end of file */
for i := 0; i < 10; i++ {
s += i
}
\ No newline at end of file
/* note: no newline at end of file */
for i := 0; i < 10; i++ { s += i }
\ No newline at end of file
/* note: no newline at end of file */
for i := 0; i < 10; i++ {
s += i
}
\ No newline at end of file
/*
Parenthesized type switch expressions originally
accepted by gofmt must continue to be rewritten
into the correct unparenthesized form.
Only type-switches that didn't declare a variable
in the type switch type assertion and which
contained only "expression-like" (named) types in their
cases were permitted to have their type assertion parenthesized
by go/parser (due to a weak predicate in the parser). All others
were rejected always, either with a syntax error in the
type switch header or in the case.
See also issue 4470.
*/
package p
func f() {
var x interface{}
switch x.(type) { // should remain the same
}
switch x.(type) { // should become: switch x.(type) {
}
switch x.(type) { // should remain the same
case int:
}
switch x.(type) { // should become: switch x.(type) {
case int:
}
switch x.(type) { // should remain the same
case []int:
}
// Parenthesized (x.(type)) in type switches containing cases
// with unnamed (literal) types were never permitted by gofmt;
// thus there won't be any code in the wild using this style if
// the code was gofmt-ed.
/*
switch (x.(type)) {
case []int:
}
*/
switch t := x.(type) { // should remain the same
default:
_ = t
}
// Parenthesized (x.(type)) in type switches declaring a variable
// were never permitted by gofmt; thus there won't be any code in
// the wild using this style if the code was gofmt-ed.
/*
switch t := (x.(type)) {
default:
_ = t
}
*/
}
/*
Parenthesized type switch expressions originally
accepted by gofmt must continue to be rewritten
into the correct unparenthesized form.
Only type-switches that didn't declare a variable
in the type switch type assertion and which
contained only "expression-like" (named) types in their
cases were permitted to have their type assertion parenthesized
by go/parser (due to a weak predicate in the parser). All others
were rejected always, either with a syntax error in the
type switch header or in the case.
See also issue 4470.
*/
package p
func f() {
var x interface{}
switch x.(type) { // should remain the same
}
switch (x.(type)) { // should become: switch x.(type) {
}
switch x.(type) { // should remain the same
case int:
}
switch (x.(type)) { // should become: switch x.(type) {
case int:
}
switch x.(type) { // should remain the same
case []int:
}
// Parenthesized (x.(type)) in type switches containing cases
// with unnamed (literal) types were never permitted by gofmt;
// thus there won't be any code in the wild using this style if
// the code was gofmt-ed.
/*
switch (x.(type)) {
case []int:
}
*/
switch t := x.(type) { // should remain the same
default:
_ = t
}
// Parenthesized (x.(type)) in type switches declaring a variable
// were never permitted by gofmt; thus there won't be any code in
// the wild using this style if the code was gofmt-ed.
/*
switch t := (x.(type)) {
default:
_ = t
}
*/
}
...@@ -268,6 +268,8 @@ var cgoEnabled = map[string]bool{ ...@@ -268,6 +268,8 @@ var cgoEnabled = map[string]bool{
"linux/386": true, "linux/386": true,
"linux/amd64": true, "linux/amd64": true,
"linux/arm": true, "linux/arm": true,
"linux/ppc64": true,
"linux/ppc64le": true,
"linux/s390": true, "linux/s390": true,
"linux/s390x": true, "linux/s390x": true,
"netbsd/386": true, "netbsd/386": true,
...@@ -1196,8 +1198,15 @@ func init() { ...@@ -1196,8 +1198,15 @@ func init() {
} }
} }
// ToolDir is the directory containing build tools. func getToolDir() string {
var ToolDir = filepath.Join(runtime.GOROOT(), "pkg/tool/"+runtime.GOOS+"_"+runtime.GOARCH) if runtime.Compiler == "gccgo" {
return runtime.GCCGOTOOLDIR
} else {
return filepath.Join(runtime.GOROOT(), "pkg/tool/"+runtime.GOOS+"_"+runtime.GOARCH)
}
}
var ToolDir = getToolDir()
// IsLocalImport reports whether the import path is // IsLocalImport reports whether the import path is
// a local import path, like ".", "..", "./foo", or "../foo". // a local import path, like ".", "..", "./foo", or "../foo".
...@@ -1218,6 +1227,8 @@ func ArchChar(goarch string) (string, error) { ...@@ -1218,6 +1227,8 @@ func ArchChar(goarch string) (string, error) {
return "5", nil return "5", nil
case "arm64": case "arm64":
return "7", nil return "7", nil
case "ppc64", "ppc64le":
return "9", nil
} }
return "", errors.New("unsupported GOARCH " + goarch) return "", errors.New("unsupported GOARCH " + goarch)
} }
...@@ -201,5 +201,8 @@ func Version() string { ...@@ -201,5 +201,8 @@ func Version() string {
const GOOS string = theGoos const GOOS string = theGoos
// GOARCH is the running program's architecture target: // GOARCH is the running program's architecture target:
// 386, amd64, arm or arm64. // 386, amd64, arm, arm64, ppc64, ppc64le.
const GOARCH string = theGoarch const GOARCH string = theGoarch
// GCCGOTOOLDIR is the Tool Dir for the gccgo build
const GCCGOTOOLDIR string = theGccgoToolDir
...@@ -163,6 +163,36 @@ done ...@@ -163,6 +163,36 @@ done
done done
done done
cmdlist="cgo go gofmt"
for c in $cmdlist; do
(cd ${NEWDIR}/src/cmd/$c && find . -name '*.go' -print) | while read f; do
oldfile=${OLDDIR}/src/cmd/$c/$f
newfile=${NEWDIR}/src/cmd/$c/$f
libgofile=go/cmd/$c/$f
merge $f ${oldfile} ${newfile} ${libgofile}
done
(cd ${NEWDIR}/src/cmd/$c && find . -name testdata -print) | while read d; do
oldtd=${OLDDIR}/src/cmd/$c/$d
newtd=${NEWDIR}/src/cmd/$c/$d
libgotd=go/cmd/$c/$d
if ! test -d ${oldtd}; then
continue
fi
(cd ${oldtd} && hg status -A .) | while read f; do
if test "`basename $f`" = ".hgignore"; then
continue
fi
f=`echo $f | sed -e 's/^..//'`
name=$d/$f
oldfile=${oldtd}/$f
newfile=${newtd}/$f
libgofile=${libgotd}/$f
merge ${name} ${oldfile} ${newfile} ${libgofile}
done
done
done
runtime="chan.goc chan.h cpuprof.goc env_posix.c heapdump.c lock_futex.c lfstack.goc lock_sema.c mcache.c mcentral.c mfixalloc.c mgc0.c mgc0.h mheap.c msize.c netpoll.goc netpoll_epoll.c netpoll_kqueue.c netpoll_stub.c panic.c print.c proc.c race.h rdebug.goc runtime.c runtime.h signal_unix.c signal_unix.h malloc.h malloc.goc mprof.goc parfor.c runtime1.goc sema.goc sigqueue.goc string.goc time.goc" runtime="chan.goc chan.h cpuprof.goc env_posix.c heapdump.c lock_futex.c lfstack.goc lock_sema.c mcache.c mcentral.c mfixalloc.c mgc0.c mgc0.h mheap.c msize.c netpoll.goc netpoll_epoll.c netpoll_kqueue.c netpoll_stub.c panic.c print.c proc.c race.h rdebug.goc runtime.c runtime.h signal_unix.c signal_unix.h malloc.h malloc.goc mprof.goc parfor.c runtime1.goc sema.goc sigqueue.goc string.goc time.goc"
for f in $runtime; do for f in $runtime; do
merge_c $f $f merge_c $f $f
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment