gitee.com/ks-custle/core-gm@v0.0.0-20230922171213-b83bdd97b62c/internal/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 // +build gc 7 8 package goroot 9 10 import ( 11 "os" 12 "path/filepath" 13 "strings" 14 "sync" 15 16 exec "gitee.com/ks-custle/core-gm/internal/execabs" 17 ) 18 19 // IsStandardPackage reports whether path is a standard package, 20 // given goroot and compiler. 21 func IsStandardPackage(goroot, compiler, path string) bool { 22 switch compiler { 23 case "gc": 24 dir := filepath.Join(goroot, "src", path) 25 _, err := os.Stat(dir) 26 return err == nil 27 case "gccgo": 28 return gccgoSearch.isStandard(path) 29 default: 30 panic("unknown compiler " + compiler) 31 } 32 } 33 34 // gccgoSearch holds the gccgo search directories. 35 type gccgoDirs struct { 36 once sync.Once 37 dirs []string 38 } 39 40 // gccgoSearch is used to check whether a gccgo package exists in the 41 // standard library. 42 var gccgoSearch gccgoDirs 43 44 // init finds the gccgo search directories. If this fails it leaves dirs == nil. 45 func (gd *gccgoDirs) init() { 46 gccgo := os.Getenv("GCCGO") 47 if gccgo == "" { 48 gccgo = "gccgo" 49 } 50 bin, err := exec.LookPath(gccgo) 51 if err != nil { 52 return 53 } 54 55 allDirs, err := exec.Command(bin, "-print-search-dirs").Output() 56 if err != nil { 57 return 58 } 59 versionB, err := exec.Command(bin, "-dumpversion").Output() 60 if err != nil { 61 return 62 } 63 version := strings.TrimSpace(string(versionB)) 64 machineB, err := exec.Command(bin, "-dumpmachine").Output() 65 if err != nil { 66 return 67 } 68 machine := strings.TrimSpace(string(machineB)) 69 70 dirsEntries := strings.Split(string(allDirs), "\n") 71 const prefix = "libraries: =" 72 var dirs []string 73 for _, dirEntry := range dirsEntries { 74 if strings.HasPrefix(dirEntry, prefix) { 75 dirs = filepath.SplitList(strings.TrimPrefix(dirEntry, prefix)) 76 break 77 } 78 } 79 if len(dirs) == 0 { 80 return 81 } 82 83 var lastDirs []string 84 for _, dir := range dirs { 85 goDir := filepath.Join(dir, "go", version) 86 if fi, err := os.Stat(goDir); err == nil && fi.IsDir() { 87 gd.dirs = append(gd.dirs, goDir) 88 goDir = filepath.Join(goDir, machine) 89 if fi, err = os.Stat(goDir); err == nil && fi.IsDir() { 90 gd.dirs = append(gd.dirs, goDir) 91 } 92 } 93 if fi, err := os.Stat(dir); err == nil && fi.IsDir() { 94 lastDirs = append(lastDirs, dir) 95 } 96 } 97 gd.dirs = append(gd.dirs, lastDirs...) 98 } 99 100 // isStandard reports whether path is a standard library for gccgo. 101 func (gd *gccgoDirs) isStandard(path string) bool { 102 // Quick check: if the first path component has a '.', it's not 103 // in the standard library. This skips most GOPATH directories. 104 i := strings.Index(path, "/") 105 if i < 0 { 106 i = len(path) 107 } 108 if strings.Contains(path[:i], ".") { 109 return false 110 } 111 112 if path == "unsafe" { 113 // Special case. 114 return true 115 } 116 117 gd.once.Do(gd.init) 118 if gd.dirs == nil { 119 // We couldn't find the gccgo search directories. 120 // Best guess, since the first component did not contain 121 // '.', is that this is a standard library package. 122 return true 123 } 124 125 for _, dir := range gd.dirs { 126 full := filepath.Join(dir, path) + ".gox" 127 if fi, err := os.Stat(full); err == nil && !fi.IsDir() { 128 return true 129 } 130 } 131 132 return false 133 }