Skip to content

Commit

Permalink
go/build, cmd/go: don't expect gccgo to have GOROOT packages
Browse files Browse the repository at this point in the history
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: Than McIntosh <thanm@google.com>
  • Loading branch information
ianlancetaylor committed May 9, 2018
1 parent 814c749 commit d540da1
Show file tree
Hide file tree
Showing 4 changed files with 155 additions and 11 deletions.
5 changes: 5 additions & 0 deletions src/cmd/go/internal/test/test.go
Expand Up @@ -626,6 +626,11 @@ func runTest(cmd *base.Command, args []string) {

a := &work.Action{Mode: "go test -i"}
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))
}
b.Do(a)
Expand Down
35 changes: 24 additions & 11 deletions src/go/build/build.go
Expand Up @@ -238,7 +238,7 @@ func (ctxt *Context) gopath() []string {
// that do not exist.
func (ctxt *Context) SrcDirs() []string {
var all []string
if ctxt.GOROOT != "" {
if ctxt.GOROOT != "" && ctxt.Compiler != "gccgo" {
dir := ctxt.joinPath(ctxt.GOROOT, "src")
if ctxt.isDir(dir) {
all = append(all, dir)
Expand Down Expand Up @@ -538,7 +538,7 @@ func (ctxt *Context) Import(path string, srcDir string, mode ImportMode) (*Packa
inTestdata := func(sub string) bool {
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")
if sub, ok := ctxt.hasSubdir(root, p.Dir); ok && !inTestdata(sub) {
p.Goroot = true
Expand All @@ -555,7 +555,7 @@ func (ctxt *Context) Import(path string, srcDir string, mode ImportMode) (*Packa
// We found a potential import path for dir,
// but check that using it wouldn't find something
// else first.
if ctxt.GOROOT != "" {
if ctxt.GOROOT != "" && ctxt.Compiler != "gccgo" {
if dir := ctxt.joinPath(ctxt.GOROOT, "src", sub); ctxt.isDir(dir) {
p.ConflictDir = dir
goto Found
Expand Down Expand Up @@ -620,7 +620,7 @@ func (ctxt *Context) Import(path string, srcDir string, mode ImportMode) (*Packa
}
return false
}
if searchVendor(ctxt.GOROOT, true) {
if ctxt.Compiler != "gccgo" && searchVendor(ctxt.GOROOT, true) {
goto Found
}
for _, root := range gopath {
Expand All @@ -633,16 +633,24 @@ func (ctxt *Context) Import(path string, srcDir string, mode ImportMode) (*Packa
// Determine directory from import path.
if ctxt.GOROOT != "" {
dir := ctxt.joinPath(ctxt.GOROOT, "src", path)
isDir := ctxt.isDir(dir)
binaryOnly = !isDir && mode&AllowBinary != 0 && pkga != "" && ctxt.isFile(ctxt.joinPath(ctxt.GOROOT, pkga))
if isDir || binaryOnly {
p.Dir = dir
p.Goroot = true
p.Root = ctxt.GOROOT
goto Found
if ctxt.Compiler != "gccgo" {
isDir := ctxt.isDir(dir)
binaryOnly = !isDir && mode&AllowBinary != 0 && pkga != "" && ctxt.isFile(ctxt.joinPath(ctxt.GOROOT, pkga))
if isDir || binaryOnly {
p.Dir = dir
p.Goroot = true
p.Root = ctxt.GOROOT
goto Found
}
}
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 {
dir := ctxt.joinPath(root, "src", path)
isDir := ctxt.isDir(dir)
Expand Down Expand Up @@ -706,6 +714,11 @@ Found:
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)
if err != nil {
return p, err
Expand Down
120 changes: 120 additions & 0 deletions src/go/build/gc.go
Expand Up @@ -7,11 +7,131 @@
package build

import (
"os"
"os/exec"
"path/filepath"
"runtime"
"strings"
"sync"
)

// getToolDir returns the default value of ToolDir.
func getToolDir() string {
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
}
6 changes: 6 additions & 0 deletions src/go/build/gccgo.go
Expand Up @@ -12,3 +12,9 @@ import "runtime"
func getToolDir() string {
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]
}

0 comments on commit d540da1

Please sign in to comment.