src/pkg/go/build/build.go - The Go Programming Language

Golang

Source file src/pkg/go/build/build.go

     1	// Copyright 2011 The Go Authors.  All rights reserved.
     2	// Use of this source code is governed by a BSD-style
     3	// license that can be found in the LICENSE file.
     4	
     5	package build
     6	
     7	import (
     8		"bytes"
     9		"errors"
    10		"fmt"
    11		"go/ast"
    12		"go/doc"
    13		"go/parser"
    14		"go/token"
    15		"io"
    16		"io/ioutil"
    17		"log"
    18		"os"
    19		pathpkg "path"
    20		"path/filepath"
    21		"runtime"
    22		"sort"
    23		"strconv"
    24		"strings"
    25		"unicode"
    26	)
    27	
    28	// A Context specifies the supporting context for a build.
    29	type Context struct {
    30		GOARCH      string   // target architecture
    31		GOOS        string   // target operating system
    32		GOROOT      string   // Go root
    33		GOPATH      string   // Go path
    34		CgoEnabled  bool     // whether cgo can be used
    35		BuildTags   []string // additional tags to recognize in +build lines
    36		UseAllFiles bool     // use files regardless of +build lines, file names
    37		Compiler    string   // compiler to assume when computing target paths
    38	
    39		// By default, Import uses the operating system's file system calls
    40		// to read directories and files.  To read from other sources,
    41		// callers can set the following functions.  They all have default
    42		// behaviors that use the local file system, so clients need only set
    43		// the functions whose behaviors they wish to change.
    44	
    45		// JoinPath joins the sequence of path fragments into a single path.
    46		// If JoinPath is nil, Import uses filepath.Join.
    47		JoinPath func(elem ...string) string
    48	
    49		// SplitPathList splits the path list into a slice of individual paths.
    50		// If SplitPathList is nil, Import uses filepath.SplitList.
    51		SplitPathList func(list string) []string
    52	
    53		// IsAbsPath reports whether path is an absolute path.
    54		// If IsAbsPath is nil, Import uses filepath.IsAbs.
    55		IsAbsPath func(path string) bool
    56	
    57		// IsDir reports whether the path names a directory.
    58		// If IsDir is nil, Import calls os.Stat and uses the result's IsDir method.
    59		IsDir func(path string) bool
    60	
    61		// HasSubdir reports whether dir is a subdirectory of
    62		// (perhaps multiple levels below) root.
    63		// If so, HasSubdir sets rel to a slash-separated path that
    64		// can be joined to root to produce a path equivalent to dir.
    65		// If HasSubdir is nil, Import uses an implementation built on
    66		// filepath.EvalSymlinks.
    67		HasSubdir func(root, dir string) (rel string, ok bool)
    68	
    69		// ReadDir returns a slice of os.FileInfo, sorted by Name,
    70		// describing the content of the named directory.
    71		// If ReadDir is nil, Import uses io.ReadDir.
    72		ReadDir func(dir string) (fi []os.FileInfo, err error)
    73	
    74		// OpenFile opens a file (not a directory) for reading.
    75		// If OpenFile is nil, Import uses os.Open.
    76		OpenFile func(path string) (r io.ReadCloser, err error)
    77	}
    78	
    79	// joinPath calls ctxt.JoinPath (if not nil) or else filepath.Join.
    80	func (ctxt *Context) joinPath(elem ...string) string {
    81		if f := ctxt.JoinPath; f != nil {
    82			return f(elem...)
    83		}
    84		return filepath.Join(elem...)
    85	}
    86	
    87	// splitPathList calls ctxt.SplitPathList (if not nil) or else filepath.SplitList.
    88	func (ctxt *Context) splitPathList(s string) []string {
    89		if f := ctxt.SplitPathList; f != nil {
    90			return f(s)
    91		}
    92		return filepath.SplitList(s)
    93	}
    94	
    95	// isAbsPath calls ctxt.IsAbsSPath (if not nil) or else filepath.IsAbs.
    96	func (ctxt *Context) isAbsPath(path string) bool {
    97		if f := ctxt.IsAbsPath; f != nil {
    98			return f(path)
    99		}
   100		return filepath.IsAbs(path)
   101	}
   102	
   103	// isDir calls ctxt.IsDir (if not nil) or else uses os.Stat.
   104	func (ctxt *Context) isDir(path string) bool {
   105		if f := ctxt.IsDir; f != nil {
   106			return f(path)
   107		}
   108		fi, err := os.Stat(path)
   109		return err == nil && fi.IsDir()
   110	}
   111	
   112	// hasSubdir calls ctxt.HasSubdir (if not nil) or else uses
   113	// the local file system to answer the question.
   114	func (ctxt *Context) hasSubdir(root, dir string) (rel string, ok bool) {
   115		if f := ctxt.HasSubdir; f != nil {
   116			return f(root, dir)
   117		}
   118	
   119		if p, err := filepath.EvalSymlinks(root); err == nil {
   120			root = p
   121		}
   122		if p, err := filepath.EvalSymlinks(dir); err == nil {
   123			dir = p
   124		}
   125		const sep = string(filepath.Separator)
   126		root = filepath.Clean(root)
   127		if !strings.HasSuffix(root, sep) {
   128			root += sep
   129		}
   130		dir = filepath.Clean(dir)
   131		if !strings.HasPrefix(dir, root) {
   132			return "", false
   133		}
   134		return filepath.ToSlash(dir[len(root):]), true
   135	}
   136	
   137	// readDir calls ctxt.ReadDir (if not nil) or else ioutil.ReadDir.
   138	func (ctxt *Context) readDir(path string) ([]os.FileInfo, error) {
   139		if f := ctxt.ReadDir; f != nil {
   140			return f(path)
   141		}
   142		return ioutil.ReadDir(path)
   143	}
   144	
   145	// openFile calls ctxt.OpenFile (if not nil) or else os.Open.
   146	func (ctxt *Context) openFile(path string) (io.ReadCloser, error) {
   147		if fn := ctxt.OpenFile; fn != nil {
   148			return fn(path)
   149		}
   150	
   151		f, err := os.Open(path)
   152		if err != nil {
   153			return nil, err // nil interface
   154		}
   155		return f, nil
   156	}
   157	
   158	// isFile determines whether path is a file by trying to open it.
   159	// It reuses openFile instead of adding another function to the
   160	// list in Context.
   161	func (ctxt *Context) isFile(path string) bool {
   162		f, err := ctxt.openFile(path)
   163		if err != nil {
   164			return false
   165		}
   166		f.Close()
   167		return true
   168	}
   169	
   170	// gopath returns the list of Go path directories.
   171	func (ctxt *Context) gopath() []string {
   172		var all []string
   173		for _, p := range ctxt.splitPathList(ctxt.GOPATH) {
   174			if p == "" || p == ctxt.GOROOT {
   175				// Empty paths are uninteresting.
   176				// If the path is the GOROOT, ignore it.
   177				// People sometimes set GOPATH=$GOROOT, which is useless
   178				// but would cause us to find packages with import paths
   179				// like "pkg/math".
   180				// Do not get confused by this common mistake.
   181				continue
   182			}
   183			all = append(all, p)
   184		}
   185		return all
   186	}
   187	
   188	// SrcDirs returns a list of package source root directories.
   189	// It draws from the current Go root and Go path but omits directories
   190	// that do not exist.
   191	func (ctxt *Context) SrcDirs() []string {
   192		var all []string
   193		if ctxt.GOROOT != "" {
   194			dir := ctxt.joinPath(ctxt.GOROOT, "src", "pkg")
   195			if ctxt.isDir(dir) {
   196				all = append(all, dir)
   197			}
   198		}
   199		for _, p := range ctxt.gopath() {
   200			dir := ctxt.joinPath(p, "src")
   201			if ctxt.isDir(dir) {
   202				all = append(all, dir)
   203			}
   204		}
   205		return all
   206	}
   207	
   208	// Default is the default Context for builds.
   209	// It uses the GOARCH, GOOS, GOROOT, and GOPATH environment variables
   210	// if set, or else the compiled code's GOARCH, GOOS, and GOROOT.
   211	var Default Context = defaultContext()
   212	
   213	var cgoEnabled = map[string]bool{
   214		"darwin/386":    true,
   215		"darwin/amd64":  true,
   216		"linux/386":     true,
   217		"linux/amd64":   true,
   218		"freebsd/386":   true,
   219		"freebsd/amd64": true,
   220		"windows/386":   true,
   221		"windows/amd64": true,
   222	}
   223	
   224	func defaultContext() Context {
   225		var c Context
   226	
   227		c.GOARCH = envOr("GOARCH", runtime.GOARCH)
   228		c.GOOS = envOr("GOOS", runtime.GOOS)
   229		c.GOROOT = runtime.GOROOT()
   230		c.GOPATH = envOr("GOPATH", "")
   231		c.Compiler = runtime.Compiler
   232	
   233		switch os.Getenv("CGO_ENABLED") {
   234		case "1":
   235			c.CgoEnabled = true
   236		case "0":
   237			c.CgoEnabled = false
   238		default:
   239			c.CgoEnabled = cgoEnabled[c.GOOS+"/"+c.GOARCH]
   240		}
   241	
   242		return c
   243	}
   244	
   245	func envOr(name, def string) string {
   246		s := os.Getenv(name)
   247		if s == "" {
   248			return def
   249		}
   250		return s
   251	}
   252	
   253	// An ImportMode controls the behavior of the Import method.
   254	type ImportMode uint
   255	
   256	const (
   257		// If FindOnly is set, Import stops after locating the directory
   258		// that should contain the sources for a package.  It does not
   259		// read any files in the directory.
   260		FindOnly ImportMode = 1 << iota
   261	
   262		// If AllowBinary is set, Import can be satisfied by a compiled
   263		// package object without corresponding sources.
   264		AllowBinary
   265	)
   266	
   267	// A Package describes the Go package found in a directory.
   268	type Package struct {
   269		Dir        string // directory containing package sources
   270		Name       string // package name
   271		Doc        string // documentation synopsis
   272		ImportPath string // import path of package ("" if unknown)
   273		Root       string // root of Go tree where this package lives
   274		SrcRoot    string // package source root directory ("" if unknown)
   275		PkgRoot    string // package install root directory ("" if unknown)
   276		BinDir     string // command install directory ("" if unknown)
   277		Goroot     bool   // package found in Go root
   278		PkgObj     string // installed .a file
   279	
   280		// Source files
   281		GoFiles   []string // .go source files (excluding CgoFiles, TestGoFiles, XTestGoFiles)
   282		CgoFiles  []string // .go source files that import "C"
   283		CFiles    []string // .c source files
   284		HFiles    []string // .h source files
   285		SFiles    []string // .s source files
   286		SysoFiles []string // .syso system object files to add to archive
   287	
   288		// Cgo directives
   289		CgoPkgConfig []string // Cgo pkg-config directives
   290		CgoCFLAGS    []string // Cgo CFLAGS directives
   291		CgoLDFLAGS   []string // Cgo LDFLAGS directives
   292	
   293		// Dependency information
   294		Imports   []string                    // imports from GoFiles, CgoFiles
   295		ImportPos map[string][]token.Position // line information for Imports
   296	
   297		// Test information
   298		TestGoFiles    []string                    // _test.go files in package
   299		TestImports    []string                    // imports from TestGoFiles
   300		TestImportPos  map[string][]token.Position // line information for TestImports
   301		XTestGoFiles   []string                    // _test.go files outside package
   302		XTestImports   []string                    // imports from XTestGoFiles
   303		XTestImportPos map[string][]token.Position // line information for XTestImports
   304	}
   305	
   306	// IsCommand reports whether the package is considered a
   307	// command to be installed (not just a library).
   308	// Packages named "main" are treated as commands.
   309	func (p *Package) IsCommand() bool {
   310		return p.Name == "main"
   311	}
   312	
   313	// ImportDir is like Import but processes the Go package found in
   314	// the named directory.
   315	func (ctxt *Context) ImportDir(dir string, mode ImportMode) (*Package, error) {
   316		return ctxt.Import(".", dir, mode)
   317	}
   318	
   319	// NoGoError is the error used by Import to describe a directory
   320	// containing no Go source files.
   321	type NoGoError struct {
   322		Dir string
   323	}
   324	
   325	func (e *NoGoError) Error() string {
   326		return "no Go source files in " + e.Dir
   327	}
   328	
   329	// Import returns details about the Go package named by the import path,
   330	// interpreting local import paths relative to the srcDir directory.
   331	// If the path is a local import path naming a package that can be imported
   332	// using a standard import path, the returned package will set p.ImportPath
   333	// to that path.
   334	//
   335	// In the directory containing the package, .go, .c, .h, and .s files are
   336	// considered part of the package except for:
   337	//
   338	//	- .go files in package documentation
   339	//	- files starting with _ or . (likely editor temporary files)
   340	//	- files with build constraints not satisfied by the context
   341	//
   342	// If an error occurs, Import returns a non-nil error also returns a non-nil
   343	// *Package containing partial information.
   344	//
   345	func (ctxt *Context) Import(path string, srcDir string, mode ImportMode) (*Package, error) {
   346		p := &Package{
   347			ImportPath: path,
   348		}
   349	
   350		var pkga string
   351		var pkgerr error
   352		switch ctxt.Compiler {
   353		case "gccgo":
   354			dir, elem := pathpkg.Split(p.ImportPath)
   355			pkga = "pkg/gccgo/" + dir + "lib" + elem + ".a"
   356		case "gc":
   357			pkga = "pkg/" + ctxt.GOOS + "_" + ctxt.GOARCH + "/" + p.ImportPath + ".a"
   358		default:
   359			// Save error for end of function.
   360			pkgerr = fmt.Errorf("import %q: unknown compiler %q", path, ctxt.Compiler)
   361		}
   362	
   363		binaryOnly := false
   364		if IsLocalImport(path) {
   365			pkga = "" // local imports have no installed path
   366			if srcDir == "" {
   367				return p, fmt.Errorf("import %q: import relative to unknown directory", path)
   368			}
   369			if !ctxt.isAbsPath(path) {
   370				p.Dir = ctxt.joinPath(srcDir, path)
   371			}
   372			// Determine canonical import path, if any.
   373			if ctxt.GOROOT != "" {
   374				root := ctxt.joinPath(ctxt.GOROOT, "src", "pkg")
   375				if sub, ok := ctxt.hasSubdir(root, p.Dir); ok {
   376					p.Goroot = true
   377					p.ImportPath = sub
   378					p.Root = ctxt.GOROOT
   379					goto Found
   380				}
   381			}
   382			all := ctxt.gopath()
   383			for i, root := range all {
   384				rootsrc := ctxt.joinPath(root, "src")
   385				if sub, ok := ctxt.hasSubdir(rootsrc, p.Dir); ok {
   386					// We found a potential import path for dir,
   387					// but check that using it wouldn't find something
   388					// else first.
   389					if ctxt.GOROOT != "" {
   390						if dir := ctxt.joinPath(ctxt.GOROOT, "src", "pkg", sub); ctxt.isDir(dir) {
   391							goto Found
   392						}
   393					}
   394					for _, earlyRoot := range all[:i] {
   395						if dir := ctxt.joinPath(earlyRoot, "src", sub); ctxt.isDir(dir) {
   396							goto Found
   397						}
   398					}
   399	
   400					// sub would not name some other directory instead of this one.
   401					// Record it.
   402					p.ImportPath = sub
   403					p.Root = root
   404					goto Found
   405				}
   406			}
   407			// It's okay that we didn't find a root containing dir.
   408			// Keep going with the information we have.
   409		} else {
   410			if strings.HasPrefix(path, "/") {
   411				return p, fmt.Errorf("import %q: cannot import absolute path", path)
   412			}
   413			// Determine directory from import path.
   414			if ctxt.GOROOT != "" {
   415				dir := ctxt.joinPath(ctxt.GOROOT, "src", "pkg", path)
   416				isDir := ctxt.isDir(dir)
   417				binaryOnly = !isDir && mode&AllowBinary != 0 && pkga != "" && ctxt.isFile(ctxt.joinPath(ctxt.GOROOT, pkga))
   418				if isDir || binaryOnly {
   419					p.Dir = dir
   420					p.Goroot = true
   421					p.Root = ctxt.GOROOT
   422					goto Found
   423				}
   424			}
   425			for _, root := range ctxt.gopath() {
   426				dir := ctxt.joinPath(root, "src", path)
   427				isDir := ctxt.isDir(dir)
   428				binaryOnly = !isDir && mode&AllowBinary != 0 && pkga != "" && ctxt.isFile(ctxt.joinPath(root, pkga))
   429				if isDir || binaryOnly {
   430					p.Dir = dir
   431					p.Root = root
   432					goto Found
   433				}
   434			}
   435			return p, fmt.Errorf("import %q: cannot find package", path)
   436		}
   437	
   438	Found:
   439		if p.Root != "" {
   440			if p.Goroot {
   441				p.SrcRoot = ctxt.joinPath(p.Root, "src", "pkg")
   442			} else {
   443				p.SrcRoot = ctxt.joinPath(p.Root, "src")
   444			}
   445			p.PkgRoot = ctxt.joinPath(p.Root, "pkg")
   446			p.BinDir = ctxt.joinPath(p.Root, "bin")
   447			if pkga != "" {
   448				p.PkgObj = ctxt.joinPath(p.Root, pkga)
   449			}
   450		}
   451	
   452		if mode&FindOnly != 0 {
   453			return p, pkgerr
   454		}
   455		if binaryOnly && (mode&AllowBinary) != 0 {
   456			return p, pkgerr
   457		}
   458	
   459		dirs, err := ctxt.readDir(p.Dir)
   460		if err != nil {
   461			return p, err
   462		}
   463	
   464		var Sfiles []string // files with ".S" (capital S)
   465		var firstFile string
   466		imported := make(map[string][]token.Position)
   467		testImported := make(map[string][]token.Position)
   468		xTestImported := make(map[string][]token.Position)
   469		fset := token.NewFileSet()
   470		for _, d := range dirs {
   471			if d.IsDir() {
   472				continue
   473			}
   474			name := d.Name()
   475			if strings.HasPrefix(name, "_") ||
   476				strings.HasPrefix(name, ".") {
   477				continue
   478			}
   479			if !ctxt.UseAllFiles && !ctxt.goodOSArchFile(name) {
   480				continue
   481			}
   482	
   483			i := strings.LastIndex(name, ".")
   484			if i < 0 {
   485				i = len(name)
   486			}
   487			ext := name[i:]
   488			switch ext {
   489			case ".go", ".c", ".s", ".h", ".S":
   490				// tentatively okay - read to make sure
   491			case ".syso":
   492				// binary objects to add to package archive
   493				// Likely of the form foo_windows.syso, but
   494				// the name was vetted above with goodOSArchFile.
   495				p.SysoFiles = append(p.SysoFiles, name)
   496				continue
   497			default:
   498				// skip
   499				continue
   500			}
   501	
   502			filename := ctxt.joinPath(p.Dir, name)
   503			f, err := ctxt.openFile(filename)
   504			if err != nil {
   505				return p, err
   506			}
   507			data, err := ioutil.ReadAll(f)
   508			f.Close()
   509			if err != nil {
   510				return p, fmt.Errorf("read %s: %v", filename, err)
   511			}
   512	
   513			// Look for +build comments to accept or reject the file.
   514			if !ctxt.UseAllFiles && !ctxt.shouldBuild(data) {
   515				continue
   516			}
   517	
   518			// Going to save the file.  For non-Go files, can stop here.
   519			switch ext {
   520			case ".c":
   521				p.CFiles = append(p.CFiles, name)
   522				continue
   523			case ".h":
   524				p.HFiles = append(p.HFiles, name)
   525				continue
   526			case ".s":
   527				p.SFiles = append(p.SFiles, name)
   528				continue
   529			case ".S":
   530				Sfiles = append(Sfiles, name)
   531				continue
   532			}
   533	
   534			pf, err := parser.ParseFile(fset, filename, data, parser.ImportsOnly|parser.ParseComments)
   535			if err != nil {
   536				return p, err
   537			}
   538	
   539			pkg := string(pf.Name.Name)
   540			if pkg == "documentation" {
   541				continue
   542			}
   543	
   544			isTest := strings.HasSuffix(name, "_test.go")
   545			isXTest := false
   546			if isTest && strings.HasSuffix(pkg, "_test") {
   547				isXTest = true
   548				pkg = pkg[:len(pkg)-len("_test")]
   549			}
   550	
   551			if p.Name == "" {
   552				p.Name = pkg
   553				firstFile = name
   554			} else if pkg != p.Name {
   555				return p, fmt.Errorf("found packages %s (%s) and %s (%s) in %s", p.Name, firstFile, pkg, name, p.Dir)
   556			}
   557			if pf.Doc != nil && p.Doc == "" {
   558				p.Doc = doc.Synopsis(pf.Doc.Text())
   559			}
   560	
   561			// Record imports and information about cgo.
   562			isCgo := false
   563			for _, decl := range pf.Decls {
   564				d, ok := decl.(*ast.GenDecl)
   565				if !ok {
   566					continue
   567				}
   568				for _, dspec := range d.Specs {
   569					spec, ok := dspec.(*ast.ImportSpec)
   570					if !ok {
   571						continue
   572					}
   573					quoted := string(spec.Path.Value)
   574					path, err := strconv.Unquote(quoted)
   575					if err != nil {
   576						log.Panicf("%s: parser returned invalid quoted string: <%s>", filename, quoted)
   577					}
   578					if isXTest {
   579						xTestImported[path] = append(xTestImported[path], fset.Position(spec.Pos()))
   580					} else if isTest {
   581						testImported[path] = append(testImported[path], fset.Position(spec.Pos()))
   582					} else {
   583						imported[path] = append(imported[path], fset.Position(spec.Pos()))
   584					}
   585					if path == "C" {
   586						if isTest {
   587							return p, fmt.Errorf("use of cgo in test %s not supported", filename)
   588						}
   589						cg := spec.Doc
   590						if cg == nil && len(d.Specs) == 1 {
   591							cg = d.Doc
   592						}
   593						if cg != nil {
   594							if err := ctxt.saveCgo(filename, p, cg); err != nil {
   595								return p, err
   596							}
   597						}
   598						isCgo = true
   599					}
   600				}
   601			}
   602			if isCgo {
   603				if ctxt.CgoEnabled {
   604					p.CgoFiles = append(p.CgoFiles, name)
   605				}
   606			} else if isXTest {
   607				p.XTestGoFiles = append(p.XTestGoFiles, name)
   608			} else if isTest {
   609				p.TestGoFiles = append(p.TestGoFiles, name)
   610			} else {
   611				p.GoFiles = append(p.GoFiles, name)
   612			}
   613		}
   614		if p.Name == "" {
   615			return p, &NoGoError{p.Dir}
   616		}
   617	
   618		p.Imports, p.ImportPos = cleanImports(imported)
   619		p.TestImports, p.TestImportPos = cleanImports(testImported)
   620		p.XTestImports, p.XTestImportPos = cleanImports(xTestImported)
   621	
   622		// add the .S files only if we are using cgo
   623		// (which means gcc will compile them).
   624		// The standard assemblers expect .s files.
   625		if len(p.CgoFiles) > 0 {
   626			p.SFiles = append(p.SFiles, Sfiles...)
   627			sort.Strings(p.SFiles)
   628		}
   629	
   630		return p, pkgerr
   631	}
   632	
   633	func cleanImports(m map[string][]token.Position) ([]string, map[string][]token.Position) {
   634		all := make([]string, 0, len(m))
   635		for path := range m {
   636			all = append(all, path)
   637		}
   638		sort.Strings(all)
   639		return all, m
   640	}
   641	
   642	// Import is shorthand for Default.Import.
   643	func Import(path, srcDir string, mode ImportMode) (*Package, error) {
   644		return Default.Import(path, srcDir, mode)
   645	}
   646	
   647	// ImportDir is shorthand for Default.ImportDir.
   648	func ImportDir(dir string, mode ImportMode) (*Package, error) {
   649		return Default.ImportDir(dir, mode)
   650	}
   651	
   652	var slashslash = []byte("//")
   653	
   654	// shouldBuild reports whether it is okay to use this file,
   655	// The rule is that in the file's leading run of // comments
   656	// and blank lines, which must be followed by a blank line
   657	// (to avoid including a Go package clause doc comment),
   658	// lines beginning with '// +build' are taken as build directives.
   659	//
   660	// The file is accepted only if each such line lists something
   661	// matching the file.  For example:
   662	//
   663	//	// +build windows linux
   664	//
   665	// marks the file as applicable only on Windows and Linux.
   666	//
   667	func (ctxt *Context) shouldBuild(content []byte) bool {
   668		// Pass 1. Identify leading run of // comments and blank lines,
   669		// which must be followed by a blank line.
   670		end := 0
   671		p := content
   672		for len(p) > 0 {
   673			line := p
   674			if i := bytes.IndexByte(line, '\n'); i >= 0 {
   675				line, p = line[:i], p[i+1:]
   676			} else {
   677				p = p[len(p):]
   678			}
   679			line = bytes.TrimSpace(line)
   680			if len(line) == 0 { // Blank line
   681				end = cap(content) - cap(line) // &line[0] - &content[0]
   682				continue
   683			}
   684			if !bytes.HasPrefix(line, slashslash) { // Not comment line
   685				break
   686			}
   687		}
   688		content = content[:end]
   689	
   690		// Pass 2.  Process each line in the run.
   691		p = content
   692		for len(p) > 0 {
   693			line := p
   694			if i := bytes.IndexByte(line, '\n'); i >= 0 {
   695				line, p = line[:i], p[i+1:]
   696			} else {
   697				p = p[len(p):]
   698			}
   699			line = bytes.TrimSpace(line)
   700			if bytes.HasPrefix(line, slashslash) {
   701				line = bytes.TrimSpace(line[len(slashslash):])
   702				if len(line) > 0 && line[0] == '+' {
   703					// Looks like a comment +line.
   704					f := strings.Fields(string(line))
   705					if f[0] == "+build" {
   706						ok := false
   707						for _, tok := range f[1:] {
   708							if ctxt.match(tok) {
   709								ok = true
   710								break
   711							}
   712						}
   713						if !ok {
   714							return false // this one doesn't match
   715						}
   716					}
   717				}
   718			}
   719		}
   720		return true // everything matches
   721	}
   722	
   723	// saveCgo saves the information from the #cgo lines in the import "C" comment.
   724	// These lines set CFLAGS and LDFLAGS and pkg-config directives that affect
   725	// the way cgo's C code is built.
   726	//
   727	// TODO(rsc): This duplicates code in cgo.
   728	// Once the dust settles, remove this code from cgo.
   729	func (ctxt *Context) saveCgo(filename string, di *Package, cg *ast.CommentGroup) error {
   730		text := cg.Text()
   731		for _, line := range strings.Split(text, "\n") {
   732			orig := line
   733	
   734			// Line is
   735			//	#cgo [GOOS/GOARCH...] LDFLAGS: stuff
   736			//
   737			line = strings.TrimSpace(line)
   738			if len(line) < 5 || line[:4] != "#cgo" || (line[4] != ' ' && line[4] != '\t') {
   739				continue
   740			}
   741	
   742			// Split at colon.
   743			line = strings.TrimSpace(line[4:])
   744			i := strings.Index(line, ":")
   745			if i < 0 {
   746				return fmt.Errorf("%s: invalid #cgo line: %s", filename, orig)
   747			}
   748			line, argstr := line[:i], line[i+1:]
   749	
   750			// Parse GOOS/GOARCH stuff.
   751			f := strings.Fields(line)
   752			if len(f) < 1 {
   753				return fmt.Errorf("%s: invalid #cgo line: %s", filename, orig)
   754			}
   755	
   756			cond, verb := f[:len(f)-1], f[len(f)-1]
   757			if len(cond) > 0 {
   758				ok := false
   759				for _, c := range cond {
   760					if ctxt.match(c) {
   761						ok = true
   762						break
   763					}
   764				}
   765				if !ok {
   766					continue
   767				}
   768			}
   769	
   770			args, err := splitQuoted(argstr)
   771			if err != nil {
   772				return fmt.Errorf("%s: invalid #cgo line: %s", filename, orig)
   773			}
   774			for _, arg := range args {
   775				if !safeName(arg) {
   776					return fmt.Errorf("%s: malformed #cgo argument: %s", filename, arg)
   777				}
   778			}
   779	
   780			switch verb {
   781			case "CFLAGS":
   782				di.CgoCFLAGS = append(di.CgoCFLAGS, args...)
   783			case "LDFLAGS":
   784				di.CgoLDFLAGS = append(di.CgoLDFLAGS, args...)
   785			case "pkg-config":
   786				di.CgoPkgConfig = append(di.CgoPkgConfig, args...)
   787			default:
   788				return fmt.Errorf("%s: invalid #cgo verb: %s", filename, orig)
   789			}
   790		}
   791		return nil
   792	}
   793	
   794	var safeBytes = []byte("+-.,/0123456789=ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz:")
   795	
   796	func safeName(s string) bool {
   797		if s == "" {
   798			return false
   799		}
   800		for i := 0; i < len(s); i++ {
   801			if c := s[i]; c < 0x80 && bytes.IndexByte(safeBytes, c) < 0 {
   802				return false
   803			}
   804		}
   805		return true
   806	}
   807	
   808	// splitQuoted splits the string s around each instance of one or more consecutive
   809	// white space characters while taking into account quotes and escaping, and
   810	// returns an array of substrings of s or an empty list if s contains only white space.
   811	// Single quotes and double quotes are recognized to prevent splitting within the
   812	// quoted region, and are removed from the resulting substrings. If a quote in s
   813	// isn't closed err will be set and r will have the unclosed argument as the
   814	// last element.  The backslash is used for escaping.
   815	//
   816	// For example, the following string:
   817	//
   818	//     a b:"c d" 'e''f'  "g\""
   819	//
   820	// Would be parsed as:
   821	//
   822	//     []string{"a", "b:c d", "ef", `g"`}
   823	//
   824	func splitQuoted(s string) (r []string, err error) {
   825		var args []string
   826		arg := make([]rune, len(s))
   827		escaped := false
   828		quoted := false
   829		quote := '\x00'
   830		i := 0
   831		for _, rune := range s {
   832			switch {
   833			case escaped:
   834				escaped = false
   835			case rune == '\\':
   836				escaped = true
   837				continue
   838			case quote != '\x00':
   839				if rune == quote {
   840					quote = '\x00'
   841					continue
   842				}
   843			case rune == '"' || rune == '\'':
   844				quoted = true
   845				quote = rune
   846				continue
   847			case unicode.IsSpace(rune):
   848				if quoted || i > 0 {
   849					quoted = false
   850					args = append(args, string(arg[:i]))
   851					i = 0
   852				}
   853				continue
   854			}
   855			arg[i] = rune
   856			i++
   857		}
   858		if quoted || i > 0 {
   859			args = append(args, string(arg[:i]))
   860		}
   861		if quote != 0 {
   862			err = errors.New("unclosed quote")
   863		} else if escaped {
   864			err = errors.New("unfinished escaping")
   865		}
   866		return args, err
   867	}
   868	
   869	// match returns true if the name is one of:
   870	//
   871	//	$GOOS
   872	//	$GOARCH
   873	//	cgo (if cgo is enabled)
   874	//	!cgo (if cgo is disabled)
   875	//	tag (if tag is listed in ctxt.BuildTags)
   876	//	!tag (if tag is not listed in ctxt.BuildTags)
   877	//	a comma-separated list of any of these
   878	//
   879	func (ctxt *Context) match(name string) bool {
   880		if name == "" {
   881			return false
   882		}
   883		if i := strings.Index(name, ","); i >= 0 {
   884			// comma-separated list
   885			return ctxt.match(name[:i]) && ctxt.match(name[i+1:])
   886		}
   887		if strings.HasPrefix(name, "!!") { // bad syntax, reject always
   888			return false
   889		}
   890		if strings.HasPrefix(name, "!") { // negation
   891			return len(name) > 1 && !ctxt.match(name[1:])
   892		}
   893	
   894		// Tags must be letters, digits, underscores.
   895		// Unlike in Go identifiers, all digits are fine (e.g., "386").
   896		for _, c := range name {
   897			if !unicode.IsLetter(c) && !unicode.IsDigit(c) && c != '_' {
   898				return false
   899			}
   900		}
   901	
   902		// special tags
   903		if ctxt.CgoEnabled && name == "cgo" {
   904			return true
   905		}
   906		if name == ctxt.GOOS || name == ctxt.GOARCH {
   907			return true
   908		}
   909	
   910		// other tags
   911		for _, tag := range ctxt.BuildTags {
   912			if tag == name {
   913				return true
   914			}
   915		}
   916	
   917		return false
   918	}
   919	
   920	// goodOSArchFile returns false if the name contains a $GOOS or $GOARCH
   921	// suffix which does not match the current system.
   922	// The recognized name formats are:
   923	//
   924	//     name_$(GOOS).*
   925	//     name_$(GOARCH).*
   926	//     name_$(GOOS)_$(GOARCH).*
   927	//     name_$(GOOS)_test.*
   928	//     name_$(GOARCH)_test.*
   929	//     name_$(GOOS)_$(GOARCH)_test.*
   930	//
   931	func (ctxt *Context) goodOSArchFile(name string) bool {
   932		if dot := strings.Index(name, "."); dot != -1 {
   933			name = name[:dot]
   934		}
   935		l := strings.Split(name, "_")
   936		if n := len(l); n > 0 && l[n-1] == "test" {
   937			l = l[:n-1]
   938		}
   939		n := len(l)
   940		if n >= 2 && knownOS[l[n-2]] && knownArch[l[n-1]] {
   941			return l[n-2] == ctxt.GOOS && l[n-1] == ctxt.GOARCH
   942		}
   943		if n >= 1 && knownOS[l[n-1]] {
   944			return l[n-1] == ctxt.GOOS
   945		}
   946		if n >= 1 && knownArch[l[n-1]] {
   947			return l[n-1] == ctxt.GOARCH
   948		}
   949		return true
   950	}
   951	
   952	var knownOS = make(map[string]bool)
   953	var knownArch = make(map[string]bool)
   954	
   955	func init() {
   956		for _, v := range strings.Fields(goosList) {
   957			knownOS[v] = true
   958		}
   959		for _, v := range strings.Fields(goarchList) {
   960			knownArch[v] = true
   961		}
   962	}
   963	
   964	// ToolDir is the directory containing build tools.
   965	var ToolDir = filepath.Join(runtime.GOROOT(), "pkg/tool/"+runtime.GOOS+"_"+runtime.GOARCH)
   966	
   967	// IsLocalImport reports whether the import path is
   968	// a local import path, like ".", "..", "./foo", or "../foo".
   969	func IsLocalImport(path string) bool {
   970		return path == "." || path == ".." ||
   971			strings.HasPrefix(path, "./") || strings.HasPrefix(path, "../")
   972	}
   973	
   974	// ArchChar returns the architecture character for the given goarch.
   975	// For example, ArchChar("amd64") returns "6".
   976	func ArchChar(goarch string) (string, error) {
   977		switch goarch {
   978		case "386":
   979			return "8", nil
   980		case "amd64":
   981			return "6", nil
   982		case "arm":
   983			return "5", nil
   984		}
   985		return "", errors.New("unsupported GOARCH " + goarch)
   986	}