summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorRuss Cox <rsc@golang.org>2012-01-23 15:16:38 -0500
committerRuss Cox <rsc@golang.org>2012-01-23 15:16:38 -0500
commit0841de5bcf798384500493d23d2639bf1e254976 (patch)
treefa1029708b84b7b8c9656132759ab00f8cd8b79c /src
parent10dd451ffa296c6557561a1f1121c874193379a4 (diff)
downloadgo-0841de5bcf798384500493d23d2639bf1e254976.tar.gz
go/build: add BuildTags to Context, allow !tag
This lets the client of go/build specify additional tags that can be recognized in a // +build directive. For example, a build for a custom environment like App Engine might include "appengine" in the BuildTags list, so that packages can be written with some files saying // +build appengine (build only on app engine) or // +build !appengine (build only when NOT on app engine) App Engine here is just a hypothetical context. I plan to use this in the cmd/go sources to distinguish the bootstrap version of cmd/go (which will not use networking) from the full version using a custom tag. It might also be useful in App Engine. Also, delete Build and Script, which we did not end up using for cmd/go and which never got turned on for real in goinstall. R=r, adg CC=golang-dev http://codereview.appspot.com/5554079
Diffstat (limited to 'src')
-rw-r--r--src/cmd/goinstall/main.go29
-rw-r--r--src/pkg/crypto/tls/root_stub.go2
-rw-r--r--src/pkg/go/build/build.go425
-rw-r--r--src/pkg/go/build/build_test.go56
-rw-r--r--src/pkg/go/build/dir.go128
-rw-r--r--src/pkg/net/cgo_stub.go2
-rw-r--r--src/pkg/os/user/lookup_stubs.go2
7 files changed, 137 insertions, 507 deletions
diff --git a/src/cmd/goinstall/main.go b/src/cmd/goinstall/main.go
index ba8592b54..bbc4b6b76 100644
--- a/src/cmd/goinstall/main.go
+++ b/src/cmd/goinstall/main.go
@@ -44,7 +44,7 @@ var (
doInstall = flag.Bool("install", true, "build and install")
clean = flag.Bool("clean", false, "clean the package directory before installing")
nuke = flag.Bool("nuke", false, "clean the package directory and target before installing")
- useMake = flag.Bool("make", true, "use make to build and install")
+ useMake = flag.Bool("make", true, "use make to build and install (obsolete, always true)")
verbose = flag.Bool("v", false, "verbose")
)
@@ -336,35 +336,10 @@ func installPackage(pkg, parent string, tree *build.Tree, retry bool) (installEr
}
// Install this package.
- if *useMake {
- err := domake(dir, pkg, tree, dirInfo.IsCommand())
- if err != nil {
- return &BuildError{pkg, err}
- }
- return nil
- }
- script, err := build.Build(tree, pkg, dirInfo)
+ err = domake(dir, pkg, tree, dirInfo.IsCommand())
if err != nil {
return &BuildError{pkg, err}
}
- if *nuke {
- printf("%s: nuke\n", pkg)
- script.Nuke()
- } else if *clean {
- printf("%s: clean\n", pkg)
- script.Clean()
- }
- if *doInstall {
- if script.Stale() {
- printf("%s: install\n", pkg)
- if err := script.Run(); err != nil {
- return &BuildError{pkg, err}
- }
- } else {
- printf("%s: up-to-date\n", pkg)
- }
- }
-
return nil
}
diff --git a/src/pkg/crypto/tls/root_stub.go b/src/pkg/crypto/tls/root_stub.go
index d00493a57..ee2c3e017 100644
--- a/src/pkg/crypto/tls/root_stub.go
+++ b/src/pkg/crypto/tls/root_stub.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build plan9 darwin/nocgo
+// +build plan9 darwin,!cgo
package tls
diff --git a/src/pkg/go/build/build.go b/src/pkg/go/build/build.go
index 9515a7e64..68e8d3420 100644
--- a/src/pkg/go/build/build.go
+++ b/src/pkg/go/build/build.go
@@ -5,245 +5,7 @@
// Package build provides tools for building Go packages.
package build
-import (
- "bytes"
- "errors"
- "fmt"
- "os"
- "os/exec"
- "path/filepath"
- "regexp"
- "runtime"
- "strings"
- "time"
-)
-
-// Build produces a build Script for the given package.
-func Build(tree *Tree, pkg string, info *DirInfo) (*Script, error) {
- s := &Script{}
- b := &build{
- script: s,
- path: filepath.Join(tree.SrcDir(), pkg),
- }
- b.obj = b.abs("_obj") + string(filepath.Separator)
-
- b.goarch = runtime.GOARCH
- if g := os.Getenv("GOARCH"); g != "" {
- b.goarch = g
- }
- var err error
- b.arch, err = ArchChar(b.goarch)
- if err != nil {
- return nil, err
- }
-
- // add import object files to list of Inputs
- for _, pkg := range info.Imports {
- t, p, err := FindTree(pkg)
- if err != nil && err != ErrNotFound {
- // FindTree should always be able to suggest an import
- // path and tree. The path must be malformed
- // (for example, an absolute or relative path).
- return nil, errors.New("build: invalid import: " + pkg)
- }
- s.addInput(filepath.Join(t.PkgDir(), p+".a"))
- }
-
- // .go files to be built with gc
- gofiles := b.abss(info.GoFiles...)
- s.addInput(gofiles...)
-
- var ofiles []string // object files to be linked or packed
-
- // make build directory
- b.mkdir(b.obj)
- s.addIntermediate(b.obj)
-
- // cgo
- if len(info.CgoFiles) > 0 {
- cgoFiles := b.abss(info.CgoFiles...)
- s.addInput(cgoFiles...)
- cgoCFiles := b.abss(info.CFiles...)
- s.addInput(cgoCFiles...)
- outGo, outObj := b.cgo(cgoFiles, cgoCFiles)
- gofiles = append(gofiles, outGo...)
- ofiles = append(ofiles, outObj...)
- s.addIntermediate(outGo...)
- s.addIntermediate(outObj...)
- }
-
- // compile
- if len(gofiles) > 0 {
- ofile := b.obj + "_go_." + b.arch
- b.gc(ofile, gofiles...)
- ofiles = append(ofiles, ofile)
- s.addIntermediate(ofile)
- }
-
- // assemble
- for _, sfile := range info.SFiles {
- ofile := b.obj + sfile[:len(sfile)-1] + b.arch
- sfile = b.abs(sfile)
- s.addInput(sfile)
- b.asm(ofile, sfile)
- ofiles = append(ofiles, ofile)
- s.addIntermediate(ofile)
- }
-
- if len(ofiles) == 0 {
- return nil, errors.New("make: no object files to build")
- }
-
- // choose target file
- var targ string
- if info.IsCommand() {
- // use the last part of the import path as binary name
- _, bin := filepath.Split(pkg)
- if runtime.GOOS == "windows" {
- bin += ".exe"
- }
- targ = filepath.Join(tree.BinDir(), bin)
- } else {
- targ = filepath.Join(tree.PkgDir(), pkg+".a")
- }
-
- // make target directory
- targDir, _ := filepath.Split(targ)
- b.mkdir(targDir)
-
- // link binary or pack object
- if info.IsCommand() {
- b.ld(targ, ofiles...)
- } else {
- b.gopack(targ, ofiles...)
- }
- s.Output = append(s.Output, targ)
-
- return b.script, nil
-}
-
-// A Script describes the build process for a Go package.
-// The Input, Intermediate, and Output fields are lists of absolute paths.
-type Script struct {
- Cmd []*Cmd
- Input []string
- Intermediate []string
- Output []string
-}
-
-func (s *Script) addInput(file ...string) {
- s.Input = append(s.Input, file...)
-}
-
-func (s *Script) addIntermediate(file ...string) {
- s.Intermediate = append(s.Intermediate, file...)
-}
-
-// Run runs the Script's Cmds in order.
-func (s *Script) Run() error {
- for _, c := range s.Cmd {
- if err := c.Run(); err != nil {
- return err
- }
- }
- return nil
-}
-
-// Stale returns true if the build's inputs are newer than its outputs.
-func (s *Script) Stale() bool {
- var latest time.Time
- // get latest mtime of outputs
- for _, file := range s.Output {
- fi, err := os.Stat(file)
- if err != nil {
- // any error reading output files means stale
- return true
- }
- if mtime := fi.ModTime(); mtime.After(latest) {
- latest = mtime
- }
- }
- for _, file := range s.Input {
- fi, err := os.Stat(file)
- if err != nil || fi.ModTime().After(latest) {
- // any error reading input files means stale
- // (attempt to rebuild to figure out why)
- return true
- }
- }
- return false
-}
-
-// Clean removes the Script's Intermediate files.
-// It tries to remove every file and returns the first error it encounters.
-func (s *Script) Clean() (err error) {
- // Reverse order so that directories get removed after the files they contain.
- for i := len(s.Intermediate) - 1; i >= 0; i-- {
- if e := os.Remove(s.Intermediate[i]); err == nil {
- err = e
- }
- }
- return
-}
-
-// Nuke removes the Script's Intermediate and Output files.
-// It tries to remove every file and returns the first error it encounters.
-func (s *Script) Nuke() (err error) {
- // Reverse order so that directories get removed after the files they contain.
- for i := len(s.Output) - 1; i >= 0; i-- {
- if e := os.Remove(s.Output[i]); err == nil {
- err = e
- }
- }
- if e := s.Clean(); err == nil {
- err = e
- }
- return
-}
-
-// A Cmd describes an individual build command.
-type Cmd struct {
- Args []string // command-line
- Stdout string // write standard output to this file, "" is passthrough
- Dir string // working directory
- Env []string // environment
- Input []string // file paths (dependencies)
- Output []string // file paths
-}
-
-func (c *Cmd) String() string {
- return strings.Join(c.Args, " ")
-}
-
-// Run executes the Cmd.
-func (c *Cmd) Run() error {
- if c.Args[0] == "mkdir" {
- for _, p := range c.Output {
- if err := os.MkdirAll(p, 0777); err != nil {
- return fmt.Errorf("command %q: %v", c, err)
- }
- }
- return nil
- }
- out := new(bytes.Buffer)
- cmd := exec.Command(c.Args[0], c.Args[1:]...)
- cmd.Dir = c.Dir
- cmd.Env = c.Env
- cmd.Stdout = out
- cmd.Stderr = out
- if c.Stdout != "" {
- f, err := os.Create(c.Stdout)
- if err != nil {
- return err
- }
- defer f.Close()
- cmd.Stdout = f
- }
- if err := cmd.Run(); err != nil {
- return fmt.Errorf("command %q: %v\n%v", c, err, out)
- }
- return nil
-}
+import "errors"
// ArchChar returns the architecture character for the given goarch.
// For example, ArchChar("amd64") returns "6".
@@ -258,188 +20,3 @@ func ArchChar(goarch string) (string, error) {
}
return "", errors.New("unsupported GOARCH " + goarch)
}
-
-type build struct {
- script *Script
- path string
- obj string
- goarch string
- arch string
-}
-
-func (b *build) abs(file string) string {
- if filepath.IsAbs(file) {
- return file
- }
- return filepath.Join(b.path, file)
-}
-
-func (b *build) abss(file ...string) []string {
- s := make([]string, len(file))
- for i, f := range file {
- s[i] = b.abs(f)
- }
- return s
-}
-
-func (b *build) add(c Cmd) {
- b.script.Cmd = append(b.script.Cmd, &c)
-}
-
-func (b *build) mkdir(name string) {
- b.add(Cmd{
- Args: []string{"mkdir", "-p", name},
- Output: []string{name},
- })
-}
-
-func (b *build) gc(ofile string, gofiles ...string) {
- gc := b.arch + "g"
- args := append([]string{gc, "-o", ofile}, gcImportArgs...)
- args = append(args, gofiles...)
- b.add(Cmd{
- Args: args,
- Input: gofiles,
- Output: []string{ofile},
- })
-}
-
-func (b *build) asm(ofile string, sfile string) {
- asm := b.arch + "a"
- b.add(Cmd{
- Args: []string{asm, "-o", ofile, sfile},
- Input: []string{sfile},
- Output: []string{ofile},
- })
-}
-
-func (b *build) ld(targ string, ofiles ...string) {
- ld := b.arch + "l"
- args := append([]string{ld, "-o", targ}, ldImportArgs...)
- args = append(args, ofiles...)
- b.add(Cmd{
- Args: args,
- Input: ofiles,
- Output: []string{targ},
- })
-}
-
-func (b *build) gopack(targ string, ofiles ...string) {
- b.add(Cmd{
- Args: append([]string{"gopack", "grc", targ}, ofiles...),
- Input: ofiles,
- Output: []string{targ},
- })
-}
-
-func (b *build) cc(ofile string, cfiles ...string) {
- cc := b.arch + "c"
- dir := fmt.Sprintf("%s_%s", runtime.GOOS, runtime.GOARCH)
- inc := filepath.Join(runtime.GOROOT(), "pkg", dir)
- args := []string{cc, "-FVw", "-I", inc, "-o", ofile}
- b.add(Cmd{
- Args: append(args, cfiles...),
- Input: cfiles,
- Output: []string{ofile},
- })
-}
-
-func (b *build) gccCompile(ofile, cfile string) {
- b.add(Cmd{
- Args: b.gccArgs("-o", ofile, "-c", cfile),
- Input: []string{cfile},
- Output: []string{ofile},
- })
-}
-
-func (b *build) gccLink(ofile string, ofiles ...string) {
- b.add(Cmd{
- Args: append(b.gccArgs("-o", ofile), ofiles...),
- Input: ofiles,
- Output: []string{ofile},
- })
-}
-
-func (b *build) gccArgs(args ...string) []string {
- // TODO(adg): HOST_CC
- a := []string{"gcc", "-I", b.path, "-g", "-fPIC", "-O2"}
- switch b.arch {
- case "8":
- a = append(a, "-m32")
- case "6":
- a = append(a, "-m64")
- }
- return append(a, args...)
-}
-
-var cgoRe = regexp.MustCompile(`[/\\:]`)
-
-func (b *build) cgo(cgofiles, cgocfiles []string) (outGo, outObj []string) {
- // cgo
- // TODO(adg): CGOPKGPATH
- // TODO(adg): CGO_FLAGS
- gofiles := []string{b.obj + "_cgo_gotypes.go"}
- cfiles := []string{b.obj + "_cgo_main.c", b.obj + "_cgo_export.c"}
- for _, fn := range cgofiles {
- f := b.obj + cgoRe.ReplaceAllString(fn[:len(fn)-2], "_")
- gofiles = append(gofiles, f+"cgo1.go")
- cfiles = append(cfiles, f+"cgo2.c")
- }
- defunC := b.obj + "_cgo_defun.c"
- output := append([]string{defunC}, cfiles...)
- output = append(output, gofiles...)
- b.add(Cmd{
- Args: append([]string{"cgo", "--"}, cgofiles...),
- Dir: b.path,
- Env: append(os.Environ(), "GOARCH="+b.goarch),
- Input: cgofiles,
- Output: output,
- })
- outGo = append(outGo, gofiles...)
- b.script.addIntermediate(defunC, b.obj+"_cgo_export.h", b.obj+"_cgo_flags")
- b.script.addIntermediate(cfiles...)
-
- // cc _cgo_defun.c
- defunObj := b.obj + "_cgo_defun." + b.arch
- b.cc(defunObj, defunC)
- outObj = append(outObj, defunObj)
-
- // gcc
- linkobj := make([]string, 0, len(cfiles))
- for _, cfile := range cfiles {
- ofile := cfile[:len(cfile)-1] + "o"
- b.gccCompile(ofile, cfile)
- linkobj = append(linkobj, ofile)
- if !strings.HasSuffix(ofile, "_cgo_main.o") {
- outObj = append(outObj, ofile)
- } else {
- b.script.addIntermediate(ofile)
- }
- }
- for _, cfile := range cgocfiles {
- ofile := b.obj + cgoRe.ReplaceAllString(cfile[:len(cfile)-1], "_") + "o"
- b.gccCompile(ofile, cfile)
- linkobj = append(linkobj, ofile)
- outObj = append(outObj, ofile)
- }
- dynObj := b.obj + "_cgo_.o"
- b.gccLink(dynObj, linkobj...)
- b.script.addIntermediate(dynObj)
-
- // cgo -dynimport
- importC := b.obj + "_cgo_import.c"
- b.add(Cmd{
- Args: []string{"cgo", "-dynimport", dynObj},
- Stdout: importC,
- Input: []string{dynObj},
- Output: []string{importC},
- })
- b.script.addIntermediate(importC)
-
- // cc _cgo_import.ARCH
- importObj := b.obj + "_cgo_import." + b.arch
- b.cc(importObj, importC)
- outObj = append(outObj, importObj)
-
- return
-}
diff --git a/src/pkg/go/build/build_test.go b/src/pkg/go/build/build_test.go
index fd4030632..381e2b2d9 100644
--- a/src/pkg/go/build/build_test.go
+++ b/src/pkg/go/build/build_test.go
@@ -5,7 +5,6 @@
package build
import (
- "os/exec"
"path/filepath"
"reflect"
"runtime"
@@ -63,8 +62,6 @@ func ifCgo(x []string) []string {
return nil
}
-const cmdtestOutput = "3"
-
func TestBuild(t *testing.T) {
for _, tt := range buildPkgs {
tree := Path[0] // Goroot
@@ -78,39 +75,32 @@ func TestBuild(t *testing.T) {
t.Errorf("ScanDir(%#q) = %#v, want %#v\n", tt.dir, info, tt.info)
continue
}
+ }
+}
- if tt.dir == "go/build/cgotest" && len(info.CgoFiles) == 0 {
- continue
- }
-
- s, err := Build(tree, tt.dir, info)
- if err != nil {
- t.Errorf("Build(%#q): %v", tt.dir, err)
- continue
+func TestMatch(t *testing.T) {
+ ctxt := DefaultContext
+ what := "default"
+ match := func(tag string) {
+ if !ctxt.match(tag) {
+ t.Errorf("%s context should match %s, does not", what, tag)
}
-
- if err := s.Run(); err != nil {
- t.Errorf("Run(%#q): %v", tt.dir, err)
- continue
+ }
+ nomatch := func(tag string) {
+ if ctxt.match(tag) {
+ t.Errorf("%s context should NOT match %s, does", what, tag)
}
+ }
- if tt.dir == "go/build/cmdtest" {
- bin := s.Output[0]
- b, err := exec.Command(bin).CombinedOutput()
- if err != nil {
- t.Errorf("exec %s: %v", bin, err)
- continue
- }
- if string(b) != cmdtestOutput {
- t.Errorf("cmdtest output: %s want: %s", b, cmdtestOutput)
- }
- }
+ match(runtime.GOOS + "," + runtime.GOARCH)
+ match(runtime.GOOS + "," + runtime.GOARCH + ",!foo")
+ nomatch(runtime.GOOS + "," + runtime.GOARCH + ",foo")
- // Deferred because cmdtest depends on pkgtest.
- defer func(s *Script) {
- if err := s.Nuke(); err != nil {
- t.Errorf("nuking: %v", err)
- }
- }(s)
- }
+ what = "modified"
+ ctxt.BuildTags = []string{"foo"}
+ match(runtime.GOOS + "," + runtime.GOARCH)
+ match(runtime.GOOS + "," + runtime.GOARCH + ",foo")
+ nomatch(runtime.GOOS + "," + runtime.GOARCH + ",!foo")
+ match(runtime.GOOS + "," + runtime.GOARCH + ",!bar")
+ nomatch(runtime.GOOS + "," + runtime.GOARCH + ",bar")
}
diff --git a/src/pkg/go/build/dir.go b/src/pkg/go/build/dir.go
index 5ce75fda7..66005455d 100644
--- a/src/pkg/go/build/dir.go
+++ b/src/pkg/go/build/dir.go
@@ -25,9 +25,10 @@ import (
// A Context specifies the supporting context for a build.
type Context struct {
- GOARCH string // target architecture
- GOOS string // target operating system
- CgoEnabled bool // whether cgo can be used
+ GOARCH string // target architecture
+ GOOS string // target operating system
+ CgoEnabled bool // whether cgo can be used
+ BuildTags []string // additional tags to recognize in +build lines
// By default, ScanDir uses the operating system's
// file system calls to read directories and files.
@@ -74,7 +75,7 @@ func (ctxt *Context) readFile(dir, file string) (string, []byte, error) {
// The DefaultContext is the default Context for builds.
// It uses the GOARCH and GOOS environment variables
// if set, or else the compiled code's GOARCH and GOOS.
-var DefaultContext = defaultContext()
+var DefaultContext Context = defaultContext()
var cgoEnabled = map[string]bool{
"darwin/386": true,
@@ -121,7 +122,7 @@ type DirInfo struct {
Imports []string // All packages imported by GoFiles
// Source files
- GoFiles []string // .go files in dir (excluding CgoFiles)
+ GoFiles []string // .go files in dir (excluding CgoFiles, TestGoFiles, XTestGoFiles)
HFiles []string // .h files in dir
CFiles []string // .c files in dir
SFiles []string // .s (and, when using cgo, .S files in dir)
@@ -148,13 +149,71 @@ func ScanDir(dir string) (info *DirInfo, err error) {
return DefaultContext.ScanDir(dir)
}
-// ScanDir returns a structure with details about the Go content found
-// in the given directory. The file lists exclude:
+// TODO(rsc): Move this comment to a more appropriate place.
+
+// ScanDir returns a structure with details about the Go package
+// found in the given directory.
+//
+// Most .go, .c, .h, and .s files in the directory are considered part
+// of the package. The exceptions are:
//
-// - files in package main (unless no other package is found)
-// - files in package documentation
-// - files ending in _test.go
+// - .go files in package main (unless no other package is found)
+// - .go files in package documentation
// - files starting with _ or .
+// - files with build constraints not satisfied by the context
+//
+// Build Constraints
+//
+// A build constraint is a line comment beginning with the directive +build
+// that lists the conditions under which a file should be included in the package.
+// Constraints may appear in any kind of source file (not just Go), but
+// they must be appear near the top of the file, preceded
+// only by blank lines and other line comments.
+//
+// A build constraint is evaluated as the OR of space-separated options;
+// each option evaluates as the AND of ots comma-separated terms;
+// and each term is an alphanumeric word or, preceded by !, its negation.
+// That is, the build constraint:
+//
+// // +build linux,386 darwin,!cgo
+//
+// corresponds to the boolean formula:
+//
+// (linux AND 386) OR (darwin AND (NOT cgo))
+//
+// During a particular build, the following words are satisfied:
+//
+// - the target operating system, as spelled by runtime.GOOS
+// - the target architecture, as spelled by runtime.GOARCH
+// - "cgo", if ctxt.CgoEnabled is true
+// - any additional words listed in ctxt.BuildTags
+//
+// If a file's name, after stripping the extension and a possible _test suffix,
+// matches *_GOOS, *_GOARCH, or *_GOOS_GOARCH for any known operating
+// system and architecture values, then the file is considered to have an implicit
+// build constraint requiring those terms.
+//
+// Examples
+//
+// To keep a file from being considered for the build:
+//
+// // +build ignore
+//
+// (any other unsatisfied word will work as well, but ``ignore'' is conventional.)
+//
+// To build a file only when using cgo, and only on Linux and OS X:
+//
+// // +build linux,cgo darwin,cgo
+//
+// Such a file is usually paired with another file implementing the
+// default functionality for other systems, which in this case would
+// carry the constraint:
+//
+// // +build !linux !darwin !cgo
+//
+// Naming a file dns_windows.go will cause it to be included only when
+// building the package for Windows; similarly, math_386.s will be included
+// only when building the package for 32-bit x86.
//
func (ctxt *Context) ScanDir(dir string) (info *DirInfo, err error) {
dirs, err := ctxt.readDir(dir)
@@ -389,7 +448,7 @@ func (ctxt *Context) shouldBuild(content []byte) bool {
if f[0] == "+build" {
ok := false
for _, tok := range f[1:] {
- if ctxt.matchOSArch(tok) {
+ if ctxt.match(tok) {
ok = true
break
}
@@ -441,7 +500,7 @@ func (ctxt *Context) saveCgo(filename string, di *DirInfo, cg *ast.CommentGroup)
if len(cond) > 0 {
ok := false
for _, c := range cond {
- if ctxt.matchOSArch(c) {
+ if ctxt.match(c) {
ok = true
break
}
@@ -550,26 +609,55 @@ func splitQuoted(s string) (r []string, err error) {
return args, err
}
-// matchOSArch returns true if the name is one of:
+// match returns true if the name is one of:
//
// $GOOS
// $GOARCH
// cgo (if cgo is enabled)
-// nocgo (if cgo is disabled)
+// !cgo (if cgo is disabled)
+// tag (if tag is listed in ctxt.BuildTags)
+// !tag (if tag is not listed in ctxt.BuildTags)
// a slash-separated list of any of these
//
-func (ctxt *Context) matchOSArch(name string) bool {
- if ctxt.CgoEnabled && name == "cgo" {
- return true
+func (ctxt *Context) match(name string) bool {
+ if name == "" {
+ return false
+ }
+ if i := strings.Index(name, ","); i >= 0 {
+ // comma-separated list
+ return ctxt.match(name[:i]) && ctxt.match(name[i+1:])
+ }
+ if strings.HasPrefix(name, "!!") { // bad syntax, reject always
+ return false
+ }
+ if strings.HasPrefix(name, "!") { // negation
+ return !ctxt.match(name[1:])
+ }
+
+ // Tags must be letters, digits, underscores.
+ // Unlike in Go identifiers, all digits is fine (e.g., "386").
+ for _, c := range name {
+ if !unicode.IsLetter(c) && !unicode.IsDigit(c) && c != '_' {
+ return false
+ }
}
- if !ctxt.CgoEnabled && name == "nocgo" {
+
+ // special tags
+ if ctxt.CgoEnabled && name == "cgo" {
return true
}
if name == ctxt.GOOS || name == ctxt.GOARCH {
return true
}
- i := strings.Index(name, "/")
- return i >= 0 && ctxt.matchOSArch(name[:i]) && ctxt.matchOSArch(name[i+1:])
+
+ // other tags
+ for _, tag := range ctxt.BuildTags {
+ if tag == name {
+ return true
+ }
+ }
+
+ return false
}
// goodOSArchFile returns false if the name contains a $GOOS or $GOARCH
diff --git a/src/pkg/net/cgo_stub.go b/src/pkg/net/cgo_stub.go
index 66aff837d..52e57d740 100644
--- a/src/pkg/net/cgo_stub.go
+++ b/src/pkg/net/cgo_stub.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build nocgo
+// +build !cgo
// Stub cgo routines for systems that do not use cgo to do network lookups.
diff --git a/src/pkg/os/user/lookup_stubs.go b/src/pkg/os/user/lookup_stubs.go
index 42fa55744..10f5170a9 100644
--- a/src/pkg/os/user/lookup_stubs.go
+++ b/src/pkg/os/user/lookup_stubs.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build nocgo windows
+// +build !cgo windows
package user