// 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)
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
// 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
}
return false
}
- if searchVendor(ctxt.GOROOT, true) {
+ if ctxt.Compiler != "gccgo" && searchVendor(ctxt.GOROOT, true) {
goto Found
}
for _, root := range gopath {
// 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)
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
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
+}