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