...

Source file src/internal/goroot/gc.go

     1	// Copyright 2018 The Go Authors. All rights reserved.
     2	// Use of this source code is governed by a BSD-style
     3	// license that can be found in the LICENSE file.
     4	
     5	// +build gc
     6	
     7	package goroot
     8	
     9	import (
    10		"os"
    11		"os/exec"
    12		"path/filepath"
    13		"strings"
    14		"sync"
    15	)
    16	
    17	// IsStandardPackage reports whether path is a standard package,
    18	// given goroot and compiler.
    19	func IsStandardPackage(goroot, compiler, path string) bool {
    20		switch compiler {
    21		case "gc":
    22			dir := filepath.Join(goroot, "src", path)
    23			_, err := os.Stat(dir)
    24			return err == nil
    25		case "gccgo":
    26			return gccgoSearch.isStandard(path)
    27		default:
    28			panic("unknown compiler " + compiler)
    29		}
    30	}
    31	
    32	// gccgoSearch holds the gccgo search directories.
    33	type gccgoDirs struct {
    34		once sync.Once
    35		dirs []string
    36	}
    37	
    38	// gccgoSearch is used to check whether a gccgo package exists in the
    39	// standard library.
    40	var gccgoSearch gccgoDirs
    41	
    42	// init finds the gccgo search directories. If this fails it leaves dirs == nil.
    43	func (gd *gccgoDirs) init() {
    44		gccgo := os.Getenv("GCCGO")
    45		if gccgo == "" {
    46			gccgo = "gccgo"
    47		}
    48		bin, err := exec.LookPath(gccgo)
    49		if err != nil {
    50			return
    51		}
    52	
    53		allDirs, err := exec.Command(bin, "-print-search-dirs").Output()
    54		if err != nil {
    55			return
    56		}
    57		versionB, err := exec.Command(bin, "-dumpversion").Output()
    58		if err != nil {
    59			return
    60		}
    61		version := strings.TrimSpace(string(versionB))
    62		machineB, err := exec.Command(bin, "-dumpmachine").Output()
    63		if err != nil {
    64			return
    65		}
    66		machine := strings.TrimSpace(string(machineB))
    67	
    68		dirsEntries := strings.Split(string(allDirs), "\n")
    69		const prefix = "libraries: ="
    70		var dirs []string
    71		for _, dirEntry := range dirsEntries {
    72			if strings.HasPrefix(dirEntry, prefix) {
    73				dirs = filepath.SplitList(strings.TrimPrefix(dirEntry, prefix))
    74				break
    75			}
    76		}
    77		if len(dirs) == 0 {
    78			return
    79		}
    80	
    81		var lastDirs []string
    82		for _, dir := range dirs {
    83			goDir := filepath.Join(dir, "go", version)
    84			if fi, err := os.Stat(goDir); err == nil && fi.IsDir() {
    85				gd.dirs = append(gd.dirs, goDir)
    86				goDir = filepath.Join(goDir, machine)
    87				if fi, err = os.Stat(goDir); err == nil && fi.IsDir() {
    88					gd.dirs = append(gd.dirs, goDir)
    89				}
    90			}
    91			if fi, err := os.Stat(dir); err == nil && fi.IsDir() {
    92				lastDirs = append(lastDirs, dir)
    93			}
    94		}
    95		gd.dirs = append(gd.dirs, lastDirs...)
    96	}
    97	
    98	// isStandard reports whether path is a standard library for gccgo.
    99	func (gd *gccgoDirs) isStandard(path string) bool {
   100		// Quick check: if the first path component has a '.', it's not
   101		// in the standard library. This skips most GOPATH directories.
   102		i := strings.Index(path, "/")
   103		if i < 0 {
   104			i = len(path)
   105		}
   106		if strings.Contains(path[:i], ".") {
   107			return false
   108		}
   109	
   110		if path == "unsafe" {
   111			// Special case.
   112			return true
   113		}
   114	
   115		gd.once.Do(gd.init)
   116		if gd.dirs == nil {
   117			// We couldn't find the gccgo search directories.
   118			// Best guess, since the first component did not contain
   119			// '.', is that this is a standard library package.
   120			return true
   121		}
   122	
   123		for _, dir := range gd.dirs {
   124			full := filepath.Join(dir, path)
   125			pkgdir, pkg := filepath.Split(full)
   126			for _, p := range [...]string{
   127				full,
   128				full + ".gox",
   129				pkgdir + "lib" + pkg + ".so",
   130				pkgdir + "lib" + pkg + ".a",
   131				full + ".o",
   132			} {
   133				if fi, err := os.Stat(p); err == nil && !fi.IsDir() {
   134					return true
   135				}
   136			}
   137		}
   138	
   139		return false
   140	}
   141	

View as plain text