Commit d540da10 authored by Ian Lance Taylor's avatar Ian Lance Taylor

go/build, cmd/go: don't expect gccgo to have GOROOT packages

When using gccgo the standard library sources are not available in
GOROOT. Don't expect them to be there. In the gccgo build, use a set
of standard library packages generated at build time.

Change-Id: Id133022604d9b7e778e73e8512f9080c61462fba
Reviewed-on: https://go-review.googlesource.com/111595
Run-TryBot: Ian Lance Taylor <iant@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: default avatarThan McIntosh <thanm@google.com>
parent 814c749c
...@@ -626,6 +626,11 @@ func runTest(cmd *base.Command, args []string) { ...@@ -626,6 +626,11 @@ func runTest(cmd *base.Command, args []string) {
a := &work.Action{Mode: "go test -i"} a := &work.Action{Mode: "go test -i"}
for _, p := range load.PackagesForBuild(all) { for _, p := range load.PackagesForBuild(all) {
if cfg.BuildToolchainName == "gccgo" && p.Standard {
// gccgo's standard library packages
// can not be reinstalled.
continue
}
a.Deps = append(a.Deps, b.CompileAction(work.ModeInstall, work.ModeInstall, p)) a.Deps = append(a.Deps, b.CompileAction(work.ModeInstall, work.ModeInstall, p))
} }
b.Do(a) b.Do(a)
......
...@@ -238,7 +238,7 @@ func (ctxt *Context) gopath() []string { ...@@ -238,7 +238,7 @@ func (ctxt *Context) gopath() []string {
// that do not exist. // that do not exist.
func (ctxt *Context) SrcDirs() []string { func (ctxt *Context) SrcDirs() []string {
var all []string var all []string
if ctxt.GOROOT != "" { if ctxt.GOROOT != "" && ctxt.Compiler != "gccgo" {
dir := ctxt.joinPath(ctxt.GOROOT, "src") dir := ctxt.joinPath(ctxt.GOROOT, "src")
if ctxt.isDir(dir) { if ctxt.isDir(dir) {
all = append(all, dir) all = append(all, dir)
...@@ -538,7 +538,7 @@ func (ctxt *Context) Import(path string, srcDir string, mode ImportMode) (*Packa ...@@ -538,7 +538,7 @@ func (ctxt *Context) Import(path string, srcDir string, mode ImportMode) (*Packa
inTestdata := func(sub string) bool { inTestdata := func(sub string) bool {
return strings.Contains(sub, "/testdata/") || strings.HasSuffix(sub, "/testdata") || strings.HasPrefix(sub, "testdata/") || sub == "testdata" return strings.Contains(sub, "/testdata/") || strings.HasSuffix(sub, "/testdata") || strings.HasPrefix(sub, "testdata/") || sub == "testdata"
} }
if ctxt.GOROOT != "" { if ctxt.GOROOT != "" && ctxt.Compiler != "gccgo" {
root := ctxt.joinPath(ctxt.GOROOT, "src") root := ctxt.joinPath(ctxt.GOROOT, "src")
if sub, ok := ctxt.hasSubdir(root, p.Dir); ok && !inTestdata(sub) { if sub, ok := ctxt.hasSubdir(root, p.Dir); ok && !inTestdata(sub) {
p.Goroot = true p.Goroot = true
...@@ -555,7 +555,7 @@ func (ctxt *Context) Import(path string, srcDir string, mode ImportMode) (*Packa ...@@ -555,7 +555,7 @@ func (ctxt *Context) Import(path string, srcDir string, mode ImportMode) (*Packa
// We found a potential import path for dir, // We found a potential import path for dir,
// but check that using it wouldn't find something // but check that using it wouldn't find something
// else first. // else first.
if ctxt.GOROOT != "" { if ctxt.GOROOT != "" && ctxt.Compiler != "gccgo" {
if dir := ctxt.joinPath(ctxt.GOROOT, "src", sub); ctxt.isDir(dir) { if dir := ctxt.joinPath(ctxt.GOROOT, "src", sub); ctxt.isDir(dir) {
p.ConflictDir = dir p.ConflictDir = dir
goto Found goto Found
...@@ -620,7 +620,7 @@ func (ctxt *Context) Import(path string, srcDir string, mode ImportMode) (*Packa ...@@ -620,7 +620,7 @@ func (ctxt *Context) Import(path string, srcDir string, mode ImportMode) (*Packa
} }
return false return false
} }
if searchVendor(ctxt.GOROOT, true) { if ctxt.Compiler != "gccgo" && searchVendor(ctxt.GOROOT, true) {
goto Found goto Found
} }
for _, root := range gopath { for _, root := range gopath {
...@@ -633,16 +633,24 @@ func (ctxt *Context) Import(path string, srcDir string, mode ImportMode) (*Packa ...@@ -633,16 +633,24 @@ func (ctxt *Context) Import(path string, srcDir string, mode ImportMode) (*Packa
// Determine directory from import path. // Determine directory from import path.
if ctxt.GOROOT != "" { if ctxt.GOROOT != "" {
dir := ctxt.joinPath(ctxt.GOROOT, "src", path) dir := ctxt.joinPath(ctxt.GOROOT, "src", path)
isDir := ctxt.isDir(dir) if ctxt.Compiler != "gccgo" {
binaryOnly = !isDir && mode&AllowBinary != 0 && pkga != "" && ctxt.isFile(ctxt.joinPath(ctxt.GOROOT, pkga)) isDir := ctxt.isDir(dir)
if isDir || binaryOnly { binaryOnly = !isDir && mode&AllowBinary != 0 && pkga != "" && ctxt.isFile(ctxt.joinPath(ctxt.GOROOT, pkga))
p.Dir = dir if isDir || binaryOnly {
p.Goroot = true p.Dir = dir
p.Root = ctxt.GOROOT p.Goroot = true
goto Found p.Root = ctxt.GOROOT
goto Found
}
} }
tried.goroot = dir tried.goroot = dir
} }
if ctxt.Compiler == "gccgo" && isStandardPackage(path) {
p.Dir = ctxt.joinPath(ctxt.GOROOT, "src", path)
p.Goroot = true
p.Root = ctxt.GOROOT
goto Found
}
for _, root := range gopath { for _, root := range gopath {
dir := ctxt.joinPath(root, "src", path) dir := ctxt.joinPath(root, "src", path)
isDir := ctxt.isDir(dir) isDir := ctxt.isDir(dir)
...@@ -706,6 +714,11 @@ Found: ...@@ -706,6 +714,11 @@ Found:
return p, pkgerr return p, pkgerr
} }
if ctxt.Compiler == "gccgo" && p.Goroot {
// gccgo has no sources for GOROOT packages.
return p, nil
}
dirs, err := ctxt.readDir(p.Dir) dirs, err := ctxt.readDir(p.Dir)
if err != nil { if err != nil {
return p, err return p, err
......
...@@ -7,11 +7,131 @@ ...@@ -7,11 +7,131 @@
package build package build
import ( import (
"os"
"os/exec"
"path/filepath" "path/filepath"
"runtime" "runtime"
"strings"
"sync"
) )
// getToolDir returns the default value of ToolDir. // getToolDir returns the default value of ToolDir.
func getToolDir() string { func getToolDir() string {
return filepath.Join(runtime.GOROOT(), "pkg/tool/"+runtime.GOOS+"_"+runtime.GOARCH) return filepath.Join(runtime.GOROOT(), "pkg/tool/"+runtime.GOOS+"_"+runtime.GOARCH)
} }
// isStandardPackage is not used for the gc toolchain.
// However, this function may be called when using `go build -compiler=gccgo`.
func isStandardPackage(path string) bool {
return gccgoSearch.isStandard(path)
}
// gccgoSearch holds the gccgo search directories.
type gccgoDirs struct {
once sync.Once
dirs []string
}
// gccgoSearch is used to check whether a gccgo package exists in the
// standard library.
var gccgoSearch gccgoDirs
// init finds the gccgo search directories. If this fails it leaves dirs == nil.
func (gd *gccgoDirs) init() {
gccgo := os.Getenv("GCCGO")
if gccgo == "" {
gccgo = "gccgo"
}
bin, err := exec.LookPath(gccgo)
if err != nil {
return
}
allDirs, err := exec.Command(bin, "-print-search-dirs").Output()
if err != nil {
return
}
versionB, err := exec.Command(bin, "-dumpversion").Output()
if err != nil {
return
}
version := strings.TrimSpace(string(versionB))
machineB, err := exec.Command(bin, "-dumpmachine").Output()
if err != nil {
return
}
machine := strings.TrimSpace(string(machineB))
dirsEntries := strings.Split(string(allDirs), "\n")
const prefix = "libraries: ="
var dirs []string
for _, dirEntry := range dirsEntries {
if strings.HasPrefix(dirEntry, prefix) {
dirs = filepath.SplitList(strings.TrimPrefix(dirEntry, prefix))
break
}
}
if len(dirs) == 0 {
return
}
var lastDirs []string
for _, dir := range dirs {
goDir := filepath.Join(dir, "go", version)
if fi, err := os.Stat(goDir); err == nil && fi.IsDir() {
gd.dirs = append(gd.dirs, goDir)
goDir = filepath.Join(goDir, machine)
if fi, err = os.Stat(goDir); err == nil && fi.IsDir() {
gd.dirs = append(gd.dirs, goDir)
}
}
if fi, err := os.Stat(dir); err == nil && fi.IsDir() {
lastDirs = append(lastDirs, dir)
}
}
gd.dirs = append(gd.dirs, lastDirs...)
}
// isStandard returns whether path is a standard library for gccgo.
func (gd *gccgoDirs) isStandard(path string) bool {
// Quick check: if the first path component has a '.', it's not
// in the standard library. This skips most GOPATH directories.
i := strings.Index(path, "/")
if i < 0 {
i = len(path)
}
if strings.Contains(path[:i], ".") {
return false
}
if path == "unsafe" {
// Special case.
return true
}
gd.once.Do(gd.init)
if gd.dirs == nil {
// We couldn't find the gccgo search directories.
// Best guess, since the first component did not contain
// '.', is that this is a standard library package.
return true
}
for _, dir := range gd.dirs {
full := filepath.Join(dir, path)
pkgdir, pkg := filepath.Split(full)
for _, p := range [...]string{
full,
full + ".gox",
pkgdir + "lib" + pkg + ".so",
pkgdir + "lib" + pkg + ".a",
full + ".o",
} {
if fi, err := os.Stat(p); err == nil && !fi.IsDir() {
return true
}
}
}
return false
}
...@@ -12,3 +12,9 @@ import "runtime" ...@@ -12,3 +12,9 @@ import "runtime"
func getToolDir() string { func getToolDir() string {
return envOr("GCCGOTOOLDIR", runtime.GCCGOTOOLDIR) return envOr("GCCGOTOOLDIR", runtime.GCCGOTOOLDIR)
} }
// isStandardPackage returns whether path names a standard library package.
// This uses a list generated at build time.
func isStandardPackage(path string) bool {
return stdpkg[path]
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment