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