1
2
3
4
5
6
7 package goroot
8
9 import (
10 exec "internal/execabs"
11 "os"
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 _, 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
33 type gccgoDirs struct {
34 once sync.Once
35 dirs []string
36 }
37
38
39
40 var gccgoSearch gccgoDirs
41
42
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
99 func (gd *gccgoDirs) isStandard(path string) bool {
100
101
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
112 return true
113 }
114
115 gd.once.Do(gd.init)
116 if gd.dirs == nil {
117
118
119
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 }
132
View as plain text