github.com/octohelm/cuemod@v0.9.4/internal/internals/goroot/gc.go (about) 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 //go: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 info, err := os.Stat(dir) 24 return err == nil && info.IsDir() 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) + ".gox" 125 if fi, err := os.Stat(full); err == nil && !fi.IsDir() { 126 return true 127 } 128 } 129 130 return false 131 }