mirror of
https://github.com/golang/go
synced 2024-11-25 06:57:58 -07:00
goinstall: use go/make package to scan and build packages
R=rsc, n13m3y3r, kevlar CC=golang-dev https://golang.org/cl/4515180
This commit is contained in:
parent
414da2e4a3
commit
db5a4ffc2a
@ -8,23 +8,5 @@ TARG=goinstall
|
|||||||
GOFILES=\
|
GOFILES=\
|
||||||
download.go\
|
download.go\
|
||||||
main.go\
|
main.go\
|
||||||
make.go\
|
|
||||||
parse.go\
|
|
||||||
path.go\
|
|
||||||
syslist.go\
|
|
||||||
|
|
||||||
CLEANFILES+=syslist.go
|
|
||||||
|
|
||||||
include ../../Make.cmd
|
include ../../Make.cmd
|
||||||
|
|
||||||
syslist.go:
|
|
||||||
echo '// Generated automatically by make.' >$@
|
|
||||||
echo 'package main' >>$@
|
|
||||||
echo 'const goosList = "$(GOOS_LIST)"' >>$@
|
|
||||||
echo 'const goarchList = "$(GOARCH_LIST)"' >>$@
|
|
||||||
|
|
||||||
test:
|
|
||||||
gotest
|
|
||||||
|
|
||||||
testshort:
|
|
||||||
gotest -test.short
|
|
||||||
|
@ -15,7 +15,9 @@ Flags and default settings:
|
|||||||
-a=false install all previously installed packages
|
-a=false install all previously installed packages
|
||||||
-clean=false clean the package directory before installing
|
-clean=false clean the package directory before installing
|
||||||
-dashboard=true tally public packages on godashboard.appspot.com
|
-dashboard=true tally public packages on godashboard.appspot.com
|
||||||
|
-install=true build and install the package and its dependencies
|
||||||
-log=true log installed packages to $GOROOT/goinstall.log for use by -a
|
-log=true log installed packages to $GOROOT/goinstall.log for use by -a
|
||||||
|
-nuke=false remove the target object and clean before installing
|
||||||
-u=false update already-downloaded packages
|
-u=false update already-downloaded packages
|
||||||
-v=false verbose operation
|
-v=false verbose operation
|
||||||
|
|
||||||
|
@ -2,8 +2,6 @@
|
|||||||
// 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.
|
||||||
|
|
||||||
// Experimental Go package installer; see doc.go.
|
|
||||||
|
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@ -11,6 +9,7 @@ import (
|
|||||||
"exec"
|
"exec"
|
||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"go/build"
|
||||||
"go/token"
|
"go/token"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
@ -39,7 +38,9 @@ var (
|
|||||||
reportToDashboard = flag.Bool("dashboard", true, "report public packages at "+dashboardURL)
|
reportToDashboard = flag.Bool("dashboard", true, "report public packages at "+dashboardURL)
|
||||||
logPkgs = flag.Bool("log", true, "log installed packages to $GOROOT/goinstall.log for use by -a")
|
logPkgs = flag.Bool("log", true, "log installed packages to $GOROOT/goinstall.log for use by -a")
|
||||||
update = flag.Bool("u", false, "update already-downloaded packages")
|
update = flag.Bool("u", false, "update already-downloaded packages")
|
||||||
|
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")
|
||||||
verbose = flag.Bool("v", false, "verbose")
|
verbose = flag.Bool("v", false, "verbose")
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -160,67 +161,84 @@ func install(pkg, parent string) {
|
|||||||
fmt.Fprintf(os.Stderr, "\t%s\n", pkg)
|
fmt.Fprintf(os.Stderr, "\t%s\n", pkg)
|
||||||
os.Exit(2)
|
os.Exit(2)
|
||||||
}
|
}
|
||||||
visit[pkg] = visiting
|
|
||||||
parents[pkg] = parent
|
parents[pkg] = parent
|
||||||
|
visit[pkg] = visiting
|
||||||
vlogf("%s: visit\n", pkg)
|
defer func() {
|
||||||
|
visit[pkg] = done
|
||||||
|
}()
|
||||||
|
|
||||||
// Check whether package is local or remote.
|
// Check whether package is local or remote.
|
||||||
// If remote, download or update it.
|
// If remote, download or update it.
|
||||||
proot, pkg, err := findPackageRoot(pkg)
|
tree, pkg, err := build.FindTree(pkg)
|
||||||
// Don't build the standard library.
|
// Don't build the standard library.
|
||||||
if err == nil && proot.goroot && isStandardPath(pkg) {
|
if err == nil && tree.Goroot && isStandardPath(pkg) {
|
||||||
if parent == "" {
|
if parent == "" {
|
||||||
errorf("%s: can not goinstall the standard library\n", pkg)
|
errorf("%s: can not goinstall the standard library\n", pkg)
|
||||||
} else {
|
} else {
|
||||||
vlogf("%s: skipping standard library\n", pkg)
|
vlogf("%s: skipping standard library\n", pkg)
|
||||||
}
|
}
|
||||||
visit[pkg] = done
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// Download remote packages if not found or forced with -u flag.
|
// Download remote packages if not found or forced with -u flag.
|
||||||
remote := isRemote(pkg)
|
remote := isRemote(pkg)
|
||||||
if remote && (err == ErrPackageNotFound || (err == nil && *update)) {
|
if remote && (err == build.ErrNotFound || (err == nil && *update)) {
|
||||||
vlogf("%s: download\n", pkg)
|
vlogf("%s: download\n", pkg)
|
||||||
err = download(pkg, proot.srcDir())
|
err = download(pkg, tree.SrcDir())
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errorf("%s: %v\n", pkg, err)
|
errorf("%s: %v\n", pkg, err)
|
||||||
visit[pkg] = done
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
dir := filepath.Join(proot.srcDir(), pkg)
|
dir := filepath.Join(tree.SrcDir(), pkg)
|
||||||
|
|
||||||
// Install prerequisites.
|
// Install prerequisites.
|
||||||
dirInfo, err := scanDir(dir, parent == "")
|
dirInfo, err := build.ScanDir(dir, parent == "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errorf("%s: %v\n", pkg, err)
|
errorf("%s: %v\n", pkg, err)
|
||||||
visit[pkg] = done
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if len(dirInfo.goFiles) == 0 {
|
if len(dirInfo.GoFiles) == 0 {
|
||||||
errorf("%s: package has no files\n", pkg)
|
errorf("%s: package has no files\n", pkg)
|
||||||
visit[pkg] = done
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
for _, p := range dirInfo.imports {
|
for _, p := range dirInfo.Imports {
|
||||||
if p != "C" {
|
if p != "C" {
|
||||||
install(p, pkg)
|
install(p, pkg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if errors {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// Install this package.
|
// Install this package.
|
||||||
if !errors {
|
script, err := build.Build(tree, pkg, dirInfo)
|
||||||
isCmd := dirInfo.pkgName == "main"
|
if err != nil {
|
||||||
if err := domake(dir, pkg, proot, isCmd); err != nil {
|
errorf("%s: install: %v\n", pkg, err)
|
||||||
errorf("installing: %v\n", err)
|
return
|
||||||
} else if remote && *logPkgs {
|
}
|
||||||
|
if *nuke {
|
||||||
|
vlogf("%s: nuke\n", pkg)
|
||||||
|
script.Nuke()
|
||||||
|
} else if *clean {
|
||||||
|
vlogf("%s: clean\n", pkg)
|
||||||
|
script.Clean()
|
||||||
|
}
|
||||||
|
if *doInstall {
|
||||||
|
if script.Stale() {
|
||||||
|
vlogf("%s: install\n", pkg)
|
||||||
|
if err := script.Run(); err != nil {
|
||||||
|
errorf("%s: install: %v\n", pkg, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
vlogf("%s: install: up-to-date\n", pkg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if remote {
|
||||||
// mark package as installed in $GOROOT/goinstall.log
|
// mark package as installed in $GOROOT/goinstall.log
|
||||||
logPackage(pkg)
|
logPackage(pkg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
visit[pkg] = done
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Is this a standard package path? strings container/vector etc.
|
// Is this a standard package path? strings container/vector etc.
|
||||||
|
@ -1,168 +0,0 @@
|
|||||||
// 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.
|
|
||||||
|
|
||||||
// Run "make install" to build package.
|
|
||||||
|
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
"template"
|
|
||||||
)
|
|
||||||
|
|
||||||
// domake builds the package in dir.
|
|
||||||
// domake generates a standard Makefile and passes it
|
|
||||||
// to make on standard input.
|
|
||||||
func domake(dir, pkg string, root *pkgroot, isCmd bool) (err os.Error) {
|
|
||||||
makefile, err := makeMakefile(dir, pkg, root, isCmd)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
cmd := []string{"bash", "gomake", "-f-"}
|
|
||||||
if *clean {
|
|
||||||
cmd = append(cmd, "clean")
|
|
||||||
}
|
|
||||||
cmd = append(cmd, "install")
|
|
||||||
return run(dir, makefile, cmd...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// makeMakefile computes the standard Makefile for the directory dir
|
|
||||||
// installing as package pkg. It includes all *.go files in the directory
|
|
||||||
// except those in package main and those ending in _test.go.
|
|
||||||
func makeMakefile(dir, pkg string, root *pkgroot, isCmd bool) ([]byte, os.Error) {
|
|
||||||
if !safeName(pkg) {
|
|
||||||
return nil, os.ErrorString("unsafe name: " + pkg)
|
|
||||||
}
|
|
||||||
targ := pkg
|
|
||||||
targDir := root.pkgDir()
|
|
||||||
if isCmd {
|
|
||||||
// use the last part of the package name for targ
|
|
||||||
_, targ = filepath.Split(pkg)
|
|
||||||
targDir = root.binDir()
|
|
||||||
}
|
|
||||||
dirInfo, err := scanDir(dir, isCmd)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
cgoFiles := dirInfo.cgoFiles
|
|
||||||
isCgo := make(map[string]bool, len(cgoFiles))
|
|
||||||
for _, file := range cgoFiles {
|
|
||||||
if !safeName(file) {
|
|
||||||
return nil, os.ErrorString("bad name: " + file)
|
|
||||||
}
|
|
||||||
isCgo[file] = true
|
|
||||||
}
|
|
||||||
|
|
||||||
goFiles := make([]string, 0, len(dirInfo.goFiles))
|
|
||||||
for _, file := range dirInfo.goFiles {
|
|
||||||
if !safeName(file) {
|
|
||||||
return nil, os.ErrorString("unsafe name: " + file)
|
|
||||||
}
|
|
||||||
if !isCgo[file] {
|
|
||||||
goFiles = append(goFiles, file)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
oFiles := make([]string, 0, len(dirInfo.cFiles)+len(dirInfo.sFiles))
|
|
||||||
cgoOFiles := make([]string, 0, len(dirInfo.cFiles))
|
|
||||||
for _, file := range dirInfo.cFiles {
|
|
||||||
if !safeName(file) {
|
|
||||||
return nil, os.ErrorString("unsafe name: " + file)
|
|
||||||
}
|
|
||||||
// When cgo is in use, C files are compiled with gcc,
|
|
||||||
// otherwise they're compiled with gc.
|
|
||||||
if len(cgoFiles) > 0 {
|
|
||||||
cgoOFiles = append(cgoOFiles, file[:len(file)-2]+".o")
|
|
||||||
} else {
|
|
||||||
oFiles = append(oFiles, file[:len(file)-2]+".$O")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, file := range dirInfo.sFiles {
|
|
||||||
if !safeName(file) {
|
|
||||||
return nil, os.ErrorString("unsafe name: " + file)
|
|
||||||
}
|
|
||||||
oFiles = append(oFiles, file[:len(file)-2]+".$O")
|
|
||||||
}
|
|
||||||
|
|
||||||
var buf bytes.Buffer
|
|
||||||
md := makedata{targ, targDir, "pkg", goFiles, oFiles, cgoFiles, cgoOFiles, imports}
|
|
||||||
if isCmd {
|
|
||||||
md.Type = "cmd"
|
|
||||||
}
|
|
||||||
if err := makefileTemplate.Execute(&buf, &md); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return buf.Bytes(), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
var safeBytes = []byte("+-./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_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
|
|
||||||
}
|
|
||||||
|
|
||||||
// makedata is the data type for the makefileTemplate.
|
|
||||||
type makedata struct {
|
|
||||||
Targ string // build target
|
|
||||||
TargDir string // build target directory
|
|
||||||
Type string // build type: "pkg" or "cmd"
|
|
||||||
GoFiles []string // list of non-cgo .go files
|
|
||||||
OFiles []string // list of .$O files
|
|
||||||
CgoFiles []string // list of cgo .go files
|
|
||||||
CgoOFiles []string // list of cgo .o files, without extension
|
|
||||||
Imports []string // gc/ld import paths
|
|
||||||
}
|
|
||||||
|
|
||||||
var makefileTemplate = template.MustParse(`
|
|
||||||
include $(GOROOT)/src/Make.inc
|
|
||||||
|
|
||||||
TARG={Targ}
|
|
||||||
TARGDIR={TargDir}
|
|
||||||
|
|
||||||
{.section GoFiles}
|
|
||||||
GOFILES=\
|
|
||||||
{.repeated section GoFiles}
|
|
||||||
{@}\
|
|
||||||
{.end}
|
|
||||||
|
|
||||||
{.end}
|
|
||||||
{.section OFiles}
|
|
||||||
OFILES=\
|
|
||||||
{.repeated section OFiles}
|
|
||||||
{@}\
|
|
||||||
{.end}
|
|
||||||
|
|
||||||
{.end}
|
|
||||||
{.section CgoFiles}
|
|
||||||
CGOFILES=\
|
|
||||||
{.repeated section CgoFiles}
|
|
||||||
{@}\
|
|
||||||
{.end}
|
|
||||||
|
|
||||||
{.end}
|
|
||||||
{.section CgoOFiles}
|
|
||||||
CGO_OFILES=\
|
|
||||||
{.repeated section CgoOFiles}
|
|
||||||
{@}\
|
|
||||||
{.end}
|
|
||||||
|
|
||||||
{.end}
|
|
||||||
GCIMPORTS={.repeated section Imports}-I "{@}" {.end}
|
|
||||||
LDIMPORTS={.repeated section Imports}-L "{@}" {.end}
|
|
||||||
|
|
||||||
include $(GOROOT)/src/Make.{Type}
|
|
||||||
`,
|
|
||||||
nil)
|
|
@ -1,172 +0,0 @@
|
|||||||
// 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.
|
|
||||||
|
|
||||||
// Wrappers for Go parser.
|
|
||||||
|
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"go/ast"
|
|
||||||
"go/parser"
|
|
||||||
"log"
|
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
"runtime"
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
type dirInfo struct {
|
|
||||||
goFiles []string // .go files within dir (including cgoFiles)
|
|
||||||
cgoFiles []string // .go files that import "C"
|
|
||||||
cFiles []string // .c files within dir
|
|
||||||
sFiles []string // .s files within dir
|
|
||||||
imports []string // All packages imported by goFiles
|
|
||||||
pkgName string // Name of package within dir
|
|
||||||
}
|
|
||||||
|
|
||||||
// scanDir returns a structure with details about the Go content found
|
|
||||||
// in the given directory. The list of files will NOT contain the
|
|
||||||
// following entries:
|
|
||||||
//
|
|
||||||
// - Files in package main (unless allowMain is true)
|
|
||||||
// - Files ending in _test.go
|
|
||||||
// - Files starting with _ (temporary)
|
|
||||||
// - Files containing .cgo in their names
|
|
||||||
//
|
|
||||||
// The imports map keys are package paths imported by listed Go files,
|
|
||||||
// and the values are the Go files importing the respective package paths.
|
|
||||||
func scanDir(dir string, allowMain bool) (info *dirInfo, err os.Error) {
|
|
||||||
f, err := os.Open(dir)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
dirs, err := f.Readdir(-1)
|
|
||||||
f.Close()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
goFiles := make([]string, 0, len(dirs))
|
|
||||||
cgoFiles := make([]string, 0, len(dirs))
|
|
||||||
cFiles := make([]string, 0, len(dirs))
|
|
||||||
sFiles := make([]string, 0, len(dirs))
|
|
||||||
importsm := make(map[string]bool)
|
|
||||||
pkgName := ""
|
|
||||||
for i := range dirs {
|
|
||||||
d := &dirs[i]
|
|
||||||
if strings.HasPrefix(d.Name, "_") || strings.Index(d.Name, ".cgo") != -1 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if !goodOSArch(d.Name) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
switch filepath.Ext(d.Name) {
|
|
||||||
case ".go":
|
|
||||||
if strings.HasSuffix(d.Name, "_test.go") {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
case ".c":
|
|
||||||
cFiles = append(cFiles, d.Name)
|
|
||||||
continue
|
|
||||||
case ".s":
|
|
||||||
sFiles = append(sFiles, d.Name)
|
|
||||||
continue
|
|
||||||
default:
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
filename := filepath.Join(dir, d.Name)
|
|
||||||
pf, err := parser.ParseFile(fset, filename, nil, parser.ImportsOnly)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
s := string(pf.Name.Name)
|
|
||||||
if s == "main" && !allowMain {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if s == "documentation" {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if pkgName == "" {
|
|
||||||
pkgName = s
|
|
||||||
} else if pkgName != s {
|
|
||||||
// Only if all files in the directory are in package main
|
|
||||||
// do we return pkgName=="main".
|
|
||||||
// A mix of main and another package reverts
|
|
||||||
// to the original (allowMain=false) behaviour.
|
|
||||||
if s == "main" || pkgName == "main" {
|
|
||||||
return scanDir(dir, false)
|
|
||||||
}
|
|
||||||
return nil, os.ErrorString("multiple package names in " + dir)
|
|
||||||
}
|
|
||||||
goFiles = append(goFiles, d.Name)
|
|
||||||
for _, decl := range pf.Decls {
|
|
||||||
for _, spec := range decl.(*ast.GenDecl).Specs {
|
|
||||||
quoted := string(spec.(*ast.ImportSpec).Path.Value)
|
|
||||||
unquoted, err := strconv.Unquote(quoted)
|
|
||||||
if err != nil {
|
|
||||||
log.Panicf("%s: parser returned invalid quoted string: <%s>", filename, quoted)
|
|
||||||
}
|
|
||||||
importsm[unquoted] = true
|
|
||||||
if unquoted == "C" {
|
|
||||||
cgoFiles = append(cgoFiles, d.Name)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
imports := make([]string, len(importsm))
|
|
||||||
i := 0
|
|
||||||
for p := range importsm {
|
|
||||||
imports[i] = p
|
|
||||||
i++
|
|
||||||
}
|
|
||||||
return &dirInfo{goFiles, cgoFiles, cFiles, sFiles, imports, pkgName}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// goodOSArch returns false if the filename contains a $GOOS or $GOARCH
|
|
||||||
// suffix which does not match the current system.
|
|
||||||
// The recognized filename formats are:
|
|
||||||
//
|
|
||||||
// name_$(GOOS).*
|
|
||||||
// name_$(GOARCH).*
|
|
||||||
// name_$(GOOS)_$(GOARCH).*
|
|
||||||
//
|
|
||||||
func goodOSArch(filename string) bool {
|
|
||||||
if dot := strings.Index(filename, "."); dot != -1 {
|
|
||||||
filename = filename[:dot]
|
|
||||||
}
|
|
||||||
l := strings.Split(filename, "_", -1)
|
|
||||||
n := len(l)
|
|
||||||
if n == 0 {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
if good, known := goodOS[l[n-1]]; known {
|
|
||||||
return good
|
|
||||||
}
|
|
||||||
if good, known := goodArch[l[n-1]]; known {
|
|
||||||
if !good || n < 2 {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
good, known = goodOS[l[n-2]]
|
|
||||||
return good || !known
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
var goodOS = make(map[string]bool)
|
|
||||||
var goodArch = make(map[string]bool)
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
goodOS = make(map[string]bool)
|
|
||||||
goodArch = make(map[string]bool)
|
|
||||||
for _, v := range strings.Fields(goosList) {
|
|
||||||
goodOS[v] = v == runtime.GOOS
|
|
||||||
}
|
|
||||||
for _, v := range strings.Fields(goarchList) {
|
|
||||||
goodArch[v] = v == runtime.GOARCH
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,149 +0,0 @@
|
|||||||
// 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"
|
|
||||||
"log"
|
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
"runtime"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
gopath []*pkgroot
|
|
||||||
imports []string
|
|
||||||
defaultRoot *pkgroot // default root for remote packages
|
|
||||||
)
|
|
||||||
|
|
||||||
// set up gopath: parse and validate GOROOT and GOPATH variables
|
|
||||||
func init() {
|
|
||||||
root := runtime.GOROOT()
|
|
||||||
p, err := newPkgroot(root)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("Invalid GOROOT %q: %v", root, err)
|
|
||||||
}
|
|
||||||
p.goroot = true
|
|
||||||
gopath = []*pkgroot{p}
|
|
||||||
|
|
||||||
for _, p := range filepath.SplitList(os.Getenv("GOPATH")) {
|
|
||||||
if p == "" {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
r, err := newPkgroot(p)
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("Invalid GOPATH %q: %v", p, err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
gopath = append(gopath, r)
|
|
||||||
imports = append(imports, r.pkgDir())
|
|
||||||
|
|
||||||
// select first GOPATH entry as default
|
|
||||||
if defaultRoot == nil {
|
|
||||||
defaultRoot = r
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// use GOROOT if no valid GOPATH specified
|
|
||||||
if defaultRoot == nil {
|
|
||||||
defaultRoot = gopath[0]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type pkgroot struct {
|
|
||||||
path string
|
|
||||||
goroot bool // TODO(adg): remove this once Go tree re-organized
|
|
||||||
}
|
|
||||||
|
|
||||||
func newPkgroot(p string) (*pkgroot, os.Error) {
|
|
||||||
if !filepath.IsAbs(p) {
|
|
||||||
return nil, os.NewError("must be absolute")
|
|
||||||
}
|
|
||||||
ep, err := filepath.EvalSymlinks(p)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return &pkgroot{path: ep}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *pkgroot) srcDir() string {
|
|
||||||
if r.goroot {
|
|
||||||
return filepath.Join(r.path, "src", "pkg")
|
|
||||||
}
|
|
||||||
return filepath.Join(r.path, "src")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *pkgroot) pkgDir() string {
|
|
||||||
goos, goarch := runtime.GOOS, runtime.GOARCH
|
|
||||||
if e := os.Getenv("GOOS"); e != "" {
|
|
||||||
goos = e
|
|
||||||
}
|
|
||||||
if e := os.Getenv("GOARCH"); e != "" {
|
|
||||||
goarch = e
|
|
||||||
}
|
|
||||||
return filepath.Join(r.path, "pkg", goos+"_"+goarch)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *pkgroot) binDir() string {
|
|
||||||
return filepath.Join(r.path, "bin")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *pkgroot) hasSrcDir(name string) bool {
|
|
||||||
fi, err := os.Stat(filepath.Join(r.srcDir(), name))
|
|
||||||
if err != nil {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return fi.IsDirectory()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *pkgroot) hasPkg(name string) bool {
|
|
||||||
fi, err := os.Stat(filepath.Join(r.pkgDir(), name+".a"))
|
|
||||||
if err != nil {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return fi.IsRegular()
|
|
||||||
// TODO(adg): check object version is consistent
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
var ErrPackageNotFound = os.NewError("package could not be found locally")
|
|
||||||
|
|
||||||
// findPackageRoot takes an import or filesystem path and returns the
|
|
||||||
// root where the package source should be and the package import path.
|
|
||||||
func findPackageRoot(path string) (root *pkgroot, pkg string, err os.Error) {
|
|
||||||
if isLocalPath(path) {
|
|
||||||
if path, err = filepath.Abs(path); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
for _, r := range gopath {
|
|
||||||
rpath := r.srcDir() + string(filepath.Separator)
|
|
||||||
if !strings.HasPrefix(path, rpath) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
root = r
|
|
||||||
pkg = path[len(rpath):]
|
|
||||||
return
|
|
||||||
}
|
|
||||||
err = fmt.Errorf("path %q not inside a GOPATH", path)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
root = defaultRoot
|
|
||||||
pkg = path
|
|
||||||
for _, r := range gopath {
|
|
||||||
if r.hasSrcDir(path) {
|
|
||||||
root = r
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
err = ErrPackageNotFound
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Is this a local path? /foo ./foo ../foo . ..
|
|
||||||
func isLocalPath(s string) bool {
|
|
||||||
const sep = string(filepath.Separator)
|
|
||||||
return strings.HasPrefix(s, sep) || strings.HasPrefix(s, "."+sep) || strings.HasPrefix(s, ".."+sep) || s == "." || s == ".."
|
|
||||||
}
|
|
@ -1,61 +0,0 @@
|
|||||||
// 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 (
|
|
||||||
"runtime"
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
thisOS = runtime.GOOS
|
|
||||||
thisArch = runtime.GOARCH
|
|
||||||
otherOS = anotherOS()
|
|
||||||
otherArch = anotherArch()
|
|
||||||
)
|
|
||||||
|
|
||||||
func anotherOS() string {
|
|
||||||
if thisOS != "darwin" {
|
|
||||||
return "darwin"
|
|
||||||
}
|
|
||||||
return "linux"
|
|
||||||
}
|
|
||||||
|
|
||||||
func anotherArch() string {
|
|
||||||
if thisArch != "amd64" {
|
|
||||||
return "amd64"
|
|
||||||
}
|
|
||||||
return "386"
|
|
||||||
}
|
|
||||||
|
|
||||||
type GoodFileTest struct {
|
|
||||||
name string
|
|
||||||
result bool
|
|
||||||
}
|
|
||||||
|
|
||||||
var tests = []GoodFileTest{
|
|
||||||
{"file.go", true},
|
|
||||||
{"file.c", true},
|
|
||||||
{"file_foo.go", true},
|
|
||||||
{"file_" + thisArch + ".go", true},
|
|
||||||
{"file_" + otherArch + ".go", false},
|
|
||||||
{"file_" + thisOS + ".go", true},
|
|
||||||
{"file_" + otherOS + ".go", false},
|
|
||||||
{"file_" + thisOS + "_" + thisArch + ".go", true},
|
|
||||||
{"file_" + otherOS + "_" + thisArch + ".go", false},
|
|
||||||
{"file_" + thisOS + "_" + otherArch + ".go", false},
|
|
||||||
{"file_" + otherOS + "_" + otherArch + ".go", false},
|
|
||||||
{"file_foo_" + thisArch + ".go", true},
|
|
||||||
{"file_foo_" + otherArch + ".go", false},
|
|
||||||
{"file_" + thisOS + ".c", true},
|
|
||||||
{"file_" + otherOS + ".c", false},
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestGoodOSArch(t *testing.T) {
|
|
||||||
for _, test := range tests {
|
|
||||||
if goodOSArch(test.name) != test.result {
|
|
||||||
t.Fatalf("goodOSArch(%q) != %v", test.name, test.result)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -208,6 +208,7 @@ NOTEST+=\
|
|||||||
../cmd/cgo\
|
../cmd/cgo\
|
||||||
../cmd/ebnflint\
|
../cmd/ebnflint\
|
||||||
../cmd/godoc\
|
../cmd/godoc\
|
||||||
|
../cmd/goinstall\
|
||||||
../cmd/gotest\
|
../cmd/gotest\
|
||||||
../cmd/govet\
|
../cmd/govet\
|
||||||
../cmd/goyacc\
|
../cmd/goyacc\
|
||||||
|
@ -15,8 +15,14 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (d *DirInfo) Build(targ string) ([]*Cmd, os.Error) {
|
// Build produces a build Script for the given package.
|
||||||
b := &build{obj: "_obj/"}
|
func Build(tree *Tree, pkg string, info *DirInfo) (*Script, os.Error) {
|
||||||
|
s := &Script{}
|
||||||
|
b := &build{
|
||||||
|
script: s,
|
||||||
|
path: filepath.Join(tree.SrcDir(), pkg),
|
||||||
|
}
|
||||||
|
b.obj = b.abs("_obj") + "/"
|
||||||
|
|
||||||
goarch := runtime.GOARCH
|
goarch := runtime.GOARCH
|
||||||
if g := os.Getenv("GOARCH"); g != "" {
|
if g := os.Getenv("GOARCH"); g != "" {
|
||||||
@ -28,17 +34,25 @@ func (d *DirInfo) Build(targ string) ([]*Cmd, os.Error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
var gofiles = d.GoFiles // .go files to be built with gc
|
// .go files to be built with gc
|
||||||
var ofiles []string // *.GOARCH files to be linked or packed
|
gofiles := b.abss(info.GoFiles...)
|
||||||
|
s.addInput(gofiles...)
|
||||||
|
|
||||||
|
var ofiles []string // object files to be linked or packed
|
||||||
|
|
||||||
// make build directory
|
// make build directory
|
||||||
b.mkdir(b.obj)
|
b.mkdir(b.obj)
|
||||||
|
s.addIntermediate(b.obj)
|
||||||
|
|
||||||
// cgo
|
// cgo
|
||||||
if len(d.CgoFiles) > 0 {
|
if len(info.CgoFiles) > 0 {
|
||||||
outGo, outObj := b.cgo(d.CgoFiles)
|
cgoFiles := b.abss(info.CgoFiles...)
|
||||||
|
s.addInput(cgoFiles...)
|
||||||
|
outGo, outObj := b.cgo(cgoFiles)
|
||||||
gofiles = append(gofiles, outGo...)
|
gofiles = append(gofiles, outGo...)
|
||||||
ofiles = append(ofiles, outObj...)
|
ofiles = append(ofiles, outObj...)
|
||||||
|
s.addIntermediate(outGo...)
|
||||||
|
s.addIntermediate(outObj...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// compile
|
// compile
|
||||||
@ -46,31 +60,130 @@ func (d *DirInfo) Build(targ string) ([]*Cmd, os.Error) {
|
|||||||
ofile := b.obj + "_go_." + b.arch
|
ofile := b.obj + "_go_." + b.arch
|
||||||
b.gc(ofile, gofiles...)
|
b.gc(ofile, gofiles...)
|
||||||
ofiles = append(ofiles, ofile)
|
ofiles = append(ofiles, ofile)
|
||||||
|
s.addIntermediate(ofile)
|
||||||
}
|
}
|
||||||
|
|
||||||
// assemble
|
// assemble
|
||||||
for _, sfile := range d.SFiles {
|
for _, sfile := range info.SFiles {
|
||||||
ofile := b.obj + sfile[:len(sfile)-1] + b.arch
|
ofile := b.obj + sfile[:len(sfile)-1] + b.arch
|
||||||
|
sfile = b.abs(sfile)
|
||||||
|
s.addInput(sfile)
|
||||||
b.asm(ofile, sfile)
|
b.asm(ofile, sfile)
|
||||||
ofiles = append(ofiles, ofile)
|
ofiles = append(ofiles, ofile)
|
||||||
|
s.addIntermediate(sfile, ofile)
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(ofiles) == 0 {
|
if len(ofiles) == 0 {
|
||||||
return nil, os.NewError("make: no object files to build")
|
return nil, os.NewError("make: no object files to build")
|
||||||
}
|
}
|
||||||
|
|
||||||
if d.IsCommand() {
|
// choose target file
|
||||||
|
var targ string
|
||||||
|
if info.IsCommand() {
|
||||||
|
// use the last part of the import path as binary name
|
||||||
|
_, bin := filepath.Split(pkg)
|
||||||
|
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...)
|
b.ld(targ, ofiles...)
|
||||||
} else {
|
} else {
|
||||||
b.gopack(targ, ofiles...)
|
b.gopack(targ, ofiles...)
|
||||||
}
|
}
|
||||||
|
s.Output = append(s.Output, targ)
|
||||||
|
|
||||||
return b.cmds, nil
|
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() os.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 int64
|
||||||
|
// 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 m := fi.Mtime_ns; m > latest {
|
||||||
|
latest = m
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, file := range s.Input {
|
||||||
|
fi, err := os.Stat(file)
|
||||||
|
if err != nil || fi.Mtime_ns > 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 os.Error) {
|
||||||
|
for i := len(s.Intermediate) - 1; i >= 0; i-- {
|
||||||
|
if e := os.Remove(s.Intermediate[i]); err == nil {
|
||||||
|
err = e
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clean 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 os.Error) {
|
||||||
|
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 {
|
type Cmd struct {
|
||||||
Args []string // command-line
|
Args []string // command-line
|
||||||
Stdout string // write standard output to this file, "" is passthrough
|
Stdout string // write standard output to this file, "" is passthrough
|
||||||
|
Dir string // working directory
|
||||||
Input []string // file paths (dependencies)
|
Input []string // file paths (dependencies)
|
||||||
Output []string // file paths
|
Output []string // file paths
|
||||||
}
|
}
|
||||||
@ -79,14 +192,15 @@ func (c *Cmd) String() string {
|
|||||||
return strings.Join(c.Args, " ")
|
return strings.Join(c.Args, " ")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Cmd) Run(dir string) os.Error {
|
// Run executes the Cmd.
|
||||||
|
func (c *Cmd) Run() os.Error {
|
||||||
out := new(bytes.Buffer)
|
out := new(bytes.Buffer)
|
||||||
cmd := exec.Command(c.Args[0], c.Args[1:]...)
|
cmd := exec.Command(c.Args[0], c.Args[1:]...)
|
||||||
cmd.Dir = dir
|
cmd.Dir = c.Dir
|
||||||
cmd.Stdout = out
|
cmd.Stdout = out
|
||||||
cmd.Stderr = out
|
cmd.Stderr = out
|
||||||
if c.Stdout != "" {
|
if c.Stdout != "" {
|
||||||
f, err := os.Create(filepath.Join(dir, c.Stdout))
|
f, err := os.Create(c.Stdout)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -99,15 +213,6 @@ func (c *Cmd) Run(dir string) os.Error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Cmd) Clean(dir string) (err os.Error) {
|
|
||||||
for _, fn := range c.Output {
|
|
||||||
if e := os.RemoveAll(fn); err == nil {
|
|
||||||
err = e
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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".
|
||||||
func ArchChar(goarch string) (string, os.Error) {
|
func ArchChar(goarch string) (string, os.Error) {
|
||||||
@ -123,13 +228,29 @@ func ArchChar(goarch string) (string, os.Error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type build struct {
|
type build struct {
|
||||||
cmds []*Cmd
|
script *Script
|
||||||
|
path string
|
||||||
obj string
|
obj string
|
||||||
arch 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) {
|
func (b *build) add(c Cmd) {
|
||||||
b.cmds = append(b.cmds, &c)
|
b.script.Cmd = append(b.script.Cmd, &c)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *build) mkdir(name string) {
|
func (b *build) mkdir(name string) {
|
||||||
@ -222,6 +343,7 @@ func (b *build) cgo(cgofiles []string) (outGo, outObj []string) {
|
|||||||
gofiles := []string{b.obj + "_cgo_gotypes.go"}
|
gofiles := []string{b.obj + "_cgo_gotypes.go"}
|
||||||
cfiles := []string{b.obj + "_cgo_main.c", b.obj + "_cgo_export.c"}
|
cfiles := []string{b.obj + "_cgo_main.c", b.obj + "_cgo_export.c"}
|
||||||
for _, fn := range cgofiles {
|
for _, fn := range cgofiles {
|
||||||
|
fn = filepath.Base(fn)
|
||||||
f := b.obj + fn[:len(fn)-2]
|
f := b.obj + fn[:len(fn)-2]
|
||||||
gofiles = append(gofiles, f+"cgo1.go")
|
gofiles = append(gofiles, f+"cgo1.go")
|
||||||
cfiles = append(cfiles, f+"cgo2.c")
|
cfiles = append(cfiles, f+"cgo2.c")
|
||||||
|
@ -5,50 +5,46 @@
|
|||||||
package build
|
package build
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"os"
|
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"runtime"
|
"runtime"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
var buildDirs = []string{
|
// TODO(adg): test building binaries
|
||||||
"pkg/path",
|
|
||||||
"cmd/gofix",
|
var buildPkgs = []string{
|
||||||
"pkg/big",
|
"path",
|
||||||
"pkg/go/build/cgotest",
|
"big",
|
||||||
|
"go/build/cgotest",
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestBuild(t *testing.T) {
|
func TestBuild(t *testing.T) {
|
||||||
out, err := filepath.Abs("_test/out")
|
for _, pkg := range buildPkgs {
|
||||||
if err != nil {
|
if runtime.GOARCH == "arm" && strings.Contains(pkg, "/cgo") {
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
for _, d := range buildDirs {
|
|
||||||
if runtime.GOARCH == "arm" && strings.Contains(d, "/cgo") {
|
|
||||||
// no cgo for arm, yet.
|
// no cgo for arm, yet.
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
dir := filepath.Join(runtime.GOROOT(), "src", d)
|
tree := Path[0] // Goroot
|
||||||
testBuild(t, dir, out)
|
testBuild(t, tree, pkg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func testBuild(t *testing.T, dir, targ string) {
|
func testBuild(t *testing.T, tree *Tree, pkg string) {
|
||||||
d, err := ScanDir(dir, true)
|
dir := filepath.Join(tree.SrcDir(), pkg)
|
||||||
|
info, err := ScanDir(dir, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
defer os.Remove(targ)
|
s, err := Build(tree, pkg, info)
|
||||||
cmds, err := d.Build(targ)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
for _, c := range cmds {
|
for _, c := range s.Cmd {
|
||||||
t.Log("Run:", c)
|
t.Log("Run:", c)
|
||||||
err = c.Run(dir)
|
err = c.Run()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(c, err)
|
t.Error(c, err)
|
||||||
return
|
return
|
||||||
|
@ -50,7 +50,6 @@ func ScanDir(dir string, allowMain bool) (info *DirInfo, err os.Error) {
|
|||||||
|
|
||||||
var di DirInfo
|
var di DirInfo
|
||||||
imported := make(map[string]bool)
|
imported := make(map[string]bool)
|
||||||
pkgName := ""
|
|
||||||
fset := token.NewFileSet()
|
fset := token.NewFileSet()
|
||||||
for i := range dirs {
|
for i := range dirs {
|
||||||
d := &dirs[i]
|
d := &dirs[i]
|
||||||
@ -89,14 +88,14 @@ func ScanDir(dir string, allowMain bool) (info *DirInfo, err os.Error) {
|
|||||||
if s == "documentation" {
|
if s == "documentation" {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if pkgName == "" {
|
if di.PkgName == "" {
|
||||||
pkgName = s
|
di.PkgName = s
|
||||||
} else if pkgName != s {
|
} else if di.PkgName != s {
|
||||||
// Only if all files in the directory are in package main
|
// Only if all files in the directory are in package main
|
||||||
// do we return pkgName=="main".
|
// do we return PkgName=="main".
|
||||||
// A mix of main and another package reverts
|
// A mix of main and another package reverts
|
||||||
// to the original (allowMain=false) behaviour.
|
// to the original (allowMain=false) behaviour.
|
||||||
if s == "main" || pkgName == "main" {
|
if s == "main" || di.PkgName == "main" {
|
||||||
return ScanDir(dir, false)
|
return ScanDir(dir, false)
|
||||||
}
|
}
|
||||||
return nil, os.ErrorString("multiple package names in " + dir)
|
return nil, os.ErrorString("multiple package names in " + dir)
|
||||||
|
Loading…
Reference in New Issue
Block a user