diff options
Diffstat (limited to 'src/cmd/goinstall')
-rw-r--r-- | src/cmd/goinstall/Makefile | 15 | ||||
-rw-r--r-- | src/cmd/goinstall/doc.go | 1 | ||||
-rw-r--r-- | src/cmd/goinstall/main.go | 2 | ||||
-rw-r--r-- | src/cmd/goinstall/make.go | 56 | ||||
-rw-r--r-- | src/cmd/goinstall/parse.go | 69 | ||||
-rw-r--r-- | src/cmd/goinstall/syslist_test.go | 61 |
6 files changed, 178 insertions, 26 deletions
diff --git a/src/cmd/goinstall/Makefile b/src/cmd/goinstall/Makefile index 6ddb32be7..aaf202ee7 100644 --- a/src/cmd/goinstall/Makefile +++ b/src/cmd/goinstall/Makefile @@ -10,5 +10,20 @@ GOFILES=\ main.go\ make.go\ parse.go\ + syslist.go\ + +CLEANFILES+=syslist.go 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 diff --git a/src/cmd/goinstall/doc.go b/src/cmd/goinstall/doc.go index 17cc06969..15845b574 100644 --- a/src/cmd/goinstall/doc.go +++ b/src/cmd/goinstall/doc.go @@ -14,6 +14,7 @@ Usage: Flags and default settings: -a=false install all previously installed packages + -clean=false clean the package directory before installing -dashboard=true tally public packages on godashboard.appspot.com -log=true log installed packages to $GOROOT/goinstall.log for use by -a -u=false update already-downloaded packages diff --git a/src/cmd/goinstall/main.go b/src/cmd/goinstall/main.go index 34441be45..8fec8e312 100644 --- a/src/cmd/goinstall/main.go +++ b/src/cmd/goinstall/main.go @@ -120,7 +120,7 @@ func logPackage(pkg string) { if installedPkgs[pkg] { return } - fout, err := os.Open(logfile, os.O_WRONLY|os.O_APPEND|os.O_CREAT, 0644) + fout, err := os.OpenFile(logfile, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0666) if err != nil { fmt.Fprintf(os.Stderr, "%s: %s\n", argv0, err) return diff --git a/src/cmd/goinstall/make.go b/src/cmd/goinstall/make.go index e2d99bb47..ceb119e5a 100644 --- a/src/cmd/goinstall/make.go +++ b/src/cmd/goinstall/make.go @@ -52,12 +52,6 @@ func makeMakefile(dir, pkg string) ([]byte, os.Error) { return nil, err } - if len(dirInfo.cgoFiles) == 0 && len(dirInfo.cFiles) > 0 { - // When using cgo, .c files are compiled with gcc. Without cgo, - // they may be intended for 6c. Just error out for now. - return nil, os.ErrorString("C files found in non-cgo package") - } - cgoFiles := dirInfo.cgoFiles isCgo := make(map[string]bool, len(cgoFiles)) for _, file := range cgoFiles { @@ -67,26 +61,40 @@ func makeMakefile(dir, pkg string) ([]byte, os.Error) { isCgo[file] = true } - oFiles := make([]string, 0, len(dirInfo.cFiles)) - for _, file := range dirInfo.cFiles { + goFiles := make([]string, 0, len(dirInfo.goFiles)) + for _, file := range dirInfo.goFiles { if !safeName(file) { return nil, os.ErrorString("unsafe name: " + file) } - oFiles = append(oFiles, file[:len(file)-2]+".o") + if !isCgo[file] { + goFiles = append(goFiles, file) + } } - goFiles := make([]string, 0, len(dirInfo.goFiles)) - for _, file := range dirInfo.goFiles { + 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) } - if !isCgo[file] { - goFiles = append(goFiles, 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{pkg, goFiles, cgoFiles, oFiles} + md := makedata{pkg, goFiles, oFiles, cgoFiles, cgoOFiles} if err := makefileTemplate.Execute(&buf, &md); err != nil { return nil, err } @@ -106,10 +114,11 @@ func safeName(s string) bool { // makedata is the data type for the makefileTemplate. type makedata struct { - Pkg string // package import path - GoFiles []string // list of non-cgo .go files - CgoFiles []string // list of cgo .go files - OFiles []string // list of ofiles for cgo + Pkg string // package import path + 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 } var makefileTemplate = template.MustParse(` @@ -124,6 +133,13 @@ GOFILES=\ {.end} {.end} +{.section OFiles} +OFILES=\ +{.repeated section OFiles} + {@}\ +{.end} + +{.end} {.section CgoFiles} CGOFILES=\ {.repeated section CgoFiles} @@ -131,9 +147,9 @@ CGOFILES=\ {.end} {.end} -{.section OFiles} +{.section CgoOFiles} CGO_OFILES=\ -{.repeated section OFiles} +{.repeated section CgoOFiles} {@}\ {.end} diff --git a/src/cmd/goinstall/parse.go b/src/cmd/goinstall/parse.go index 014b8fcb2..0e617903c 100644 --- a/src/cmd/goinstall/parse.go +++ b/src/cmd/goinstall/parse.go @@ -14,6 +14,7 @@ import ( "path/filepath" "strconv" "strings" + "runtime" ) @@ -21,6 +22,7 @@ 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 } @@ -37,7 +39,7 @@ type dirInfo struct { // 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, os.O_RDONLY, 0) + f, err := os.Open(dir) if err != nil { return nil, err } @@ -50,6 +52,7 @@ func scanDir(dir string, allowMain bool) (info *dirInfo, err os.Error) { 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 { @@ -57,13 +60,25 @@ func scanDir(dir string, allowMain bool) (info *dirInfo, err os.Error) { if strings.HasPrefix(d.Name, "_") || strings.Index(d.Name, ".cgo") != -1 { continue } - if strings.HasSuffix(d.Name, ".c") { - cFiles = append(cFiles, d.Name) + if !goodOSArch(d.Name) { continue } - if !strings.HasSuffix(d.Name, ".go") || strings.HasSuffix(d.Name, "_test.go") { + + 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 { @@ -106,5 +121,49 @@ func scanDir(dir string, allowMain bool) (info *dirInfo, err os.Error) { imports[i] = p i++ } - return &dirInfo{goFiles, cgoFiles, cFiles, imports, pkgName}, nil + 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 + } } diff --git a/src/cmd/goinstall/syslist_test.go b/src/cmd/goinstall/syslist_test.go new file mode 100644 index 000000000..795cd293a --- /dev/null +++ b/src/cmd/goinstall/syslist_test.go @@ -0,0 +1,61 @@ +// 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) + } + } +} |