]> git.ipfire.org Git - thirdparty/gcc.git/blob - libgo/go/cmd/go/internal/modload/build.go
libgo: update to final 1.14.2 release
[thirdparty/gcc.git] / libgo / go / cmd / go / internal / modload / build.go
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 package modload
6
7 import (
8 "bytes"
9 "encoding/hex"
10 "fmt"
11 "internal/goroot"
12 "os"
13 "path/filepath"
14 "runtime/debug"
15 "strings"
16
17 "cmd/go/internal/base"
18 "cmd/go/internal/cfg"
19 "cmd/go/internal/modfetch"
20 "cmd/go/internal/modinfo"
21 "cmd/go/internal/search"
22
23 "golang.org/x/mod/module"
24 "golang.org/x/mod/semver"
25 )
26
27 var (
28 infoStart, _ = hex.DecodeString("3077af0c9274080241e1c107e6d618e6")
29 infoEnd, _ = hex.DecodeString("f932433186182072008242104116d8f2")
30 )
31
32 func isStandardImportPath(path string) bool {
33 return findStandardImportPath(path) != ""
34 }
35
36 func findStandardImportPath(path string) string {
37 if path == "" {
38 panic("findStandardImportPath called with empty path")
39 }
40 if search.IsStandardImportPath(path) {
41 if goroot.IsStandardPackage(cfg.GOROOT, cfg.BuildContext.Compiler, path) {
42 return filepath.Join(cfg.GOROOT, "src", path)
43 }
44 }
45 return ""
46 }
47
48 // PackageModuleInfo returns information about the module that provides
49 // a given package. If modules are not enabled or if the package is in the
50 // standard library or if the package was not successfully loaded with
51 // ImportPaths or a similar loading function, nil is returned.
52 func PackageModuleInfo(pkgpath string) *modinfo.ModulePublic {
53 if isStandardImportPath(pkgpath) || !Enabled() {
54 return nil
55 }
56 m, ok := findModule(pkgpath)
57 if !ok {
58 return nil
59 }
60 return moduleInfo(m, true)
61 }
62
63 func ModuleInfo(path string) *modinfo.ModulePublic {
64 if !Enabled() {
65 return nil
66 }
67
68 if i := strings.Index(path, "@"); i >= 0 {
69 return moduleInfo(module.Version{Path: path[:i], Version: path[i+1:]}, false)
70 }
71
72 for _, m := range BuildList() {
73 if m.Path == path {
74 return moduleInfo(m, true)
75 }
76 }
77
78 return &modinfo.ModulePublic{
79 Path: path,
80 Error: &modinfo.ModuleError{
81 Err: "module not in current build",
82 },
83 }
84 }
85
86 // addUpdate fills in m.Update if an updated version is available.
87 func addUpdate(m *modinfo.ModulePublic) {
88 if m.Version == "" {
89 return
90 }
91
92 if info, err := Query(m.Path, "upgrade", m.Version, Allowed); err == nil && semver.Compare(info.Version, m.Version) > 0 {
93 m.Update = &modinfo.ModulePublic{
94 Path: m.Path,
95 Version: info.Version,
96 Time: &info.Time,
97 }
98 }
99 }
100
101 // addVersions fills in m.Versions with the list of known versions.
102 func addVersions(m *modinfo.ModulePublic) {
103 m.Versions, _ = versions(m.Path)
104 }
105
106 func moduleInfo(m module.Version, fromBuildList bool) *modinfo.ModulePublic {
107 if m == Target {
108 info := &modinfo.ModulePublic{
109 Path: m.Path,
110 Version: m.Version,
111 Main: true,
112 }
113 if HasModRoot() {
114 info.Dir = ModRoot()
115 info.GoMod = ModFilePath()
116 if modFile.Go != nil {
117 info.GoVersion = modFile.Go.Version
118 }
119 }
120 return info
121 }
122
123 info := &modinfo.ModulePublic{
124 Path: m.Path,
125 Version: m.Version,
126 Indirect: fromBuildList && loaded != nil && !loaded.direct[m.Path],
127 }
128 if loaded != nil {
129 info.GoVersion = loaded.goVersion[m.Path]
130 }
131
132 // completeFromModCache fills in the extra fields in m using the module cache.
133 completeFromModCache := func(m *modinfo.ModulePublic) {
134 if m.Version != "" {
135 if q, err := Query(m.Path, m.Version, "", nil); err != nil {
136 m.Error = &modinfo.ModuleError{Err: err.Error()}
137 } else {
138 m.Version = q.Version
139 m.Time = &q.Time
140 }
141
142 mod := module.Version{Path: m.Path, Version: m.Version}
143 gomod, err := modfetch.CachePath(mod, "mod")
144 if err == nil {
145 if info, err := os.Stat(gomod); err == nil && info.Mode().IsRegular() {
146 m.GoMod = gomod
147 }
148 }
149 dir, err := modfetch.DownloadDir(mod)
150 if err == nil {
151 m.Dir = dir
152 }
153 }
154 }
155
156 if !fromBuildList {
157 completeFromModCache(info) // Will set m.Error in vendor mode.
158 return info
159 }
160
161 r := Replacement(m)
162 if r.Path == "" {
163 if cfg.BuildMod == "vendor" {
164 // It's tempting to fill in the "Dir" field to point within the vendor
165 // directory, but that would be misleading: the vendor directory contains
166 // a flattened package tree, not complete modules, and it can even
167 // interleave packages from different modules if one module path is a
168 // prefix of the other.
169 } else {
170 completeFromModCache(info)
171 }
172 return info
173 }
174
175 // Don't hit the network to fill in extra data for replaced modules.
176 // The original resolved Version and Time don't matter enough to be
177 // worth the cost, and we're going to overwrite the GoMod and Dir from the
178 // replacement anyway. See https://golang.org/issue/27859.
179 info.Replace = &modinfo.ModulePublic{
180 Path: r.Path,
181 Version: r.Version,
182 GoVersion: info.GoVersion,
183 }
184 if r.Version == "" {
185 if filepath.IsAbs(r.Path) {
186 info.Replace.Dir = r.Path
187 } else {
188 info.Replace.Dir = filepath.Join(ModRoot(), r.Path)
189 }
190 info.Replace.GoMod = filepath.Join(info.Replace.Dir, "go.mod")
191 }
192 if cfg.BuildMod != "vendor" {
193 completeFromModCache(info.Replace)
194 info.Dir = info.Replace.Dir
195 info.GoMod = info.Replace.GoMod
196 }
197 return info
198 }
199
200 // PackageBuildInfo returns a string containing module version information
201 // for modules providing packages named by path and deps. path and deps must
202 // name packages that were resolved successfully with ImportPaths or one of
203 // the Load functions.
204 func PackageBuildInfo(path string, deps []string) string {
205 if isStandardImportPath(path) || !Enabled() {
206 return ""
207 }
208 target := mustFindModule(path, path)
209 mdeps := make(map[module.Version]bool)
210 for _, dep := range deps {
211 if !isStandardImportPath(dep) {
212 mdeps[mustFindModule(path, dep)] = true
213 }
214 }
215 var mods []module.Version
216 delete(mdeps, target)
217 for mod := range mdeps {
218 mods = append(mods, mod)
219 }
220 module.Sort(mods)
221
222 var buf bytes.Buffer
223 fmt.Fprintf(&buf, "path\t%s\n", path)
224 tv := target.Version
225 if tv == "" {
226 tv = "(devel)"
227 }
228 fmt.Fprintf(&buf, "mod\t%s\t%s\t%s\n", target.Path, tv, modfetch.Sum(target))
229 for _, mod := range mods {
230 mv := mod.Version
231 if mv == "" {
232 mv = "(devel)"
233 }
234 r := Replacement(mod)
235 h := ""
236 if r.Path == "" {
237 h = "\t" + modfetch.Sum(mod)
238 }
239 fmt.Fprintf(&buf, "dep\t%s\t%s%s\n", mod.Path, mv, h)
240 if r.Path != "" {
241 fmt.Fprintf(&buf, "=>\t%s\t%s\t%s\n", r.Path, r.Version, modfetch.Sum(r))
242 }
243 }
244 return buf.String()
245 }
246
247 // mustFindModule is like findModule, but it calls base.Fatalf if the
248 // module can't be found.
249 //
250 // TODO(jayconrod): remove this. Callers should use findModule and return
251 // errors instead of relying on base.Fatalf.
252 func mustFindModule(target, path string) module.Version {
253 pkg, ok := loaded.pkgCache.Get(path).(*loadPkg)
254 if ok {
255 if pkg.err != nil {
256 base.Fatalf("build %v: cannot load %v: %v", target, path, pkg.err)
257 }
258 return pkg.mod
259 }
260
261 if path == "command-line-arguments" {
262 return Target
263 }
264
265 if printStackInDie {
266 debug.PrintStack()
267 }
268 base.Fatalf("build %v: cannot find module for path %v", target, path)
269 panic("unreachable")
270 }
271
272 // findModule searches for the module that contains the package at path.
273 // If the package was loaded with ImportPaths or one of the other loading
274 // functions, its containing module and true are returned. Otherwise,
275 // module.Version{} and false are returend.
276 func findModule(path string) (module.Version, bool) {
277 if pkg, ok := loaded.pkgCache.Get(path).(*loadPkg); ok {
278 return pkg.mod, pkg.mod != module.Version{}
279 }
280 if path == "command-line-arguments" {
281 return Target, true
282 }
283 return module.Version{}, false
284 }
285
286 func ModInfoProg(info string, isgccgo bool) []byte {
287 // Inject a variable with the debug information as runtime.modinfo,
288 // but compile it in package main so that it is specific to the binary.
289 // The variable must be a literal so that it will have the correct value
290 // before the initializer for package main runs.
291 //
292 // The runtime startup code refers to the variable, which keeps it live
293 // in all binaries.
294 //
295 // Note: we use an alternate recipe below for gccgo (based on an
296 // init function) due to the fact that gccgo does not support
297 // applying a "//go:linkname" directive to a variable. This has
298 // drawbacks in that other packages may want to look at the module
299 // info in their init functions (see issue 29628), which won't
300 // work for gccgo. See also issue 30344.
301
302 if !isgccgo {
303 return []byte(fmt.Sprintf(`package main
304 import _ "unsafe"
305 //go:linkname __set_modinfo__ runtime.setmodinfo
306 func __set_modinfo__(string)
307 func init() { __set_modinfo__(%q) }
308 `, string(infoStart)+info+string(infoEnd)))
309 } else {
310 return []byte(fmt.Sprintf(`package main
311 import _ "unsafe"
312 //go:linkname __set_debug_modinfo__ runtime.setmodinfo
313 func __set_debug_modinfo__(string)
314 func init() { __set_debug_modinfo__(%q) }
315 `, string(infoStart)+info+string(infoEnd)))
316 }
317 }