]> Cypherpunks.ru repositories - gostls13.git/blob - src/cmd/dist/buildtool.go
cmd/go: add check for unknown godebug setting
[gostls13.git] / src / cmd / dist / buildtool.go
1 // Copyright 2015 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 // Build toolchain using Go bootstrap version.
6 //
7 // The general strategy is to copy the source files we need into
8 // a new GOPATH workspace, adjust import paths appropriately,
9 // invoke the Go bootstrap toolchains go command to build those sources,
10 // and then copy the binaries back.
11
12 package main
13
14 import (
15         "fmt"
16         "os"
17         "path/filepath"
18         "regexp"
19         "strings"
20 )
21
22 // bootstrapDirs is a list of directories holding code that must be
23 // compiled with the Go bootstrap toolchain to produce the bootstrapTargets.
24 // All directories in this list are relative to and must be below $GOROOT/src.
25 //
26 // The list has two kinds of entries: names beginning with cmd/ with
27 // no other slashes, which are commands, and other paths, which are packages
28 // supporting the commands. Packages in the standard library can be listed
29 // if a newer copy needs to be substituted for the Go bootstrap copy when used
30 // by the command packages. Paths ending with /... automatically
31 // include all packages within subdirectories as well.
32 // These will be imported during bootstrap as bootstrap/name, like bootstrap/math/big.
33 var bootstrapDirs = []string{
34         "cmd/asm",
35         "cmd/asm/internal/...",
36         "cmd/cgo",
37         "cmd/compile",
38         "cmd/compile/internal/...",
39         "cmd/internal/archive",
40         "cmd/internal/bio",
41         "cmd/internal/codesign",
42         "cmd/internal/dwarf",
43         "cmd/internal/edit",
44         "cmd/internal/gcprog",
45         "cmd/internal/goobj",
46         "cmd/internal/notsha256",
47         "cmd/internal/obj/...",
48         "cmd/internal/objabi",
49         "cmd/internal/pkgpath",
50         "cmd/internal/quoted",
51         "cmd/internal/src",
52         "cmd/internal/sys",
53         "cmd/link",
54         "cmd/link/internal/...",
55         "compress/flate",
56         "compress/zlib",
57         "container/heap",
58         "debug/dwarf",
59         "debug/elf",
60         "debug/macho",
61         "debug/pe",
62         "go/build/constraint",
63         "go/constant",
64         "internal/abi",
65         "internal/coverage",
66         "internal/buildcfg",
67         "internal/goarch",
68         "internal/godebugs",
69         "internal/goexperiment",
70         "internal/goroot",
71         "internal/goversion",
72         "internal/pkgbits",
73         "internal/platform",
74         "internal/profile",
75         "internal/race",
76         "internal/saferio",
77         "internal/syscall/unix",
78         "internal/types/errors",
79         "internal/unsafeheader",
80         "internal/xcoff",
81         "math/big",
82         "math/bits",
83         "sort",
84         "strconv",
85 }
86
87 // File prefixes that are ignored by go/build anyway, and cause
88 // problems with editor generated temporary files (#18931).
89 var ignorePrefixes = []string{
90         ".",
91         "_",
92         "#",
93 }
94
95 // File suffixes that use build tags introduced since Go 1.17.
96 // These must not be copied into the bootstrap build directory.
97 // Also ignore test files.
98 var ignoreSuffixes = []string{
99         "_test.s",
100         "_test.go",
101 }
102
103 var tryDirs = []string{
104         "sdk/go1.17",
105         "go1.17",
106 }
107
108 func bootstrapBuildTools() {
109         goroot_bootstrap := os.Getenv("GOROOT_BOOTSTRAP")
110         if goroot_bootstrap == "" {
111                 home := os.Getenv("HOME")
112                 goroot_bootstrap = pathf("%s/go1.4", home)
113                 for _, d := range tryDirs {
114                         if p := pathf("%s/%s", home, d); isdir(p) {
115                                 goroot_bootstrap = p
116                         }
117                 }
118         }
119         xprintf("Building Go toolchain1 using %s.\n", goroot_bootstrap)
120
121         mkbuildcfg(pathf("%s/src/internal/buildcfg/zbootstrap.go", goroot))
122         mkobjabi(pathf("%s/src/cmd/internal/objabi/zbootstrap.go", goroot))
123
124         // Use $GOROOT/pkg/bootstrap as the bootstrap workspace root.
125         // We use a subdirectory of $GOROOT/pkg because that's the
126         // space within $GOROOT where we store all generated objects.
127         // We could use a temporary directory outside $GOROOT instead,
128         // but it is easier to debug on failure if the files are in a known location.
129         workspace := pathf("%s/pkg/bootstrap", goroot)
130         xremoveall(workspace)
131         xatexit(func() { xremoveall(workspace) })
132         base := pathf("%s/src/bootstrap", workspace)
133         xmkdirall(base)
134
135         // Copy source code into $GOROOT/pkg/bootstrap and rewrite import paths.
136         writefile("module bootstrap\n", pathf("%s/%s", base, "go.mod"), 0)
137         for _, dir := range bootstrapDirs {
138                 recurse := strings.HasSuffix(dir, "/...")
139                 dir = strings.TrimSuffix(dir, "/...")
140                 filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
141                         if err != nil {
142                                 fatalf("walking bootstrap dirs failed: %v: %v", path, err)
143                         }
144
145                         name := filepath.Base(path)
146                         src := pathf("%s/src/%s", goroot, path)
147                         dst := pathf("%s/%s", base, path)
148
149                         if info.IsDir() {
150                                 if !recurse && path != dir || name == "testdata" {
151                                         return filepath.SkipDir
152                                 }
153
154                                 xmkdirall(dst)
155                                 if path == "cmd/cgo" {
156                                         // Write to src because we need the file both for bootstrap
157                                         // and for later in the main build.
158                                         mkzdefaultcc("", pathf("%s/zdefaultcc.go", src))
159                                         mkzdefaultcc("", pathf("%s/zdefaultcc.go", dst))
160                                 }
161                                 return nil
162                         }
163
164                         for _, pre := range ignorePrefixes {
165                                 if strings.HasPrefix(name, pre) {
166                                         return nil
167                                 }
168                         }
169                         for _, suf := range ignoreSuffixes {
170                                 if strings.HasSuffix(name, suf) {
171                                         return nil
172                                 }
173                         }
174
175                         text := bootstrapRewriteFile(src)
176                         writefile(text, dst, 0)
177                         return nil
178                 })
179         }
180
181         // Set up environment for invoking Go bootstrap toolchains go command.
182         // GOROOT points at Go bootstrap GOROOT,
183         // GOPATH points at our bootstrap workspace,
184         // GOBIN is empty, so that binaries are installed to GOPATH/bin,
185         // and GOOS, GOHOSTOS, GOARCH, and GOHOSTOS are empty,
186         // so that Go bootstrap toolchain builds whatever kind of binary it knows how to build.
187         // Restore GOROOT, GOPATH, and GOBIN when done.
188         // Don't bother with GOOS, GOHOSTOS, GOARCH, and GOHOSTARCH,
189         // because setup will take care of those when bootstrapBuildTools returns.
190
191         defer os.Setenv("GOROOT", os.Getenv("GOROOT"))
192         os.Setenv("GOROOT", goroot_bootstrap)
193
194         defer os.Setenv("GOPATH", os.Getenv("GOPATH"))
195         os.Setenv("GOPATH", workspace)
196
197         defer os.Setenv("GOBIN", os.Getenv("GOBIN"))
198         os.Setenv("GOBIN", "")
199
200         os.Setenv("GOOS", "")
201         os.Setenv("GOHOSTOS", "")
202         os.Setenv("GOARCH", "")
203         os.Setenv("GOHOSTARCH", "")
204
205         // Run Go bootstrap to build binaries.
206         // Use the math_big_pure_go build tag to disable the assembly in math/big
207         // which may contain unsupported instructions.
208         // Use the purego build tag to disable other assembly code,
209         // such as in cmd/internal/notsha256.
210         cmd := []string{
211                 pathf("%s/bin/go", goroot_bootstrap),
212                 "install",
213                 "-tags=math_big_pure_go compiler_bootstrap purego",
214         }
215         if vflag > 0 {
216                 cmd = append(cmd, "-v")
217         }
218         if tool := os.Getenv("GOBOOTSTRAP_TOOLEXEC"); tool != "" {
219                 cmd = append(cmd, "-toolexec="+tool)
220         }
221         cmd = append(cmd, "bootstrap/cmd/...")
222         run(base, ShowOutput|CheckExit, cmd...)
223
224         // Copy binaries into tool binary directory.
225         for _, name := range bootstrapDirs {
226                 if !strings.HasPrefix(name, "cmd/") {
227                         continue
228                 }
229                 name = name[len("cmd/"):]
230                 if !strings.Contains(name, "/") {
231                         copyfile(pathf("%s/%s%s", tooldir, name, exe), pathf("%s/bin/%s%s", workspace, name, exe), writeExec)
232                 }
233         }
234
235         if vflag > 0 {
236                 xprintf("\n")
237         }
238 }
239
240 var ssaRewriteFileSubstring = filepath.FromSlash("src/cmd/compile/internal/ssa/rewrite")
241
242 // isUnneededSSARewriteFile reports whether srcFile is a
243 // src/cmd/compile/internal/ssa/rewriteARCHNAME.go file for an
244 // architecture that isn't for the given GOARCH.
245 //
246 // When unneeded is true archCaps is the rewrite base filename without
247 // the "rewrite" prefix or ".go" suffix: AMD64, 386, ARM, ARM64, etc.
248 func isUnneededSSARewriteFile(srcFile, goArch string) (archCaps string, unneeded bool) {
249         if !strings.Contains(srcFile, ssaRewriteFileSubstring) {
250                 return "", false
251         }
252         fileArch := strings.TrimSuffix(strings.TrimPrefix(filepath.Base(srcFile), "rewrite"), ".go")
253         if fileArch == "" {
254                 return "", false
255         }
256         b := fileArch[0]
257         if b == '_' || ('a' <= b && b <= 'z') {
258                 return "", false
259         }
260         archCaps = fileArch
261         fileArch = strings.ToLower(fileArch)
262         fileArch = strings.TrimSuffix(fileArch, "splitload")
263         fileArch = strings.TrimSuffix(fileArch, "latelower")
264         if fileArch == goArch {
265                 return "", false
266         }
267         if fileArch == strings.TrimSuffix(goArch, "le") {
268                 return "", false
269         }
270         return archCaps, true
271 }
272
273 func bootstrapRewriteFile(srcFile string) string {
274         // During bootstrap, generate dummy rewrite files for
275         // irrelevant architectures. We only need to build a bootstrap
276         // binary that works for the current gohostarch.
277         // This saves 6+ seconds of bootstrap.
278         if archCaps, ok := isUnneededSSARewriteFile(srcFile, gohostarch); ok {
279                 return fmt.Sprintf(`// Code generated by go tool dist; DO NOT EDIT.
280
281 package ssa
282
283 func rewriteValue%s(v *Value) bool { panic("unused during bootstrap") }
284 func rewriteBlock%s(b *Block) bool { panic("unused during bootstrap") }
285 `, archCaps, archCaps)
286         }
287
288         return bootstrapFixImports(srcFile)
289 }
290
291 func bootstrapFixImports(srcFile string) string {
292         text := readfile(srcFile)
293         if !strings.Contains(srcFile, "/cmd/") && !strings.Contains(srcFile, `\cmd\`) {
294                 text = regexp.MustCompile(`\bany\b`).ReplaceAllString(text, "interface{}")
295         }
296         lines := strings.SplitAfter(text, "\n")
297         inBlock := false
298         for i, line := range lines {
299                 if strings.HasPrefix(line, "import (") {
300                         inBlock = true
301                         continue
302                 }
303                 if inBlock && strings.HasPrefix(line, ")") {
304                         inBlock = false
305                         continue
306                 }
307                 if strings.HasPrefix(line, `import "`) || strings.HasPrefix(line, `import . "`) ||
308                         inBlock && (strings.HasPrefix(line, "\t\"") || strings.HasPrefix(line, "\t. \"") || strings.HasPrefix(line, "\texec \"")) {
309                         line = strings.Replace(line, `"cmd/`, `"bootstrap/cmd/`, -1)
310                         for _, dir := range bootstrapDirs {
311                                 if strings.HasPrefix(dir, "cmd/") {
312                                         continue
313                                 }
314                                 line = strings.Replace(line, `"`+dir+`"`, `"bootstrap/`+dir+`"`, -1)
315                         }
316                         lines[i] = line
317                 }
318         }
319
320         lines[0] = "// Code generated by go tool dist; DO NOT EDIT.\n// This is a bootstrap copy of " + srcFile + "\n\n//line " + srcFile + ":1\n" + lines[0]
321
322         return strings.Join(lines, "")
323 }