mirror of
https://github.com/golang/go
synced 2024-11-25 01:37:57 -07:00
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 https://golang.org/cl/5554079
This commit is contained in:
parent
bf0c190343
commit
b5777571b3
@ -44,7 +44,7 @@ var (
|
|||||||
doInstall = flag.Bool("install", true, "build and install")
|
doInstall = flag.Bool("install", true, "build and install")
|
||||||
clean = flag.Bool("clean", false, "clean the package directory before installing")
|
clean = flag.Bool("clean", false, "clean the package directory before installing")
|
||||||
nuke = flag.Bool("nuke", false, "clean the package directory and target 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")
|
verbose = flag.Bool("v", false, "verbose")
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -336,35 +336,10 @@ func installPackage(pkg, parent string, tree *build.Tree, retry bool) (installEr
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Install this package.
|
// Install this package.
|
||||||
if *useMake {
|
err = domake(dir, pkg, tree, dirInfo.IsCommand())
|
||||||
err := domake(dir, pkg, tree, dirInfo.IsCommand())
|
|
||||||
if err != nil {
|
|
||||||
return &BuildError{pkg, err}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
script, err := build.Build(tree, pkg, dirInfo)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return &BuildError{pkg, err}
|
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
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
// +build plan9 darwin/nocgo
|
// +build plan9 darwin,!cgo
|
||||||
|
|
||||||
package tls
|
package tls
|
||||||
|
|
||||||
|
@ -5,245 +5,7 @@
|
|||||||
// Package build provides tools for building Go packages.
|
// Package build provides tools for building Go packages.
|
||||||
package build
|
package build
|
||||||
|
|
||||||
import (
|
import "errors"
|
||||||
"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
|
|
||||||
}
|
|
||||||
|
|
||||||
// ArchChar returns the architecture character for the given goarch.
|
// ArchChar returns the architecture character for the given goarch.
|
||||||
// For example, ArchChar("amd64") returns "6".
|
// For example, ArchChar("amd64") returns "6".
|
||||||
@ -258,188 +20,3 @@ func ArchChar(goarch string) (string, error) {
|
|||||||
}
|
}
|
||||||
return "", errors.New("unsupported GOARCH " + goarch)
|
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
|
|
||||||
}
|
|
||||||
|
@ -5,7 +5,6 @@
|
|||||||
package build
|
package build
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"os/exec"
|
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"reflect"
|
"reflect"
|
||||||
"runtime"
|
"runtime"
|
||||||
@ -63,8 +62,6 @@ func ifCgo(x []string) []string {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
const cmdtestOutput = "3"
|
|
||||||
|
|
||||||
func TestBuild(t *testing.T) {
|
func TestBuild(t *testing.T) {
|
||||||
for _, tt := range buildPkgs {
|
for _, tt := range buildPkgs {
|
||||||
tree := Path[0] // Goroot
|
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)
|
t.Errorf("ScanDir(%#q) = %#v, want %#v\n", tt.dir, info, tt.info)
|
||||||
continue
|
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
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := s.Run(); err != nil {
|
|
||||||
t.Errorf("Run(%#q): %v", tt.dir, err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Deferred because cmdtest depends on pkgtest.
|
|
||||||
defer func(s *Script) {
|
|
||||||
if err := s.Nuke(); err != nil {
|
|
||||||
t.Errorf("nuking: %v", err)
|
|
||||||
}
|
|
||||||
}(s)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
nomatch := func(tag string) {
|
||||||
|
if ctxt.match(tag) {
|
||||||
|
t.Errorf("%s context should NOT match %s, does", what, tag)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
match(runtime.GOOS + "," + runtime.GOARCH)
|
||||||
|
match(runtime.GOOS + "," + runtime.GOARCH + ",!foo")
|
||||||
|
nomatch(runtime.GOOS + "," + runtime.GOARCH + ",foo")
|
||||||
|
|
||||||
|
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")
|
||||||
|
}
|
||||||
|
@ -25,9 +25,10 @@ import (
|
|||||||
|
|
||||||
// A Context specifies the supporting context for a build.
|
// A Context specifies the supporting context for a build.
|
||||||
type Context struct {
|
type Context struct {
|
||||||
GOARCH string // target architecture
|
GOARCH string // target architecture
|
||||||
GOOS string // target operating system
|
GOOS string // target operating system
|
||||||
CgoEnabled bool // whether cgo can be used
|
CgoEnabled bool // whether cgo can be used
|
||||||
|
BuildTags []string // additional tags to recognize in +build lines
|
||||||
|
|
||||||
// By default, ScanDir uses the operating system's
|
// By default, ScanDir uses the operating system's
|
||||||
// file system calls to read directories and files.
|
// 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.
|
// The DefaultContext is the default Context for builds.
|
||||||
// It uses the GOARCH and GOOS environment variables
|
// It uses the GOARCH and GOOS environment variables
|
||||||
// if set, or else the compiled code's GOARCH and GOOS.
|
// if set, or else the compiled code's GOARCH and GOOS.
|
||||||
var DefaultContext = defaultContext()
|
var DefaultContext Context = defaultContext()
|
||||||
|
|
||||||
var cgoEnabled = map[string]bool{
|
var cgoEnabled = map[string]bool{
|
||||||
"darwin/386": true,
|
"darwin/386": true,
|
||||||
@ -121,7 +122,7 @@ type DirInfo struct {
|
|||||||
Imports []string // All packages imported by GoFiles
|
Imports []string // All packages imported by GoFiles
|
||||||
|
|
||||||
// Source files
|
// 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
|
HFiles []string // .h files in dir
|
||||||
CFiles []string // .c files in dir
|
CFiles []string // .c files in dir
|
||||||
SFiles []string // .s (and, when using cgo, .S 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)
|
return DefaultContext.ScanDir(dir)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ScanDir returns a structure with details about the Go content found
|
// TODO(rsc): Move this comment to a more appropriate place.
|
||||||
// in the given directory. The file lists exclude:
|
|
||||||
|
// ScanDir returns a structure with details about the Go package
|
||||||
|
// found in the given directory.
|
||||||
//
|
//
|
||||||
// - files in package main (unless no other package is found)
|
// Most .go, .c, .h, and .s files in the directory are considered part
|
||||||
// - files in package documentation
|
// of the package. The exceptions are:
|
||||||
// - 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 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) {
|
func (ctxt *Context) ScanDir(dir string) (info *DirInfo, err error) {
|
||||||
dirs, err := ctxt.readDir(dir)
|
dirs, err := ctxt.readDir(dir)
|
||||||
@ -389,7 +448,7 @@ func (ctxt *Context) shouldBuild(content []byte) bool {
|
|||||||
if f[0] == "+build" {
|
if f[0] == "+build" {
|
||||||
ok := false
|
ok := false
|
||||||
for _, tok := range f[1:] {
|
for _, tok := range f[1:] {
|
||||||
if ctxt.matchOSArch(tok) {
|
if ctxt.match(tok) {
|
||||||
ok = true
|
ok = true
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@ -441,7 +500,7 @@ func (ctxt *Context) saveCgo(filename string, di *DirInfo, cg *ast.CommentGroup)
|
|||||||
if len(cond) > 0 {
|
if len(cond) > 0 {
|
||||||
ok := false
|
ok := false
|
||||||
for _, c := range cond {
|
for _, c := range cond {
|
||||||
if ctxt.matchOSArch(c) {
|
if ctxt.match(c) {
|
||||||
ok = true
|
ok = true
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@ -550,26 +609,55 @@ func splitQuoted(s string) (r []string, err error) {
|
|||||||
return args, err
|
return args, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// matchOSArch returns true if the name is one of:
|
// match returns true if the name is one of:
|
||||||
//
|
//
|
||||||
// $GOOS
|
// $GOOS
|
||||||
// $GOARCH
|
// $GOARCH
|
||||||
// cgo (if cgo is enabled)
|
// 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
|
// a slash-separated list of any of these
|
||||||
//
|
//
|
||||||
func (ctxt *Context) matchOSArch(name string) bool {
|
func (ctxt *Context) match(name string) bool {
|
||||||
if ctxt.CgoEnabled && name == "cgo" {
|
if name == "" {
|
||||||
return true
|
return false
|
||||||
}
|
}
|
||||||
if !ctxt.CgoEnabled && name == "nocgo" {
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// special tags
|
||||||
|
if ctxt.CgoEnabled && name == "cgo" {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
if name == ctxt.GOOS || name == ctxt.GOARCH {
|
if name == ctxt.GOOS || name == ctxt.GOARCH {
|
||||||
return true
|
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
|
// goodOSArchFile returns false if the name contains a $GOOS or $GOARCH
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// 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.
|
// Stub cgo routines for systems that do not use cgo to do network lookups.
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
// +build nocgo windows
|
// +build !cgo windows
|
||||||
|
|
||||||
package user
|
package user
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user