summaryrefslogtreecommitdiff
path: root/src/cmd/goinstall
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd/goinstall')
-rw-r--r--src/cmd/goinstall/Makefile15
-rw-r--r--src/cmd/goinstall/doc.go1
-rw-r--r--src/cmd/goinstall/main.go2
-rw-r--r--src/cmd/goinstall/make.go56
-rw-r--r--src/cmd/goinstall/parse.go69
-rw-r--r--src/cmd/goinstall/syslist_test.go61
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)
+ }
+ }
+}