Source file
src/cmd/dist/buildtool.go
1
2
3
4
5
6
7
8
9
10
11
12 package main
13
14 import (
15 "fmt"
16 "os"
17 "path/filepath"
18 "regexp"
19 "runtime"
20 "strings"
21 )
22
23
24
25
26
27
28
29
30
31
32
33
34 var bootstrapDirs = []string{
35 "cmd/asm",
36 "cmd/asm/internal/...",
37 "cmd/cgo",
38 "cmd/compile",
39 "cmd/compile/internal/...",
40 "cmd/internal/archive",
41 "cmd/internal/bio",
42 "cmd/internal/codesign",
43 "cmd/internal/dwarf",
44 "cmd/internal/edit",
45 "cmd/internal/gcprog",
46 "cmd/internal/goobj",
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/constant",
63 "internal/buildcfg",
64 "internal/goexperiment",
65 "internal/goversion",
66 "internal/race",
67 "internal/unsafeheader",
68 "internal/xcoff",
69 "math/big",
70 "math/bits",
71 "sort",
72 "strconv",
73 }
74
75
76
77 var ignorePrefixes = []string{
78 ".",
79 "_",
80 "#",
81 }
82
83
84
85
86 var ignoreSuffixes = []string{
87 "_arm64.s",
88 "_arm64.go",
89 "_riscv64.s",
90 "_riscv64.go",
91 "_wasm.s",
92 "_wasm.go",
93 "_test.s",
94 "_test.go",
95 }
96
97 var tryDirs = []string{
98 "sdk/go1.17",
99 "go1.17",
100 }
101
102 func bootstrapBuildTools() {
103 goroot_bootstrap := os.Getenv("GOROOT_BOOTSTRAP")
104 if goroot_bootstrap == "" {
105 home := os.Getenv("HOME")
106 goroot_bootstrap = pathf("%s/go1.4", home)
107 for _, d := range tryDirs {
108 if p := pathf("%s/%s", home, d); isdir(p) {
109 goroot_bootstrap = p
110 }
111 }
112 }
113 xprintf("Building Go toolchain1 using %s.\n", goroot_bootstrap)
114
115 mkbuildcfg(pathf("%s/src/internal/buildcfg/zbootstrap.go", goroot))
116 mkobjabi(pathf("%s/src/cmd/internal/objabi/zbootstrap.go", goroot))
117
118
119
120
121
122
123 workspace := pathf("%s/pkg/bootstrap", goroot)
124 xremoveall(workspace)
125 xatexit(func() { xremoveall(workspace) })
126 base := pathf("%s/src/bootstrap", workspace)
127 xmkdirall(base)
128
129
130 writefile("module bootstrap\n", pathf("%s/%s", base, "go.mod"), 0)
131 for _, dir := range bootstrapDirs {
132 recurse := strings.HasSuffix(dir, "/...")
133 dir = strings.TrimSuffix(dir, "/...")
134 filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
135 if err != nil {
136 fatalf("walking bootstrap dirs failed: %v: %v", path, err)
137 }
138
139 name := filepath.Base(path)
140 src := pathf("%s/src/%s", goroot, path)
141 dst := pathf("%s/%s", base, path)
142
143 if info.IsDir() {
144 if !recurse && path != dir || name == "testdata" {
145 return filepath.SkipDir
146 }
147
148 xmkdirall(dst)
149 if path == "cmd/cgo" {
150
151
152 mkzdefaultcc("", pathf("%s/zdefaultcc.go", src))
153 mkzdefaultcc("", pathf("%s/zdefaultcc.go", dst))
154 }
155 return nil
156 }
157
158 for _, pre := range ignorePrefixes {
159 if strings.HasPrefix(name, pre) {
160 return nil
161 }
162 }
163 for _, suf := range ignoreSuffixes {
164 if strings.HasSuffix(name, suf) {
165 return nil
166 }
167 }
168
169 text := bootstrapRewriteFile(src)
170 writefile(text, dst, 0)
171 return nil
172 })
173 }
174
175
176
177
178
179
180
181
182
183
184
185 defer os.Setenv("GOROOT", os.Getenv("GOROOT"))
186 os.Setenv("GOROOT", goroot_bootstrap)
187
188 defer os.Setenv("GOPATH", os.Getenv("GOPATH"))
189 os.Setenv("GOPATH", workspace)
190
191 defer os.Setenv("GOBIN", os.Getenv("GOBIN"))
192 os.Setenv("GOBIN", "")
193
194 os.Setenv("GOOS", "")
195 os.Setenv("GOHOSTOS", "")
196 os.Setenv("GOARCH", "")
197 os.Setenv("GOHOSTARCH", "")
198
199
200
201
202
203
204
205
206
207 cmd := []string{
208 pathf("%s/bin/go", goroot_bootstrap),
209 "install",
210 "-gcflags=-l",
211 "-tags=math_big_pure_go compiler_bootstrap",
212 }
213 if vflag > 0 {
214 cmd = append(cmd, "-v")
215 }
216 if tool := os.Getenv("GOBOOTSTRAP_TOOLEXEC"); tool != "" {
217 cmd = append(cmd, "-toolexec="+tool)
218 }
219 cmd = append(cmd, "bootstrap/cmd/...")
220 run(base, ShowOutput|CheckExit, cmd...)
221
222
223 for _, name := range bootstrapDirs {
224 if !strings.HasPrefix(name, "cmd/") {
225 continue
226 }
227 name = name[len("cmd/"):]
228 if !strings.Contains(name, "/") {
229 copyfile(pathf("%s/%s%s", tooldir, name, exe), pathf("%s/bin/%s%s", workspace, name, exe), writeExec)
230 }
231 }
232
233 if vflag > 0 {
234 xprintf("\n")
235 }
236 }
237
238 var ssaRewriteFileSubstring = filepath.FromSlash("src/cmd/compile/internal/ssa/rewrite")
239
240
241
242
243
244
245
246 func isUnneededSSARewriteFile(srcFile string) (archCaps string, unneeded bool) {
247 if !strings.Contains(srcFile, ssaRewriteFileSubstring) {
248 return "", false
249 }
250 fileArch := strings.TrimSuffix(strings.TrimPrefix(filepath.Base(srcFile), "rewrite"), ".go")
251 if fileArch == "" {
252 return "", false
253 }
254 b := fileArch[0]
255 if b == '_' || ('a' <= b && b <= 'z') {
256 return "", false
257 }
258 archCaps = fileArch
259 fileArch = strings.ToLower(fileArch)
260 fileArch = strings.TrimSuffix(fileArch, "splitload")
261 if fileArch == os.Getenv("GOHOSTARCH") {
262 return "", false
263 }
264 if fileArch == strings.TrimSuffix(runtime.GOARCH, "le") {
265 return "", false
266 }
267 if fileArch == strings.TrimSuffix(os.Getenv("GOARCH"), "le") {
268 return "", false
269 }
270 return archCaps, true
271 }
272
273 func bootstrapRewriteFile(srcFile string) string {
274
275
276
277
278 if archCaps, ok := isUnneededSSARewriteFile(srcFile); 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
311 line = strings.Replace(line, `exec "internal/execabs"`, `"os/exec"`, -1)
312 for _, dir := range bootstrapDirs {
313 if strings.HasPrefix(dir, "cmd/") {
314 continue
315 }
316 line = strings.Replace(line, `"`+dir+`"`, `"bootstrap/`+dir+`"`, -1)
317 }
318 lines[i] = line
319 }
320 }
321
322 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]
323
324 return strings.Join(lines, "")
325 }
326
View as plain text