From 7d7d64c1ae3c0732b167d2050b101808f078d711 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Tue, 6 Jan 2015 23:26:02 +0000 Subject: [PATCH] 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 --- libgo/Makefile.am | 2 + libgo/Makefile.in | 2 + libgo/go/cmd/cgo/ast.go | 460 +++ libgo/go/cmd/cgo/doc.go | 748 +++++ libgo/go/cmd/cgo/gcc.go | 1728 +++++++++++ libgo/go/cmd/cgo/godefs.go | 294 ++ libgo/go/cmd/cgo/main.go | 360 +++ libgo/go/cmd/cgo/out.go | 1299 +++++++++ libgo/go/cmd/cgo/util.go | 84 + libgo/go/cmd/go/bootstrap.go | 30 + libgo/go/cmd/go/build.go | 2594 +++++++++++++++++ libgo/go/cmd/go/clean.go | 248 ++ libgo/go/cmd/go/context.go | 36 + libgo/go/cmd/go/discovery.go | 83 + libgo/go/cmd/go/doc.go | 990 +++++++ libgo/go/cmd/go/env.go | 112 + libgo/go/cmd/go/fix.go | 30 + libgo/go/cmd/go/fmt.go | 38 + libgo/go/cmd/go/get.go | 429 +++ libgo/go/cmd/go/go11.go | 10 + libgo/go/cmd/go/help.go | 337 +++ libgo/go/cmd/go/http.go | 87 + libgo/go/cmd/go/list.go | 208 ++ libgo/go/cmd/go/main.go | 722 +++++ libgo/go/cmd/go/match_test.go | 88 + libgo/go/cmd/go/mkdoc.sh | 9 + libgo/go/cmd/go/pkg.go | 856 ++++++ libgo/go/cmd/go/pkg_test.go | 73 + libgo/go/cmd/go/run.go | 143 + libgo/go/cmd/go/script | 23 + libgo/go/cmd/go/script.txt | 352 +++ libgo/go/cmd/go/signal.go | 31 + libgo/go/cmd/go/signal_notunix.go | 17 + libgo/go/cmd/go/signal_unix.go | 18 + libgo/go/cmd/go/tag_test.go | 100 + libgo/go/cmd/go/test.bash | 820 ++++++ libgo/go/cmd/go/test.go | 1308 +++++++++ libgo/go/cmd/go/testdata/cgocover/p.go | 19 + libgo/go/cmd/go/testdata/cgocover/p_test.go | 7 + libgo/go/cmd/go/testdata/dep_test.go | 7 + libgo/go/cmd/go/testdata/example1_test.go | 23 + libgo/go/cmd/go/testdata/example2_test.go | 21 + libgo/go/cmd/go/testdata/local/easy.go | 7 + .../cmd/go/testdata/local/easysub/easysub.go | 7 + .../go/cmd/go/testdata/local/easysub/main.go | 9 + libgo/go/cmd/go/testdata/local/hard.go | 7 + libgo/go/cmd/go/testdata/local/sub/sub.go | 12 + .../cmd/go/testdata/local/sub/sub/subsub.go | 7 + .../go/testdata/shadow/root1/src/foo/foo.go | 1 + .../go/testdata/shadow/root1/src/math/math.go | 1 + .../go/testdata/shadow/root2/src/foo/foo.go | 1 + libgo/go/cmd/go/testdata/src/badpkg/x.go | 1 + libgo/go/cmd/go/testdata/src/cgotest/m.go | 5 + .../go/testdata/src/go-cmd-test/helloworld.go | 5 + libgo/go/cmd/go/testdata/src/main_test/m.go | 4 + .../cmd/go/testdata/src/main_test/m_test.go | 10 + libgo/go/cmd/go/testdata/src/notest/hello.go | 6 + libgo/go/cmd/go/testdata/src/syntaxerror/x.go | 1 + .../cmd/go/testdata/src/syntaxerror/x_test.go | 4 + .../go/cmd/go/testdata/src/testcycle/p1/p1.go | 7 + .../go/testdata/src/testcycle/p1/p1_test.go | 6 + .../go/cmd/go/testdata/src/testcycle/p2/p2.go | 7 + .../go/cmd/go/testdata/src/testcycle/p3/p3.go | 5 + .../go/testdata/src/testcycle/p3/p3_test.go | 10 + libgo/go/cmd/go/testdata/src/xtestonly/f.go | 3 + .../cmd/go/testdata/src/xtestonly/f_test.go | 12 + libgo/go/cmd/go/testdata/standalone_test.go | 6 + libgo/go/cmd/go/testdata/testimport/p.go | 3 + libgo/go/cmd/go/testdata/testimport/p1/p1.go | 3 + libgo/go/cmd/go/testdata/testimport/p2/p2.go | 3 + libgo/go/cmd/go/testdata/testimport/p_test.go | 13 + libgo/go/cmd/go/testdata/testimport/x_test.go | 15 + libgo/go/cmd/go/testdata/testonly/p_test.go | 1 + libgo/go/cmd/go/testflag.go | 318 ++ libgo/go/cmd/go/tool.go | 156 + libgo/go/cmd/go/vcs.go | 728 +++++ libgo/go/cmd/go/version.go | 25 + libgo/go/cmd/go/vet.go | 37 + libgo/go/cmd/gofmt/doc.go | 93 + libgo/go/cmd/gofmt/gofmt.go | 344 +++ libgo/go/cmd/gofmt/gofmt_test.go | 134 + libgo/go/cmd/gofmt/long_test.go | 159 + libgo/go/cmd/gofmt/rewrite.go | 306 ++ libgo/go/cmd/gofmt/simplify.go | 121 + libgo/go/cmd/gofmt/testdata/comments.golden | 9 + libgo/go/cmd/gofmt/testdata/comments.input | 9 + libgo/go/cmd/gofmt/testdata/composites.golden | 202 ++ libgo/go/cmd/gofmt/testdata/composites.input | 202 ++ libgo/go/cmd/gofmt/testdata/crlf.golden | 12 + libgo/go/cmd/gofmt/testdata/crlf.input | 12 + libgo/go/cmd/gofmt/testdata/import.golden | 126 + libgo/go/cmd/gofmt/testdata/import.input | 131 + libgo/go/cmd/gofmt/testdata/old.golden | 9 + libgo/go/cmd/gofmt/testdata/old.input | 8 + libgo/go/cmd/gofmt/testdata/rewrite1.golden | 12 + libgo/go/cmd/gofmt/testdata/rewrite1.input | 12 + libgo/go/cmd/gofmt/testdata/rewrite2.golden | 10 + libgo/go/cmd/gofmt/testdata/rewrite2.input | 10 + libgo/go/cmd/gofmt/testdata/rewrite3.golden | 12 + libgo/go/cmd/gofmt/testdata/rewrite3.input | 12 + libgo/go/cmd/gofmt/testdata/rewrite4.golden | 74 + libgo/go/cmd/gofmt/testdata/rewrite4.input | 74 + libgo/go/cmd/gofmt/testdata/rewrite5.golden | 15 + libgo/go/cmd/gofmt/testdata/rewrite5.input | 15 + libgo/go/cmd/gofmt/testdata/rewrite6.golden | 15 + libgo/go/cmd/gofmt/testdata/rewrite6.input | 15 + libgo/go/cmd/gofmt/testdata/rewrite7.golden | 15 + libgo/go/cmd/gofmt/testdata/rewrite7.input | 15 + libgo/go/cmd/gofmt/testdata/rewrite8.golden | 10 + libgo/go/cmd/gofmt/testdata/rewrite8.input | 10 + libgo/go/cmd/gofmt/testdata/slices1.golden | 58 + libgo/go/cmd/gofmt/testdata/slices1.input | 58 + libgo/go/cmd/gofmt/testdata/slices2.golden | 61 + libgo/go/cmd/gofmt/testdata/slices2.input | 61 + libgo/go/cmd/gofmt/testdata/stdin1.golden | 3 + .../go/cmd/gofmt/testdata/stdin1.golden.gofmt | 3 + libgo/go/cmd/gofmt/testdata/stdin1.input | 3 + .../go/cmd/gofmt/testdata/stdin1.input.gofmt | 3 + libgo/go/cmd/gofmt/testdata/stdin2.golden | 11 + .../go/cmd/gofmt/testdata/stdin2.golden.gofmt | 10 + libgo/go/cmd/gofmt/testdata/stdin2.input | 11 + .../go/cmd/gofmt/testdata/stdin2.input.gofmt | 11 + libgo/go/cmd/gofmt/testdata/stdin3.golden | 6 + .../go/cmd/gofmt/testdata/stdin3.golden.gofmt | 7 + libgo/go/cmd/gofmt/testdata/stdin3.input | 4 + .../go/cmd/gofmt/testdata/stdin3.input.gofmt | 7 + libgo/go/cmd/gofmt/testdata/stdin4.golden | 3 + .../go/cmd/gofmt/testdata/stdin4.golden.gofmt | 3 + libgo/go/cmd/gofmt/testdata/stdin4.input | 3 + .../go/cmd/gofmt/testdata/stdin4.input.gofmt | 3 + libgo/go/cmd/gofmt/testdata/typeswitch.golden | 60 + libgo/go/cmd/gofmt/testdata/typeswitch.input | 60 + libgo/go/go/build/build.go | 15 +- libgo/go/runtime/extern.go | 5 +- libgo/merge.sh | 30 + 135 files changed, 18991 insertions(+), 3 deletions(-) create mode 100644 libgo/go/cmd/cgo/ast.go create mode 100644 libgo/go/cmd/cgo/doc.go create mode 100644 libgo/go/cmd/cgo/gcc.go create mode 100644 libgo/go/cmd/cgo/godefs.go create mode 100644 libgo/go/cmd/cgo/main.go create mode 100644 libgo/go/cmd/cgo/out.go create mode 100644 libgo/go/cmd/cgo/util.go create mode 100644 libgo/go/cmd/go/bootstrap.go create mode 100644 libgo/go/cmd/go/build.go create mode 100644 libgo/go/cmd/go/clean.go create mode 100644 libgo/go/cmd/go/context.go create mode 100644 libgo/go/cmd/go/discovery.go create mode 100644 libgo/go/cmd/go/doc.go create mode 100644 libgo/go/cmd/go/env.go create mode 100644 libgo/go/cmd/go/fix.go create mode 100644 libgo/go/cmd/go/fmt.go create mode 100644 libgo/go/cmd/go/get.go create mode 100644 libgo/go/cmd/go/go11.go create mode 100644 libgo/go/cmd/go/help.go create mode 100644 libgo/go/cmd/go/http.go create mode 100644 libgo/go/cmd/go/list.go create mode 100644 libgo/go/cmd/go/main.go create mode 100644 libgo/go/cmd/go/match_test.go create mode 100644 libgo/go/cmd/go/mkdoc.sh create mode 100644 libgo/go/cmd/go/pkg.go create mode 100644 libgo/go/cmd/go/pkg_test.go create mode 100644 libgo/go/cmd/go/run.go create mode 100644 libgo/go/cmd/go/script create mode 100644 libgo/go/cmd/go/script.txt create mode 100644 libgo/go/cmd/go/signal.go create mode 100644 libgo/go/cmd/go/signal_notunix.go create mode 100644 libgo/go/cmd/go/signal_unix.go create mode 100644 libgo/go/cmd/go/tag_test.go create mode 100644 libgo/go/cmd/go/test.bash create mode 100644 libgo/go/cmd/go/test.go create mode 100644 libgo/go/cmd/go/testdata/cgocover/p.go create mode 100644 libgo/go/cmd/go/testdata/cgocover/p_test.go create mode 100644 libgo/go/cmd/go/testdata/dep_test.go create mode 100644 libgo/go/cmd/go/testdata/example1_test.go create mode 100644 libgo/go/cmd/go/testdata/example2_test.go create mode 100644 libgo/go/cmd/go/testdata/local/easy.go create mode 100644 libgo/go/cmd/go/testdata/local/easysub/easysub.go create mode 100644 libgo/go/cmd/go/testdata/local/easysub/main.go create mode 100644 libgo/go/cmd/go/testdata/local/hard.go create mode 100644 libgo/go/cmd/go/testdata/local/sub/sub.go create mode 100644 libgo/go/cmd/go/testdata/local/sub/sub/subsub.go create mode 100644 libgo/go/cmd/go/testdata/shadow/root1/src/foo/foo.go create mode 100644 libgo/go/cmd/go/testdata/shadow/root1/src/math/math.go create mode 100644 libgo/go/cmd/go/testdata/shadow/root2/src/foo/foo.go create mode 100644 libgo/go/cmd/go/testdata/src/badpkg/x.go create mode 100644 libgo/go/cmd/go/testdata/src/cgotest/m.go create mode 100644 libgo/go/cmd/go/testdata/src/go-cmd-test/helloworld.go create mode 100644 libgo/go/cmd/go/testdata/src/main_test/m.go create mode 100644 libgo/go/cmd/go/testdata/src/main_test/m_test.go create mode 100644 libgo/go/cmd/go/testdata/src/notest/hello.go create mode 100644 libgo/go/cmd/go/testdata/src/syntaxerror/x.go create mode 100644 libgo/go/cmd/go/testdata/src/syntaxerror/x_test.go create mode 100644 libgo/go/cmd/go/testdata/src/testcycle/p1/p1.go create mode 100644 libgo/go/cmd/go/testdata/src/testcycle/p1/p1_test.go create mode 100644 libgo/go/cmd/go/testdata/src/testcycle/p2/p2.go create mode 100644 libgo/go/cmd/go/testdata/src/testcycle/p3/p3.go create mode 100644 libgo/go/cmd/go/testdata/src/testcycle/p3/p3_test.go create mode 100644 libgo/go/cmd/go/testdata/src/xtestonly/f.go create mode 100644 libgo/go/cmd/go/testdata/src/xtestonly/f_test.go create mode 100644 libgo/go/cmd/go/testdata/standalone_test.go create mode 100644 libgo/go/cmd/go/testdata/testimport/p.go create mode 100644 libgo/go/cmd/go/testdata/testimport/p1/p1.go create mode 100644 libgo/go/cmd/go/testdata/testimport/p2/p2.go create mode 100644 libgo/go/cmd/go/testdata/testimport/p_test.go create mode 100644 libgo/go/cmd/go/testdata/testimport/x_test.go create mode 100644 libgo/go/cmd/go/testdata/testonly/p_test.go create mode 100644 libgo/go/cmd/go/testflag.go create mode 100644 libgo/go/cmd/go/tool.go create mode 100644 libgo/go/cmd/go/vcs.go create mode 100644 libgo/go/cmd/go/version.go create mode 100644 libgo/go/cmd/go/vet.go create mode 100644 libgo/go/cmd/gofmt/doc.go create mode 100644 libgo/go/cmd/gofmt/gofmt.go create mode 100644 libgo/go/cmd/gofmt/gofmt_test.go create mode 100644 libgo/go/cmd/gofmt/long_test.go create mode 100644 libgo/go/cmd/gofmt/rewrite.go create mode 100644 libgo/go/cmd/gofmt/simplify.go create mode 100644 libgo/go/cmd/gofmt/testdata/comments.golden create mode 100644 libgo/go/cmd/gofmt/testdata/comments.input create mode 100644 libgo/go/cmd/gofmt/testdata/composites.golden create mode 100644 libgo/go/cmd/gofmt/testdata/composites.input create mode 100644 libgo/go/cmd/gofmt/testdata/crlf.golden create mode 100644 libgo/go/cmd/gofmt/testdata/crlf.input create mode 100644 libgo/go/cmd/gofmt/testdata/import.golden create mode 100644 libgo/go/cmd/gofmt/testdata/import.input create mode 100644 libgo/go/cmd/gofmt/testdata/old.golden create mode 100644 libgo/go/cmd/gofmt/testdata/old.input create mode 100644 libgo/go/cmd/gofmt/testdata/rewrite1.golden create mode 100644 libgo/go/cmd/gofmt/testdata/rewrite1.input create mode 100644 libgo/go/cmd/gofmt/testdata/rewrite2.golden create mode 100644 libgo/go/cmd/gofmt/testdata/rewrite2.input create mode 100644 libgo/go/cmd/gofmt/testdata/rewrite3.golden create mode 100644 libgo/go/cmd/gofmt/testdata/rewrite3.input create mode 100644 libgo/go/cmd/gofmt/testdata/rewrite4.golden create mode 100644 libgo/go/cmd/gofmt/testdata/rewrite4.input create mode 100644 libgo/go/cmd/gofmt/testdata/rewrite5.golden create mode 100644 libgo/go/cmd/gofmt/testdata/rewrite5.input create mode 100644 libgo/go/cmd/gofmt/testdata/rewrite6.golden create mode 100644 libgo/go/cmd/gofmt/testdata/rewrite6.input create mode 100644 libgo/go/cmd/gofmt/testdata/rewrite7.golden create mode 100644 libgo/go/cmd/gofmt/testdata/rewrite7.input create mode 100644 libgo/go/cmd/gofmt/testdata/rewrite8.golden create mode 100644 libgo/go/cmd/gofmt/testdata/rewrite8.input create mode 100644 libgo/go/cmd/gofmt/testdata/slices1.golden create mode 100644 libgo/go/cmd/gofmt/testdata/slices1.input create mode 100644 libgo/go/cmd/gofmt/testdata/slices2.golden create mode 100644 libgo/go/cmd/gofmt/testdata/slices2.input create mode 100644 libgo/go/cmd/gofmt/testdata/stdin1.golden create mode 100644 libgo/go/cmd/gofmt/testdata/stdin1.golden.gofmt create mode 100644 libgo/go/cmd/gofmt/testdata/stdin1.input create mode 100644 libgo/go/cmd/gofmt/testdata/stdin1.input.gofmt create mode 100644 libgo/go/cmd/gofmt/testdata/stdin2.golden create mode 100644 libgo/go/cmd/gofmt/testdata/stdin2.golden.gofmt create mode 100644 libgo/go/cmd/gofmt/testdata/stdin2.input create mode 100644 libgo/go/cmd/gofmt/testdata/stdin2.input.gofmt create mode 100644 libgo/go/cmd/gofmt/testdata/stdin3.golden create mode 100644 libgo/go/cmd/gofmt/testdata/stdin3.golden.gofmt create mode 100644 libgo/go/cmd/gofmt/testdata/stdin3.input create mode 100644 libgo/go/cmd/gofmt/testdata/stdin3.input.gofmt create mode 100644 libgo/go/cmd/gofmt/testdata/stdin4.golden create mode 100644 libgo/go/cmd/gofmt/testdata/stdin4.golden.gofmt create mode 100644 libgo/go/cmd/gofmt/testdata/stdin4.input create mode 100644 libgo/go/cmd/gofmt/testdata/stdin4.input.gofmt create mode 100644 libgo/go/cmd/gofmt/testdata/typeswitch.golden create mode 100644 libgo/go/cmd/gofmt/testdata/typeswitch.input diff --git a/libgo/Makefile.am b/libgo/Makefile.am index 380caf53c6b..526b656a309 100644 --- a/libgo/Makefile.am +++ b/libgo/Makefile.am @@ -26,6 +26,7 @@ STAMP = echo timestamp > toolexecdir = $(glibgo_toolexecdir) toolexeclibdir = $(glibgo_toolexeclibdir) toolexeclibgodir = $(nover_glibgo_toolexeclibdir)/go/$(gcc_version)/$(target_alias) +libexecsubdir = $(libexecdir)/gcc/$(target_alias)/$(gcc_version) LIBFFI = @LIBFFI@ LIBFFIINCS = @LIBFFIINCS@ @@ -1007,6 +1008,7 @@ s-version: Makefile echo 'const theVersion = "'`$(GOC) --version | sed 1q`'"' >> version.go.tmp echo 'const theGoarch = "'$(GOARCH)'"' >> 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 $(STAMP) $@ diff --git a/libgo/Makefile.in b/libgo/Makefile.in index d495bf66dd7..2254478aebe 100644 --- a/libgo/Makefile.in +++ b/libgo/Makefile.in @@ -454,6 +454,7 @@ STAMP = echo timestamp > toolexecdir = $(glibgo_toolexecdir) toolexeclibdir = $(glibgo_toolexeclibdir) toolexeclibgodir = $(nover_glibgo_toolexeclibdir)/go/$(gcc_version)/$(target_alias) +libexecsubdir = $(libexecdir)/gcc/$(target_alias)/$(gcc_version) WARN_CFLAGS = $(WARN_FLAGS) $(WERROR) # -I/-D flags to pass when compiling. @@ -4392,6 +4393,7 @@ s-version: Makefile echo 'const theVersion = "'`$(GOC) --version | sed 1q`'"' >> version.go.tmp echo 'const theGoarch = "'$(GOARCH)'"' >> 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 $(STAMP) $@ diff --git a/libgo/go/cmd/cgo/ast.go b/libgo/go/cmd/cgo/ast.go new file mode 100644 index 00000000000..7757efa1bc3 --- /dev/null +++ b/libgo/go/cmd/cgo/ast.go @@ -0,0 +1,460 @@ +// 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) + } + } +} diff --git a/libgo/go/cmd/cgo/doc.go b/libgo/go/cmd/cgo/doc.go new file mode 100644 index 00000000000..69c7ce893c3 --- /dev/null +++ b/libgo/go/cmd/cgo/doc.go @@ -0,0 +1,748 @@ +// 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 + // #include + 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 + 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 + 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 + 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: + + + #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: + + + __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 [ [""]] + + In internal linking mode, allow an unresolved reference to + , assuming it will be resolved by a dynamic library + symbol. The optional specifies the symbol's name and + possibly version in the dynamic library, and the optional "" + names the specific library where the symbol should be found. + + In the , # 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 "" + + In internal linking mode, use "" 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 + + In internal linking mode, put the Go symbol + named into the program's exported symbol table as + , 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 + + In external linking mode, allow unresolved references to + in the go.o object file prepared for the host linker, + under the assumption that 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 + + In external linking mode, put the Go symbol + named into the program's exported symbol table as + , 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 "" + + In external linking mode, invoke the host linker (usually gcc) + with "" 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. + +*/ diff --git a/libgo/go/cmd/cgo/gcc.go b/libgo/go/cmd/cgo/gcc.go new file mode 100644 index 00000000000..f55cfbac447 --- /dev/null +++ b/libgo/go/cmd/cgo/gcc.go @@ -0,0 +1,1728 @@ +// 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 < 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("*") + 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 +} diff --git a/libgo/go/cmd/cgo/godefs.go b/libgo/go/cmd/cgo/godefs.go new file mode 100644 index 00000000000..ce5ac2736c5 --- /dev/null +++ b/libgo/go/cmd/cgo/godefs.go @@ -0,0 +1,294 @@ +// 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() +} diff --git a/libgo/go/cmd/cgo/main.go b/libgo/go/cmd/cgo/main.go new file mode 100644 index 00000000000..ea4b9c2c70d --- /dev/null +++ b/libgo/go/cmd/cgo/main.go @@ -0,0 +1,360 @@ +// 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...) +} diff --git a/libgo/go/cmd/cgo/out.go b/libgo/go/cmd/cgo/out.go new file mode 100644 index 00000000000..76c7247af0d --- /dev/null +++ b/libgo/go/cmd/cgo/out.go @@ -0,0 +1,1299 @@ +// 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 +#include +` + +const builtinProlog = ` +#include /* 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 +#include +#include + +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; +` diff --git a/libgo/go/cmd/cgo/util.go b/libgo/go/cmd/cgo/util.go new file mode 100644 index 00000000000..4e7800d1272 --- /dev/null +++ b/libgo/go/cmd/cgo/util.go @@ -0,0 +1,84 @@ +// 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 +} diff --git a/libgo/go/cmd/go/bootstrap.go b/libgo/go/cmd/go/bootstrap.go new file mode 100644 index 00000000000..dc7ed5f4c06 --- /dev/null +++ b/libgo/go/cmd/go/bootstrap.go @@ -0,0 +1,30 @@ +// 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") +} diff --git a/libgo/go/cmd/go/build.go b/libgo/go/cmd/go/build.go new file mode 100644 index 00000000000..c9957930a12 --- /dev/null +++ b/libgo/go/cmd/go/build.go @@ -0,0 +1,2594 @@ +// 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 "" +} + +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" + } +} diff --git a/libgo/go/cmd/go/clean.go b/libgo/go/cmd/go/clean.go new file mode 100644 index 00000000000..16054a5b5bc --- /dev/null +++ b/libgo/go/cmd/go/clean.go @@ -0,0 +1,248 @@ +// 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) +} diff --git a/libgo/go/cmd/go/context.go b/libgo/go/cmd/go/context.go new file mode 100644 index 00000000000..68e518259f4 --- /dev/null +++ b/libgo/go/cmd/go/context.go @@ -0,0 +1,36 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import ( + "go/build" +) + +type Context struct { + GOARCH string `json:",omitempty"` // target architecture + GOOS string `json:",omitempty"` // target operating system + GOROOT string `json:",omitempty"` // Go root + GOPATH string `json:",omitempty"` // Go path + CgoEnabled bool `json:",omitempty"` // whether cgo can be used + UseAllFiles bool `json:",omitempty"` // use files regardless of +build lines, file names + Compiler string `json:",omitempty"` // compiler to assume when computing target paths + BuildTags []string `json:",omitempty"` // build constraints to match in +build lines + ReleaseTags []string `json:",omitempty"` // releases the current release is compatible with + InstallSuffix string `json:",omitempty"` // suffix to use in the name of the install dir +} + +func newContext(c *build.Context) *Context { + return &Context{ + GOARCH: c.GOARCH, + GOOS: c.GOOS, + GOROOT: c.GOROOT, + CgoEnabled: c.CgoEnabled, + UseAllFiles: c.UseAllFiles, + Compiler: c.Compiler, + BuildTags: c.BuildTags, + ReleaseTags: c.ReleaseTags, + InstallSuffix: c.InstallSuffix, + } +} diff --git a/libgo/go/cmd/go/discovery.go b/libgo/go/cmd/go/discovery.go new file mode 100644 index 00000000000..b9f42799546 --- /dev/null +++ b/libgo/go/cmd/go/discovery.go @@ -0,0 +1,83 @@ +// 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 section or the beginning of the . +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 "" +} diff --git a/libgo/go/cmd/go/doc.go b/libgo/go/cmd/go/doc.go new file mode 100644 index 00000000000..9840804ce74 --- /dev/null +++ b/libgo/go/cmd/go/doc.go @@ -0,0 +1,990 @@ +// 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 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 tag in the document's HTML +. + +The meta tag has the form: + + + +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 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 + + + +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 diff --git a/libgo/go/cmd/go/env.go b/libgo/go/cmd/go/env.go new file mode 100644 index 00000000000..26d37df4f9b --- /dev/null +++ b/libgo/go/cmd/go/env.go @@ -0,0 +1,112 @@ +// 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) + } + } + } +} diff --git a/libgo/go/cmd/go/fix.go b/libgo/go/cmd/go/fix.go new file mode 100644 index 00000000000..8736cce3e2a --- /dev/null +++ b/libgo/go/cmd/go/fix.go @@ -0,0 +1,30 @@ +// 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))) + } +} diff --git a/libgo/go/cmd/go/fmt.go b/libgo/go/cmd/go/fmt.go new file mode 100644 index 00000000000..65dc3ca5990 --- /dev/null +++ b/libgo/go/cmd/go/fmt.go @@ -0,0 +1,38 @@ +// 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))) + } +} diff --git a/libgo/go/cmd/go/get.go b/libgo/go/cmd/go/get.go new file mode 100644 index 00000000000..e708fcf779f --- /dev/null +++ b/libgo/go/cmd/go/get.go @@ -0,0 +1,429 @@ +// 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 = "" // 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 +} diff --git a/libgo/go/cmd/go/go11.go b/libgo/go/cmd/go/go11.go new file mode 100644 index 00000000000..8a434dfed1c --- /dev/null +++ b/libgo/go/cmd/go/go11.go @@ -0,0 +1,10 @@ +// 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 diff --git a/libgo/go/cmd/go/help.go b/libgo/go/cmd/go/help.go new file mode 100644 index 00000000000..40da7e1f5ee --- /dev/null +++ b/libgo/go/cmd/go/help.go @@ -0,0 +1,337 @@ +// 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 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 tag in the document's HTML +. + +The meta tag has the form: + + + +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 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 + + + +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. + `, +} diff --git a/libgo/go/cmd/go/http.go b/libgo/go/cmd/go/http.go new file mode 100644 index 00000000000..107b820f28c --- /dev/null +++ b/libgo/go/cmd/go/http.go @@ -0,0 +1,87 @@ +// 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 +} diff --git a/libgo/go/cmd/go/list.go b/libgo/go/cmd/go/list.go new file mode 100644 index 00000000000..0ead4350238 --- /dev/null +++ b/libgo/go/cmd/go/list.go @@ -0,0 +1,208 @@ +// 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' +} diff --git a/libgo/go/cmd/go/main.go b/libgo/go/cmd/go/main.go new file mode 100644 index 00000000000..5b1194aaa34 --- /dev/null +++ b/libgo/go/cmd/go/main.go @@ -0,0 +1,722 @@ +// 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 ' 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 "", "" +} diff --git a/libgo/go/cmd/go/match_test.go b/libgo/go/cmd/go/match_test.go new file mode 100644 index 00000000000..38b9b115e7c --- /dev/null +++ b/libgo/go/cmd/go/match_test.go @@ -0,0 +1,88 @@ +// 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) + } + } +} diff --git a/libgo/go/cmd/go/mkdoc.sh b/libgo/go/cmd/go/mkdoc.sh new file mode 100644 index 00000000000..12fd7ba3e7f --- /dev/null +++ b/libgo/go/cmd/go/mkdoc.sh @@ -0,0 +1,9 @@ +#!/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 + diff --git a/libgo/go/cmd/go/pkg.go b/libgo/go/cmd/go/pkg.go new file mode 100644 index 00000000000..b700ad5c9a2 --- /dev/null +++ b/libgo/go/cmd/go/pkg.go @@ -0,0 +1,856 @@ +// 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 +} diff --git a/libgo/go/cmd/go/pkg_test.go b/libgo/go/cmd/go/pkg_test.go new file mode 100644 index 00000000000..06b9f0ac6eb --- /dev/null +++ b/libgo/go/cmd/go/pkg_test.go @@ -0,0 +1,73 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import ( + "reflect" + "strings" + "testing" +) + +var foldDupTests = []struct { + list []string + f1, f2 string +}{ + {stringList("math/rand", "math/big"), "", ""}, + {stringList("math", "strings"), "", ""}, + {stringList("strings"), "", ""}, + {stringList("strings", "strings"), "strings", "strings"}, + {stringList("Rand", "rand", "math", "math/rand", "math/Rand"), "Rand", "rand"}, +} + +func TestFoldDup(t *testing.T) { + for _, tt := range foldDupTests { + f1, f2 := foldDup(tt.list) + if f1 != tt.f1 || f2 != tt.f2 { + t.Errorf("foldDup(%q) = %q, %q, want %q, %q", tt.list, f1, f2, tt.f1, tt.f2) + } + } +} + +var parseMetaGoImportsTests = []struct { + in string + out []metaImport +}{ + { + ``, + []metaImport{{"foo/bar", "git", "https://github.com/rsc/foo/bar"}}, + }, + { + ` + `, + []metaImport{ + {"foo/bar", "git", "https://github.com/rsc/foo/bar"}, + {"baz/quux", "git", "http://github.com/rsc/baz/quux"}, + }, + }, + { + ` + + `, + []metaImport{{"foo/bar", "git", "https://github.com/rsc/foo/bar"}}, + }, + { + ` + `, + []metaImport{{"foo/bar", "git", "https://github.com/rsc/foo/bar"}}, + }, +} + +func TestParseMetaGoImports(t *testing.T) { + for i, tt := range parseMetaGoImportsTests { + out, err := parseMetaGoImports(strings.NewReader(tt.in)) + if err != nil { + t.Errorf("test#%d: %v", i, err) + continue + } + if !reflect.DeepEqual(out, tt.out) { + t.Errorf("test#%d:\n\thave %q\n\twant %q", i, out, tt.out) + } + } +} diff --git a/libgo/go/cmd/go/run.go b/libgo/go/cmd/go/run.go new file mode 100644 index 00000000000..ef8aa95a351 --- /dev/null +++ b/libgo/go/cmd/go/run.go @@ -0,0 +1,143 @@ +// 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) + } +} diff --git a/libgo/go/cmd/go/script b/libgo/go/cmd/go/script new file mode 100644 index 00000000000..340a7e824ca --- /dev/null +++ b/libgo/go/cmd/go/script @@ -0,0 +1,23 @@ +#!/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 diff --git a/libgo/go/cmd/go/script.txt b/libgo/go/cmd/go/script.txt new file mode 100644 index 00000000000..a672146584e --- /dev/null +++ b/libgo/go/cmd/go/script.txt @@ -0,0 +1,352 @@ +--- 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. +--- + diff --git a/libgo/go/cmd/go/signal.go b/libgo/go/cmd/go/signal.go new file mode 100644 index 00000000000..e8ba0d36556 --- /dev/null +++ b/libgo/go/cmd/go/signal.go @@ -0,0 +1,31 @@ +// 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) +} diff --git a/libgo/go/cmd/go/signal_notunix.go b/libgo/go/cmd/go/signal_notunix.go new file mode 100644 index 00000000000..29aa9d8c209 --- /dev/null +++ b/libgo/go/cmd/go/signal_notunix.go @@ -0,0 +1,17 @@ +// 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 diff --git a/libgo/go/cmd/go/signal_unix.go b/libgo/go/cmd/go/signal_unix.go new file mode 100644 index 00000000000..e86cd465231 --- /dev/null +++ b/libgo/go/cmd/go/signal_unix.go @@ -0,0 +1,18 @@ +// 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 diff --git a/libgo/go/cmd/go/tag_test.go b/libgo/go/cmd/go/tag_test.go new file mode 100644 index 00000000000..ffe218c7b6d --- /dev/null +++ b/libgo/go/cmd/go/tag_test.go @@ -0,0 +1,100 @@ +// 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) + } + } +} diff --git a/libgo/go/cmd/go/test.bash b/libgo/go/cmd/go/test.bash new file mode 100644 index 00000000000..0060ce2185f --- /dev/null +++ b/libgo/go/cmd/go/test.bash @@ -0,0 +1,820 @@ +#!/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<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 <$d/src/example/b/main.go <$d/src/example/a/a.go <$d/src/example/a/pkg/pkg.go <$d/src/example/a/Pkg/pkg.go <$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 <$d/src/example/b/FILE.go <$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 +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 diff --git a/libgo/go/cmd/go/test.go b/libgo/go/cmd/go/test.go new file mode 100644 index 00000000000..f7ae9c01fba --- /dev/null +++ b/libgo/go/cmd/go/test.go @@ -0,0 +1,1308 @@ +// 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, "") + 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) +} + +`)) diff --git a/libgo/go/cmd/go/testdata/cgocover/p.go b/libgo/go/cmd/go/testdata/cgocover/p.go new file mode 100644 index 00000000000..a6a3891cd4e --- /dev/null +++ b/libgo/go/cmd/go/testdata/cgocover/p.go @@ -0,0 +1,19 @@ +package p + +/* +void +f(void) +{ +} +*/ +import "C" + +var b bool + +func F() { + if b { + for { + } + } + C.f() +} diff --git a/libgo/go/cmd/go/testdata/cgocover/p_test.go b/libgo/go/cmd/go/testdata/cgocover/p_test.go new file mode 100644 index 00000000000..a8f057e3587 --- /dev/null +++ b/libgo/go/cmd/go/testdata/cgocover/p_test.go @@ -0,0 +1,7 @@ +package p + +import "testing" + +func TestF(t *testing.T) { + F() +} diff --git a/libgo/go/cmd/go/testdata/dep_test.go b/libgo/go/cmd/go/testdata/dep_test.go new file mode 100644 index 00000000000..0c53ac4f963 --- /dev/null +++ b/libgo/go/cmd/go/testdata/dep_test.go @@ -0,0 +1,7 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package deps + +import _ "testing" diff --git a/libgo/go/cmd/go/testdata/example1_test.go b/libgo/go/cmd/go/testdata/example1_test.go new file mode 100644 index 00000000000..ec7092e972b --- /dev/null +++ b/libgo/go/cmd/go/testdata/example1_test.go @@ -0,0 +1,23 @@ +// 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 +} diff --git a/libgo/go/cmd/go/testdata/example2_test.go b/libgo/go/cmd/go/testdata/example2_test.go new file mode 100644 index 00000000000..1e0e80b80f0 --- /dev/null +++ b/libgo/go/cmd/go/testdata/example2_test.go @@ -0,0 +1,21 @@ +// 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 +} diff --git a/libgo/go/cmd/go/testdata/local/easy.go b/libgo/go/cmd/go/testdata/local/easy.go new file mode 100644 index 00000000000..4eeb517da15 --- /dev/null +++ b/libgo/go/cmd/go/testdata/local/easy.go @@ -0,0 +1,7 @@ +package main + +import "./easysub" + +func main() { + easysub.Hello() +} diff --git a/libgo/go/cmd/go/testdata/local/easysub/easysub.go b/libgo/go/cmd/go/testdata/local/easysub/easysub.go new file mode 100644 index 00000000000..07040daee57 --- /dev/null +++ b/libgo/go/cmd/go/testdata/local/easysub/easysub.go @@ -0,0 +1,7 @@ +package easysub + +import "fmt" + +func Hello() { + fmt.Println("easysub.Hello") +} diff --git a/libgo/go/cmd/go/testdata/local/easysub/main.go b/libgo/go/cmd/go/testdata/local/easysub/main.go new file mode 100644 index 00000000000..6c30b52362e --- /dev/null +++ b/libgo/go/cmd/go/testdata/local/easysub/main.go @@ -0,0 +1,9 @@ +// +build ignore + +package main + +import "." + +func main() { + easysub.Hello() +} diff --git a/libgo/go/cmd/go/testdata/local/hard.go b/libgo/go/cmd/go/testdata/local/hard.go new file mode 100644 index 00000000000..2ffac3fd73b --- /dev/null +++ b/libgo/go/cmd/go/testdata/local/hard.go @@ -0,0 +1,7 @@ +package main + +import "./sub" + +func main() { + sub.Hello() +} diff --git a/libgo/go/cmd/go/testdata/local/sub/sub.go b/libgo/go/cmd/go/testdata/local/sub/sub.go new file mode 100644 index 00000000000..d5dbf6d5fa5 --- /dev/null +++ b/libgo/go/cmd/go/testdata/local/sub/sub.go @@ -0,0 +1,12 @@ +package sub + +import ( + "fmt" + + subsub "./sub" +) + +func Hello() { + fmt.Println("sub.Hello") + subsub.Hello() +} diff --git a/libgo/go/cmd/go/testdata/local/sub/sub/subsub.go b/libgo/go/cmd/go/testdata/local/sub/sub/subsub.go new file mode 100644 index 00000000000..4cc72233e13 --- /dev/null +++ b/libgo/go/cmd/go/testdata/local/sub/sub/subsub.go @@ -0,0 +1,7 @@ +package subsub + +import "fmt" + +func Hello() { + fmt.Println("subsub.Hello") +} diff --git a/libgo/go/cmd/go/testdata/shadow/root1/src/foo/foo.go b/libgo/go/cmd/go/testdata/shadow/root1/src/foo/foo.go new file mode 100644 index 00000000000..f52652b1ba7 --- /dev/null +++ b/libgo/go/cmd/go/testdata/shadow/root1/src/foo/foo.go @@ -0,0 +1 @@ +package foo diff --git a/libgo/go/cmd/go/testdata/shadow/root1/src/math/math.go b/libgo/go/cmd/go/testdata/shadow/root1/src/math/math.go new file mode 100644 index 00000000000..c91c24e967c --- /dev/null +++ b/libgo/go/cmd/go/testdata/shadow/root1/src/math/math.go @@ -0,0 +1 @@ +package math diff --git a/libgo/go/cmd/go/testdata/shadow/root2/src/foo/foo.go b/libgo/go/cmd/go/testdata/shadow/root2/src/foo/foo.go new file mode 100644 index 00000000000..f52652b1ba7 --- /dev/null +++ b/libgo/go/cmd/go/testdata/shadow/root2/src/foo/foo.go @@ -0,0 +1 @@ +package foo diff --git a/libgo/go/cmd/go/testdata/src/badpkg/x.go b/libgo/go/cmd/go/testdata/src/badpkg/x.go new file mode 100644 index 00000000000..dda35e8ed3d --- /dev/null +++ b/libgo/go/cmd/go/testdata/src/badpkg/x.go @@ -0,0 +1 @@ +pkg badpkg diff --git a/libgo/go/cmd/go/testdata/src/cgotest/m.go b/libgo/go/cmd/go/testdata/src/cgotest/m.go new file mode 100644 index 00000000000..4d68307cf0d --- /dev/null +++ b/libgo/go/cmd/go/testdata/src/cgotest/m.go @@ -0,0 +1,5 @@ +package cgotest + +import "C" + +var _ C.int diff --git a/libgo/go/cmd/go/testdata/src/go-cmd-test/helloworld.go b/libgo/go/cmd/go/testdata/src/go-cmd-test/helloworld.go new file mode 100644 index 00000000000..002a5c740c7 --- /dev/null +++ b/libgo/go/cmd/go/testdata/src/go-cmd-test/helloworld.go @@ -0,0 +1,5 @@ +package main + +func main() { + println("hello world") +} diff --git a/libgo/go/cmd/go/testdata/src/main_test/m.go b/libgo/go/cmd/go/testdata/src/main_test/m.go new file mode 100644 index 00000000000..c682f030b4e --- /dev/null +++ b/libgo/go/cmd/go/testdata/src/main_test/m.go @@ -0,0 +1,4 @@ +package main + +func F() {} +func main() {} diff --git a/libgo/go/cmd/go/testdata/src/main_test/m_test.go b/libgo/go/cmd/go/testdata/src/main_test/m_test.go new file mode 100644 index 00000000000..f865b7734f0 --- /dev/null +++ b/libgo/go/cmd/go/testdata/src/main_test/m_test.go @@ -0,0 +1,10 @@ +package main_test + +import ( + . "main_test" + "testing" +) + +func Test1(t *testing.T) { + F() +} diff --git a/libgo/go/cmd/go/testdata/src/notest/hello.go b/libgo/go/cmd/go/testdata/src/notest/hello.go new file mode 100644 index 00000000000..7c42c32fb0a --- /dev/null +++ b/libgo/go/cmd/go/testdata/src/notest/hello.go @@ -0,0 +1,6 @@ +package notest + +func hello() { + println("hello world") +} +Hello world diff --git a/libgo/go/cmd/go/testdata/src/syntaxerror/x.go b/libgo/go/cmd/go/testdata/src/syntaxerror/x.go new file mode 100644 index 00000000000..c89cd18d0fe --- /dev/null +++ b/libgo/go/cmd/go/testdata/src/syntaxerror/x.go @@ -0,0 +1 @@ +package p diff --git a/libgo/go/cmd/go/testdata/src/syntaxerror/x_test.go b/libgo/go/cmd/go/testdata/src/syntaxerror/x_test.go new file mode 100644 index 00000000000..2460743e501 --- /dev/null +++ b/libgo/go/cmd/go/testdata/src/syntaxerror/x_test.go @@ -0,0 +1,4 @@ +package p + +func f() (x.y, z int) { +} diff --git a/libgo/go/cmd/go/testdata/src/testcycle/p1/p1.go b/libgo/go/cmd/go/testdata/src/testcycle/p1/p1.go new file mode 100644 index 00000000000..65ab76d4e1e --- /dev/null +++ b/libgo/go/cmd/go/testdata/src/testcycle/p1/p1.go @@ -0,0 +1,7 @@ +package p1 + +import _ "testcycle/p2" + +func init() { + println("p1 init") +} diff --git a/libgo/go/cmd/go/testdata/src/testcycle/p1/p1_test.go b/libgo/go/cmd/go/testdata/src/testcycle/p1/p1_test.go new file mode 100644 index 00000000000..75abb13e6d0 --- /dev/null +++ b/libgo/go/cmd/go/testdata/src/testcycle/p1/p1_test.go @@ -0,0 +1,6 @@ +package p1 + +import "testing" + +func Test(t *testing.T) { +} diff --git a/libgo/go/cmd/go/testdata/src/testcycle/p2/p2.go b/libgo/go/cmd/go/testdata/src/testcycle/p2/p2.go new file mode 100644 index 00000000000..7e26cdf19c9 --- /dev/null +++ b/libgo/go/cmd/go/testdata/src/testcycle/p2/p2.go @@ -0,0 +1,7 @@ +package p2 + +import _ "testcycle/p3" + +func init() { + println("p2 init") +} diff --git a/libgo/go/cmd/go/testdata/src/testcycle/p3/p3.go b/libgo/go/cmd/go/testdata/src/testcycle/p3/p3.go new file mode 100644 index 00000000000..bb0a2f4f656 --- /dev/null +++ b/libgo/go/cmd/go/testdata/src/testcycle/p3/p3.go @@ -0,0 +1,5 @@ +package p3 + +func init() { + println("p3 init") +} diff --git a/libgo/go/cmd/go/testdata/src/testcycle/p3/p3_test.go b/libgo/go/cmd/go/testdata/src/testcycle/p3/p3_test.go new file mode 100644 index 00000000000..9b4b0757f82 --- /dev/null +++ b/libgo/go/cmd/go/testdata/src/testcycle/p3/p3_test.go @@ -0,0 +1,10 @@ +package p3 + +import ( + "testing" + + _ "testcycle/p1" +) + +func Test(t *testing.T) { +} diff --git a/libgo/go/cmd/go/testdata/src/xtestonly/f.go b/libgo/go/cmd/go/testdata/src/xtestonly/f.go new file mode 100644 index 00000000000..dac039e1ad0 --- /dev/null +++ b/libgo/go/cmd/go/testdata/src/xtestonly/f.go @@ -0,0 +1,3 @@ +package xtestonly + +func F() int { return 42 } diff --git a/libgo/go/cmd/go/testdata/src/xtestonly/f_test.go b/libgo/go/cmd/go/testdata/src/xtestonly/f_test.go new file mode 100644 index 00000000000..01f6e83730c --- /dev/null +++ b/libgo/go/cmd/go/testdata/src/xtestonly/f_test.go @@ -0,0 +1,12 @@ +package xtestonly_test + +import ( + "testing" + "xtestonly" +) + +func TestF(t *testing.T) { + if x := xtestonly.F(); x != 42 { + t.Errorf("f.F() = %d, want 42", x) + } +} diff --git a/libgo/go/cmd/go/testdata/standalone_test.go b/libgo/go/cmd/go/testdata/standalone_test.go new file mode 100644 index 00000000000..59cf918b9bc --- /dev/null +++ b/libgo/go/cmd/go/testdata/standalone_test.go @@ -0,0 +1,6 @@ +package standalone_test + +import "testing" + +func Test(t *testing.T) { +} diff --git a/libgo/go/cmd/go/testdata/testimport/p.go b/libgo/go/cmd/go/testdata/testimport/p.go new file mode 100644 index 00000000000..f94d2cd0e66 --- /dev/null +++ b/libgo/go/cmd/go/testdata/testimport/p.go @@ -0,0 +1,3 @@ +package p + +func F() int { return 1 } diff --git a/libgo/go/cmd/go/testdata/testimport/p1/p1.go b/libgo/go/cmd/go/testdata/testimport/p1/p1.go new file mode 100644 index 00000000000..fd315272ea2 --- /dev/null +++ b/libgo/go/cmd/go/testdata/testimport/p1/p1.go @@ -0,0 +1,3 @@ +package p1 + +func F() int { return 1 } diff --git a/libgo/go/cmd/go/testdata/testimport/p2/p2.go b/libgo/go/cmd/go/testdata/testimport/p2/p2.go new file mode 100644 index 00000000000..d4888865ddb --- /dev/null +++ b/libgo/go/cmd/go/testdata/testimport/p2/p2.go @@ -0,0 +1,3 @@ +package p2 + +func F() int { return 1 } diff --git a/libgo/go/cmd/go/testdata/testimport/p_test.go b/libgo/go/cmd/go/testdata/testimport/p_test.go new file mode 100644 index 00000000000..a3fb4a9e278 --- /dev/null +++ b/libgo/go/cmd/go/testdata/testimport/p_test.go @@ -0,0 +1,13 @@ +package p + +import ( + "./p1" + + "testing" +) + +func TestF(t *testing.T) { + if F() != p1.F() { + t.Fatal(F()) + } +} diff --git a/libgo/go/cmd/go/testdata/testimport/x_test.go b/libgo/go/cmd/go/testdata/testimport/x_test.go new file mode 100644 index 00000000000..b253e3fd2dd --- /dev/null +++ b/libgo/go/cmd/go/testdata/testimport/x_test.go @@ -0,0 +1,15 @@ +package p_test + +import ( + . "../testimport" + + "./p2" + + "testing" +) + +func TestF1(t *testing.T) { + if F() != p2.F() { + t.Fatal(F()) + } +} diff --git a/libgo/go/cmd/go/testdata/testonly/p_test.go b/libgo/go/cmd/go/testdata/testonly/p_test.go new file mode 100644 index 00000000000..c89cd18d0fe --- /dev/null +++ b/libgo/go/cmd/go/testdata/testonly/p_test.go @@ -0,0 +1 @@ +package p diff --git a/libgo/go/cmd/go/testflag.go b/libgo/go/cmd/go/testflag.go new file mode 100644 index 00000000000..73f311e5f69 --- /dev/null +++ b/libgo/go/cmd/go/testflag.go @@ -0,0 +1,318 @@ +// 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) +} diff --git a/libgo/go/cmd/go/tool.go b/libgo/go/cmd/go/tool.go new file mode 100644 index 00000000000..6d26f7a4b4a --- /dev/null +++ b/libgo/go/cmd/go/tool.go @@ -0,0 +1,156 @@ +// 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) + } +} diff --git a/libgo/go/cmd/go/vcs.go b/libgo/go/cmd/go/vcs.go new file mode 100644 index 00000000000..8f0bae0b755 --- /dev/null +++ b/libgo/go/cmd/go/vcs.go @@ -0,0 +1,728 @@ +// 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 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: `^(?Pcode\.google\.com/p/(?P[a-z0-9\-]+)(\.(?P[a-z0-9\-]+))?)(/[A-Za-z0-9_.\-]+)*$`, + repo: "https://{root}", + check: googleCodeVCS, + }, + + // Google Code - old syntax + { + re: `^(?P[a-z0-9_\-.]+)\.googlecode\.com/(git|hg|svn)(?P/.*)?$`, + check: oldGoogleCode, + }, + + // Github + { + prefix: "github.com/", + re: `^(?Pgithub\.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: `^(?Pbitbucket\.org/(?P[A-Za-z0-9_.\-]+/[A-Za-z0-9_.\-]+))(/[A-Za-z0-9_.\-]+)*$`, + repo: "https://{root}", + check: bitbucketVCS, + }, + + // Launchpad + { + prefix: "launchpad.net/", + re: `^(?Plaunchpad\.net/((?P[A-Za-z0-9_.\-]+)(?P/[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(?P([a-z0-9.\-]+\.)+[a-z0-9.\-]+(:[0-9]+)?/[A-Za-z0-9_.\-/]*?)\.(?Pbzr|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 +} diff --git a/libgo/go/cmd/go/version.go b/libgo/go/cmd/go/version.go new file mode 100644 index 00000000000..a41f4a73615 --- /dev/null +++ b/libgo/go/cmd/go/version.go @@ -0,0 +1,25 @@ +// 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) +} diff --git a/libgo/go/cmd/go/vet.go b/libgo/go/cmd/go/vet.go new file mode 100644 index 00000000000..ffb4318373b --- /dev/null +++ b/libgo/go/cmd/go/vet.go @@ -0,0 +1,37 @@ +// 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))) + } +} diff --git a/libgo/go/cmd/gofmt/doc.go b/libgo/go/cmd/gofmt/doc.go new file mode 100644 index 00000000000..8f73ef5b9dd --- /dev/null +++ b/libgo/go/cmd/gofmt/doc.go @@ -0,0 +1,93 @@ +// 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. diff --git a/libgo/go/cmd/gofmt/gofmt.go b/libgo/go/cmd/gofmt/gofmt.go new file mode 100644 index 00000000000..576cae5228e --- /dev/null +++ b/libgo/go/cmd/gofmt/gofmt.go @@ -0,0 +1,344 @@ +// 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("", 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() +} diff --git a/libgo/go/cmd/gofmt/gofmt_test.go b/libgo/go/cmd/gofmt/gofmt_test.go new file mode 100644 index 00000000000..b9335b8f3db --- /dev/null +++ b/libgo/go/cmd/gofmt/gofmt_test.go @@ -0,0 +1,134 @@ +// 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) + } +} diff --git a/libgo/go/cmd/gofmt/long_test.go b/libgo/go/cmd/gofmt/long_test.go new file mode 100644 index 00000000000..108278b3369 --- /dev/null +++ b/libgo/go/cmd/gofmt/long_test.go @@ -0,0 +1,159 @@ +// 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) + } +} diff --git a/libgo/go/cmd/gofmt/rewrite.go b/libgo/go/cmd/gofmt/rewrite.go new file mode 100644 index 00000000000..fb6c6fc811a --- /dev/null +++ b/libgo/go/cmd/gofmt/rewrite.go @@ -0,0 +1,306 @@ +// 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 +} diff --git a/libgo/go/cmd/gofmt/simplify.go b/libgo/go/cmd/gofmt/simplify.go new file mode 100644 index 00000000000..45d000d675e --- /dev/null +++ b/libgo/go/cmd/gofmt/simplify.go @@ -0,0 +1,121 @@ +// 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) +} diff --git a/libgo/go/cmd/gofmt/testdata/comments.golden b/libgo/go/cmd/gofmt/testdata/comments.golden new file mode 100644 index 00000000000..ad6bcafafa2 --- /dev/null +++ b/libgo/go/cmd/gofmt/testdata/comments.golden @@ -0,0 +1,9 @@ +package main + +func main() {} + +// comment here + +func f() {} + +//line foo.go:1 diff --git a/libgo/go/cmd/gofmt/testdata/comments.input b/libgo/go/cmd/gofmt/testdata/comments.input new file mode 100644 index 00000000000..ad6bcafafa2 --- /dev/null +++ b/libgo/go/cmd/gofmt/testdata/comments.input @@ -0,0 +1,9 @@ +package main + +func main() {} + +// comment here + +func f() {} + +//line foo.go:1 diff --git a/libgo/go/cmd/gofmt/testdata/composites.golden b/libgo/go/cmd/gofmt/testdata/composites.golden new file mode 100644 index 00000000000..b2825e732aa --- /dev/null +++ b/libgo/go/cmd/gofmt/testdata/composites.golden @@ -0,0 +1,202 @@ +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}, +} diff --git a/libgo/go/cmd/gofmt/testdata/composites.input b/libgo/go/cmd/gofmt/testdata/composites.input new file mode 100644 index 00000000000..7210dafc96c --- /dev/null +++ b/libgo/go/cmd/gofmt/testdata/composites.input @@ -0,0 +1,202 @@ +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}, +} diff --git a/libgo/go/cmd/gofmt/testdata/crlf.golden b/libgo/go/cmd/gofmt/testdata/crlf.golden new file mode 100644 index 00000000000..57679f770fe --- /dev/null +++ b/libgo/go/cmd/gofmt/testdata/crlf.golden @@ -0,0 +1,12 @@ +/* + 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() +} diff --git a/libgo/go/cmd/gofmt/testdata/crlf.input b/libgo/go/cmd/gofmt/testdata/crlf.input new file mode 100644 index 00000000000..61a1aa0b4ee --- /dev/null +++ b/libgo/go/cmd/gofmt/testdata/crlf.input @@ -0,0 +1,12 @@ +/* + 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() +} diff --git a/libgo/go/cmd/gofmt/testdata/import.golden b/libgo/go/cmd/gofmt/testdata/import.golden new file mode 100644 index 00000000000..51d7be79dfa --- /dev/null +++ b/libgo/go/cmd/gofmt/testdata/import.golden @@ -0,0 +1,126 @@ +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" +) diff --git a/libgo/go/cmd/gofmt/testdata/import.input b/libgo/go/cmd/gofmt/testdata/import.input new file mode 100644 index 00000000000..9a4b09dbf91 --- /dev/null +++ b/libgo/go/cmd/gofmt/testdata/import.input @@ -0,0 +1,131 @@ +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" +) diff --git a/libgo/go/cmd/gofmt/testdata/old.golden b/libgo/go/cmd/gofmt/testdata/old.golden new file mode 100644 index 00000000000..95a0b72a0e0 --- /dev/null +++ b/libgo/go/cmd/gofmt/testdata/old.golden @@ -0,0 +1,9 @@ +package P + +func f() { + if x { + y + } else { + z + } +} diff --git a/libgo/go/cmd/gofmt/testdata/old.input b/libgo/go/cmd/gofmt/testdata/old.input new file mode 100644 index 00000000000..e24eed215d3 --- /dev/null +++ b/libgo/go/cmd/gofmt/testdata/old.input @@ -0,0 +1,8 @@ +package P + +func f() { + if x { + y + } else + z +} diff --git a/libgo/go/cmd/gofmt/testdata/rewrite1.golden b/libgo/go/cmd/gofmt/testdata/rewrite1.golden new file mode 100644 index 00000000000..d9beb370582 --- /dev/null +++ b/libgo/go/cmd/gofmt/testdata/rewrite1.golden @@ -0,0 +1,12 @@ +// 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) +} diff --git a/libgo/go/cmd/gofmt/testdata/rewrite1.input b/libgo/go/cmd/gofmt/testdata/rewrite1.input new file mode 100644 index 00000000000..bdb894320d3 --- /dev/null +++ b/libgo/go/cmd/gofmt/testdata/rewrite1.input @@ -0,0 +1,12 @@ +// 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) +} diff --git a/libgo/go/cmd/gofmt/testdata/rewrite2.golden b/libgo/go/cmd/gofmt/testdata/rewrite2.golden new file mode 100644 index 00000000000..64c67ffa67b --- /dev/null +++ b/libgo/go/cmd/gofmt/testdata/rewrite2.golden @@ -0,0 +1,10 @@ +// 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 {} diff --git a/libgo/go/cmd/gofmt/testdata/rewrite2.input b/libgo/go/cmd/gofmt/testdata/rewrite2.input new file mode 100644 index 00000000000..21171447a10 --- /dev/null +++ b/libgo/go/cmd/gofmt/testdata/rewrite2.input @@ -0,0 +1,10 @@ +// 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 {} diff --git a/libgo/go/cmd/gofmt/testdata/rewrite3.golden b/libgo/go/cmd/gofmt/testdata/rewrite3.golden new file mode 100644 index 00000000000..0d16d16011b --- /dev/null +++ b/libgo/go/cmd/gofmt/testdata/rewrite3.golden @@ -0,0 +1,12 @@ +// 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 +} diff --git a/libgo/go/cmd/gofmt/testdata/rewrite3.input b/libgo/go/cmd/gofmt/testdata/rewrite3.input new file mode 100644 index 00000000000..0d16d16011b --- /dev/null +++ b/libgo/go/cmd/gofmt/testdata/rewrite3.input @@ -0,0 +1,12 @@ +// 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 +} diff --git a/libgo/go/cmd/gofmt/testdata/rewrite4.golden b/libgo/go/cmd/gofmt/testdata/rewrite4.golden new file mode 100644 index 00000000000..8dfc81a0746 --- /dev/null +++ b/libgo/go/cmd/gofmt/testdata/rewrite4.golden @@ -0,0 +1,74 @@ +// 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() +} diff --git a/libgo/go/cmd/gofmt/testdata/rewrite4.input b/libgo/go/cmd/gofmt/testdata/rewrite4.input new file mode 100644 index 00000000000..164cc0451f3 --- /dev/null +++ b/libgo/go/cmd/gofmt/testdata/rewrite4.input @@ -0,0 +1,74 @@ +// 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() +} diff --git a/libgo/go/cmd/gofmt/testdata/rewrite5.golden b/libgo/go/cmd/gofmt/testdata/rewrite5.golden new file mode 100644 index 00000000000..5a448a63d37 --- /dev/null +++ b/libgo/go/cmd/gofmt/testdata/rewrite5.golden @@ -0,0 +1,15 @@ +// 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 +} diff --git a/libgo/go/cmd/gofmt/testdata/rewrite5.input b/libgo/go/cmd/gofmt/testdata/rewrite5.input new file mode 100644 index 00000000000..0d759e69b6d --- /dev/null +++ b/libgo/go/cmd/gofmt/testdata/rewrite5.input @@ -0,0 +1,15 @@ +// 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 +} diff --git a/libgo/go/cmd/gofmt/testdata/rewrite6.golden b/libgo/go/cmd/gofmt/testdata/rewrite6.golden new file mode 100644 index 00000000000..e565dbdd97b --- /dev/null +++ b/libgo/go/cmd/gofmt/testdata/rewrite6.golden @@ -0,0 +1,15 @@ +// 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 +} diff --git a/libgo/go/cmd/gofmt/testdata/rewrite6.input b/libgo/go/cmd/gofmt/testdata/rewrite6.input new file mode 100644 index 00000000000..8c088b3e878 --- /dev/null +++ b/libgo/go/cmd/gofmt/testdata/rewrite6.input @@ -0,0 +1,15 @@ +// 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 +} diff --git a/libgo/go/cmd/gofmt/testdata/rewrite7.golden b/libgo/go/cmd/gofmt/testdata/rewrite7.golden new file mode 100644 index 00000000000..29babad9f94 --- /dev/null +++ b/libgo/go/cmd/gofmt/testdata/rewrite7.golden @@ -0,0 +1,15 @@ +// 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) +} diff --git a/libgo/go/cmd/gofmt/testdata/rewrite7.input b/libgo/go/cmd/gofmt/testdata/rewrite7.input new file mode 100644 index 00000000000..073e2a3e6f8 --- /dev/null +++ b/libgo/go/cmd/gofmt/testdata/rewrite7.input @@ -0,0 +1,15 @@ +// 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) +} diff --git a/libgo/go/cmd/gofmt/testdata/rewrite8.golden b/libgo/go/cmd/gofmt/testdata/rewrite8.golden new file mode 100644 index 00000000000..cfc452b0310 --- /dev/null +++ b/libgo/go/cmd/gofmt/testdata/rewrite8.golden @@ -0,0 +1,10 @@ +// 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 diff --git a/libgo/go/cmd/gofmt/testdata/rewrite8.input b/libgo/go/cmd/gofmt/testdata/rewrite8.input new file mode 100644 index 00000000000..235efa91cc6 --- /dev/null +++ b/libgo/go/cmd/gofmt/testdata/rewrite8.input @@ -0,0 +1,10 @@ +// 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{} diff --git a/libgo/go/cmd/gofmt/testdata/slices1.golden b/libgo/go/cmd/gofmt/testdata/slices1.golden new file mode 100644 index 00000000000..61e074f68a8 --- /dev/null +++ b/libgo/go/cmd/gofmt/testdata/slices1.golden @@ -0,0 +1,58 @@ +// 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 +} diff --git a/libgo/go/cmd/gofmt/testdata/slices1.input b/libgo/go/cmd/gofmt/testdata/slices1.input new file mode 100644 index 00000000000..4d2cbfff400 --- /dev/null +++ b/libgo/go/cmd/gofmt/testdata/slices1.input @@ -0,0 +1,58 @@ +// 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 +} diff --git a/libgo/go/cmd/gofmt/testdata/slices2.golden b/libgo/go/cmd/gofmt/testdata/slices2.golden new file mode 100644 index 00000000000..433788e1ee6 --- /dev/null +++ b/libgo/go/cmd/gofmt/testdata/slices2.golden @@ -0,0 +1,61 @@ +// 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 +} diff --git a/libgo/go/cmd/gofmt/testdata/slices2.input b/libgo/go/cmd/gofmt/testdata/slices2.input new file mode 100644 index 00000000000..433788e1ee6 --- /dev/null +++ b/libgo/go/cmd/gofmt/testdata/slices2.input @@ -0,0 +1,61 @@ +// 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 +} diff --git a/libgo/go/cmd/gofmt/testdata/stdin1.golden b/libgo/go/cmd/gofmt/testdata/stdin1.golden new file mode 100644 index 00000000000..ff8b0b7ab48 --- /dev/null +++ b/libgo/go/cmd/gofmt/testdata/stdin1.golden @@ -0,0 +1,3 @@ + if x { + y + } diff --git a/libgo/go/cmd/gofmt/testdata/stdin1.golden.gofmt b/libgo/go/cmd/gofmt/testdata/stdin1.golden.gofmt new file mode 100644 index 00000000000..1f888877d01 --- /dev/null +++ b/libgo/go/cmd/gofmt/testdata/stdin1.golden.gofmt @@ -0,0 +1,3 @@ + if x { + y +} diff --git a/libgo/go/cmd/gofmt/testdata/stdin1.input b/libgo/go/cmd/gofmt/testdata/stdin1.input new file mode 100644 index 00000000000..ff8b0b7ab48 --- /dev/null +++ b/libgo/go/cmd/gofmt/testdata/stdin1.input @@ -0,0 +1,3 @@ + if x { + y + } diff --git a/libgo/go/cmd/gofmt/testdata/stdin1.input.gofmt b/libgo/go/cmd/gofmt/testdata/stdin1.input.gofmt new file mode 100644 index 00000000000..1f888877d01 --- /dev/null +++ b/libgo/go/cmd/gofmt/testdata/stdin1.input.gofmt @@ -0,0 +1,3 @@ + if x { + y +} diff --git a/libgo/go/cmd/gofmt/testdata/stdin2.golden b/libgo/go/cmd/gofmt/testdata/stdin2.golden new file mode 100644 index 00000000000..7eb1b54fec0 --- /dev/null +++ b/libgo/go/cmd/gofmt/testdata/stdin2.golden @@ -0,0 +1,11 @@ + + +var x int + +func f() { + y := z + /* this is a comment */ + // this is a comment too +} + + diff --git a/libgo/go/cmd/gofmt/testdata/stdin2.golden.gofmt b/libgo/go/cmd/gofmt/testdata/stdin2.golden.gofmt new file mode 100644 index 00000000000..85e80030081 --- /dev/null +++ b/libgo/go/cmd/gofmt/testdata/stdin2.golden.gofmt @@ -0,0 +1,10 @@ + + + +var x int + +func f() { + y := z +} + + diff --git a/libgo/go/cmd/gofmt/testdata/stdin2.input b/libgo/go/cmd/gofmt/testdata/stdin2.input new file mode 100644 index 00000000000..99defd2d10c --- /dev/null +++ b/libgo/go/cmd/gofmt/testdata/stdin2.input @@ -0,0 +1,11 @@ + + +var x int + + +func f() { y := z + /* this is a comment */ + // this is a comment too +} + + diff --git a/libgo/go/cmd/gofmt/testdata/stdin2.input.gofmt b/libgo/go/cmd/gofmt/testdata/stdin2.input.gofmt new file mode 100644 index 00000000000..7eb1b54fec0 --- /dev/null +++ b/libgo/go/cmd/gofmt/testdata/stdin2.input.gofmt @@ -0,0 +1,11 @@ + + +var x int + +func f() { + y := z + /* this is a comment */ + // this is a comment too +} + + diff --git a/libgo/go/cmd/gofmt/testdata/stdin3.golden b/libgo/go/cmd/gofmt/testdata/stdin3.golden new file mode 100644 index 00000000000..1bf2f5a483f --- /dev/null +++ b/libgo/go/cmd/gofmt/testdata/stdin3.golden @@ -0,0 +1,6 @@ + + /* note: no newline at end of file */ + for i := 0; i < 10; i++ { + s += i + } + \ No newline at end of file diff --git a/libgo/go/cmd/gofmt/testdata/stdin3.golden.gofmt b/libgo/go/cmd/gofmt/testdata/stdin3.golden.gofmt new file mode 100644 index 00000000000..b4d1d4663ed --- /dev/null +++ b/libgo/go/cmd/gofmt/testdata/stdin3.golden.gofmt @@ -0,0 +1,7 @@ + + + /* note: no newline at end of file */ + for i := 0; i < 10; i++ { + s += i + } + \ No newline at end of file diff --git a/libgo/go/cmd/gofmt/testdata/stdin3.input b/libgo/go/cmd/gofmt/testdata/stdin3.input new file mode 100644 index 00000000000..d963bd0d21b --- /dev/null +++ b/libgo/go/cmd/gofmt/testdata/stdin3.input @@ -0,0 +1,4 @@ + + /* note: no newline at end of file */ + for i := 0; i < 10; i++ { s += i } + \ No newline at end of file diff --git a/libgo/go/cmd/gofmt/testdata/stdin3.input.gofmt b/libgo/go/cmd/gofmt/testdata/stdin3.input.gofmt new file mode 100644 index 00000000000..b4d1d4663ed --- /dev/null +++ b/libgo/go/cmd/gofmt/testdata/stdin3.input.gofmt @@ -0,0 +1,7 @@ + + + /* note: no newline at end of file */ + for i := 0; i < 10; i++ { + s += i + } + \ No newline at end of file diff --git a/libgo/go/cmd/gofmt/testdata/stdin4.golden b/libgo/go/cmd/gofmt/testdata/stdin4.golden new file mode 100644 index 00000000000..5f73435517f --- /dev/null +++ b/libgo/go/cmd/gofmt/testdata/stdin4.golden @@ -0,0 +1,3 @@ + // comment + + i := 0 diff --git a/libgo/go/cmd/gofmt/testdata/stdin4.golden.gofmt b/libgo/go/cmd/gofmt/testdata/stdin4.golden.gofmt new file mode 100644 index 00000000000..5f73435517f --- /dev/null +++ b/libgo/go/cmd/gofmt/testdata/stdin4.golden.gofmt @@ -0,0 +1,3 @@ + // comment + + i := 0 diff --git a/libgo/go/cmd/gofmt/testdata/stdin4.input b/libgo/go/cmd/gofmt/testdata/stdin4.input new file mode 100644 index 00000000000..f02a54fb1a9 --- /dev/null +++ b/libgo/go/cmd/gofmt/testdata/stdin4.input @@ -0,0 +1,3 @@ + // comment + + i := 0 diff --git a/libgo/go/cmd/gofmt/testdata/stdin4.input.gofmt b/libgo/go/cmd/gofmt/testdata/stdin4.input.gofmt new file mode 100644 index 00000000000..5f73435517f --- /dev/null +++ b/libgo/go/cmd/gofmt/testdata/stdin4.input.gofmt @@ -0,0 +1,3 @@ + // comment + + i := 0 diff --git a/libgo/go/cmd/gofmt/testdata/typeswitch.golden b/libgo/go/cmd/gofmt/testdata/typeswitch.golden new file mode 100644 index 00000000000..2b1905edd3b --- /dev/null +++ b/libgo/go/cmd/gofmt/testdata/typeswitch.golden @@ -0,0 +1,60 @@ +/* + 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 + } + */ +} diff --git a/libgo/go/cmd/gofmt/testdata/typeswitch.input b/libgo/go/cmd/gofmt/testdata/typeswitch.input new file mode 100644 index 00000000000..8f8cba9b855 --- /dev/null +++ b/libgo/go/cmd/gofmt/testdata/typeswitch.input @@ -0,0 +1,60 @@ +/* + 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 + } + */ +} diff --git a/libgo/go/go/build/build.go b/libgo/go/go/build/build.go index 1032c93c7e2..5fe7dcb6b2f 100644 --- a/libgo/go/go/build/build.go +++ b/libgo/go/go/build/build.go @@ -268,6 +268,8 @@ var cgoEnabled = map[string]bool{ "linux/386": true, "linux/amd64": true, "linux/arm": true, + "linux/ppc64": true, + "linux/ppc64le": true, "linux/s390": true, "linux/s390x": true, "netbsd/386": true, @@ -1196,8 +1198,15 @@ func init() { } } -// ToolDir is the directory containing build tools. -var ToolDir = filepath.Join(runtime.GOROOT(), "pkg/tool/"+runtime.GOOS+"_"+runtime.GOARCH) +func getToolDir() string { + 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 // a local import path, like ".", "..", "./foo", or "../foo". @@ -1218,6 +1227,8 @@ func ArchChar(goarch string) (string, error) { return "5", nil case "arm64": return "7", nil + case "ppc64", "ppc64le": + return "9", nil } return "", errors.New("unsupported GOARCH " + goarch) } diff --git a/libgo/go/runtime/extern.go b/libgo/go/runtime/extern.go index 333d4fd000f..393984c7d57 100644 --- a/libgo/go/runtime/extern.go +++ b/libgo/go/runtime/extern.go @@ -201,5 +201,8 @@ func Version() string { const GOOS string = theGoos // GOARCH is the running program's architecture target: -// 386, amd64, arm or arm64. +// 386, amd64, arm, arm64, ppc64, ppc64le. const GOARCH string = theGoarch + +// GCCGOTOOLDIR is the Tool Dir for the gccgo build +const GCCGOTOOLDIR string = theGccgoToolDir diff --git a/libgo/merge.sh b/libgo/merge.sh index e579ac7c41b..fb0d1afe82f 100755 --- a/libgo/merge.sh +++ b/libgo/merge.sh @@ -163,6 +163,36 @@ 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" for f in $runtime; do merge_c $f $f