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

go/build: move isStandardPackage to new internal/goroot package

The module code in cmd/go sometimes needs to know whether it is
looking at a standard package, and currently uses gc-specific code for
that. This CL moves the existing isStandardPackage code in the
go/build package, which works for both gc and gccgo, into a new
internal/goroot package so that cmd/go can call it. The changes to
cmd/go will be in a subsequent CL.

Change-Id: Ic1ce4c022a932c6b3e99fa062631577085cc6ecb
Reviewed-on: https://go-review.googlesource.com/137435
Run-TryBot: Ian Lance Taylor <iant@golang.org>
Reviewed-by: default avatarBrad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
parent 23f75541
......@@ -12,6 +12,7 @@ import (
"go/doc"
"go/parser"
"go/token"
"internal/goroot"
"io"
"io/ioutil"
"log"
......@@ -656,7 +657,7 @@ func (ctxt *Context) Import(path string, srcDir string, mode ImportMode) (*Packa
}
tried.goroot = dir
}
if ctxt.Compiler == "gccgo" && isStandardPackage(path) {
if ctxt.Compiler == "gccgo" && goroot.IsStandardPackage(ctxt.GOROOT, ctxt.Compiler, path) {
p.Dir = ctxt.joinPath(ctxt.GOROOT, "src", path)
p.Goroot = true
p.Root = ctxt.GOROOT
......
......@@ -258,7 +258,7 @@ var pkgDeps = map[string][]string{
"encoding/pem": {"L4"},
"encoding/xml": {"L4", "encoding"},
"flag": {"L4", "OS"},
"go/build": {"L4", "OS", "GOPARSER"},
"go/build": {"L4", "OS", "GOPARSER", "internal/goroot"},
"html": {"L4"},
"image/draw": {"L4", "image/internal/imageutil"},
"image/gif": {"L4", "compress/lzw", "image/color/palette", "image/draw"},
......@@ -266,6 +266,7 @@ var pkgDeps = map[string][]string{
"image/jpeg": {"L4", "image/internal/imageutil"},
"image/png": {"L4", "compress/zlib"},
"index/suffixarray": {"L4", "regexp"},
"internal/goroot": {"L4", "OS"},
"internal/singleflight": {"sync"},
"internal/trace": {"L4", "OS"},
"math/big": {"L4"},
......
......@@ -7,131 +7,11 @@
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
}
......@@ -12,9 +12,3 @@ 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]
}
// Copyright 2018 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.
// +build gc
package goroot
import (
"os"
"os/exec"
"path/filepath"
"strings"
"sync"
)
// IsStandardPackage returns whether path is a standard package,
// given goroot and compiler.
func IsStandardPackage(goroot, compiler, path string) bool {
switch compiler {
case "gc":
dir := filepath.Join(goroot, "src", path)
_, err := os.Stat(dir)
return err == nil
case "gccgo":
return gccgoSearch.isStandard(path)
default:
panic("unknown compiler " + compiler)
}
}
// 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
}
// Copyright 2018 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.
// +build gccgo
package goroot
import (
"os"
"path/filepath"
)
// IsStandardPackage returns whether path is a standard package,
// given goroot and compiler.
func IsStandardPackage(goroot, compiler, path string) bool {
switch compiler {
case "gc":
dir := filepath.Join(goroot, "src", path)
_, err := os.Stat(dir)
return err == nil
case "gccgo":
return stdpkg[path]
default:
panic("unknown compiler " + compiler)
}
}
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