1  
     2  
     3  
     4  
     5  
     6  
     7  package goroot
     8  
     9  import (
    10  	"os"
    11  	"os/exec"
    12  	"path/filepath"
    13  	"strings"
    14  	"sync"
    15  )
    16  
    17  
    18  
    19  func IsStandardPackage(goroot, compiler, path string) bool {
    20  	switch compiler {
    21  	case "gc":
    22  		dir := filepath.Join(goroot, "src", path)
    23  		dirents, err := os.ReadDir(dir)
    24  		if err != nil {
    25  			return false
    26  		}
    27  		for _, dirent := range dirents {
    28  			if strings.HasSuffix(dirent.Name(), ".go") {
    29  				return true
    30  			}
    31  		}
    32  		return false
    33  	case "gccgo":
    34  		return gccgoSearch.isStandard(path)
    35  	default:
    36  		panic("unknown compiler " + compiler)
    37  	}
    38  }
    39  
    40  
    41  type gccgoDirs struct {
    42  	once sync.Once
    43  	dirs []string
    44  }
    45  
    46  
    47  
    48  var gccgoSearch gccgoDirs
    49  
    50  
    51  func (gd *gccgoDirs) init() {
    52  	gccgo := os.Getenv("GCCGO")
    53  	if gccgo == "" {
    54  		gccgo = "gccgo"
    55  	}
    56  	bin, err := exec.LookPath(gccgo)
    57  	if err != nil {
    58  		return
    59  	}
    60  
    61  	allDirs, err := exec.Command(bin, "-print-search-dirs").Output()
    62  	if err != nil {
    63  		return
    64  	}
    65  	versionB, err := exec.Command(bin, "-dumpversion").Output()
    66  	if err != nil {
    67  		return
    68  	}
    69  	version := strings.TrimSpace(string(versionB))
    70  	machineB, err := exec.Command(bin, "-dumpmachine").Output()
    71  	if err != nil {
    72  		return
    73  	}
    74  	machine := strings.TrimSpace(string(machineB))
    75  
    76  	dirsEntries := strings.Split(string(allDirs), "\n")
    77  	const prefix = "libraries: ="
    78  	var dirs []string
    79  	for _, dirEntry := range dirsEntries {
    80  		if strings.HasPrefix(dirEntry, prefix) {
    81  			dirs = filepath.SplitList(strings.TrimPrefix(dirEntry, prefix))
    82  			break
    83  		}
    84  	}
    85  	if len(dirs) == 0 {
    86  		return
    87  	}
    88  
    89  	var lastDirs []string
    90  	for _, dir := range dirs {
    91  		goDir := filepath.Join(dir, "go", version)
    92  		if fi, err := os.Stat(goDir); err == nil && fi.IsDir() {
    93  			gd.dirs = append(gd.dirs, goDir)
    94  			goDir = filepath.Join(goDir, machine)
    95  			if fi, err = os.Stat(goDir); err == nil && fi.IsDir() {
    96  				gd.dirs = append(gd.dirs, goDir)
    97  			}
    98  		}
    99  		if fi, err := os.Stat(dir); err == nil && fi.IsDir() {
   100  			lastDirs = append(lastDirs, dir)
   101  		}
   102  	}
   103  	gd.dirs = append(gd.dirs, lastDirs...)
   104  }
   105  
   106  
   107  func (gd *gccgoDirs) isStandard(path string) bool {
   108  	
   109  	
   110  	i := strings.Index(path, "/")
   111  	if i < 0 {
   112  		i = len(path)
   113  	}
   114  	if strings.Contains(path[:i], ".") {
   115  		return false
   116  	}
   117  
   118  	if path == "unsafe" {
   119  		
   120  		return true
   121  	}
   122  
   123  	gd.once.Do(gd.init)
   124  	if gd.dirs == nil {
   125  		
   126  		
   127  		
   128  		return true
   129  	}
   130  
   131  	for _, dir := range gd.dirs {
   132  		full := filepath.Join(dir, path) + ".gox"
   133  		if fi, err := os.Stat(full); err == nil && !fi.IsDir() {
   134  			return true
   135  		}
   136  	}
   137  
   138  	return false
   139  }
   140  
View as plain text