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 "go/version"
17 "os"
18 "path/filepath"
19 "regexp"
20 "strings"
21 )
22
23
24
25
26
27
28
29
30
31
32
33
34 var bootstrapDirs = []string{
35 "cmp",
36 "cmd/asm",
37 "cmd/asm/internal/...",
38 "cmd/cgo",
39 "cmd/compile",
40 "cmd/compile/internal/...",
41 "cmd/internal/archive",
42 "cmd/internal/bio",
43 "cmd/internal/codesign",
44 "cmd/internal/dwarf",
45 "cmd/internal/edit",
46 "cmd/internal/gcprog",
47 "cmd/internal/goobj",
48 "cmd/internal/hash",
49 "cmd/internal/macho",
50 "cmd/internal/obj/...",
51 "cmd/internal/objabi",
52 "cmd/internal/pgo",
53 "cmd/internal/pkgpath",
54 "cmd/internal/quoted",
55 "cmd/internal/src",
56 "cmd/internal/sys",
57 "cmd/internal/telemetry",
58 "cmd/internal/telemetry/counter",
59 "cmd/link",
60 "cmd/link/internal/...",
61 "compress/flate",
62 "compress/zlib",
63 "container/heap",
64 "debug/dwarf",
65 "debug/elf",
66 "debug/macho",
67 "debug/pe",
68 "go/build/constraint",
69 "go/constant",
70 "go/version",
71 "internal/abi",
72 "internal/coverage",
73 "cmd/internal/cov/covcmd",
74 "internal/bisect",
75 "internal/buildcfg",
76 "internal/exportdata",
77 "internal/goarch",
78 "internal/godebugs",
79 "internal/goexperiment",
80 "internal/goroot",
81 "internal/gover",
82 "internal/goversion",
83
84
85
86
87 "internal/lazyregexp",
88 "internal/pkgbits",
89 "internal/platform",
90 "internal/profile",
91 "internal/race",
92 "internal/saferio",
93 "internal/syscall/unix",
94 "internal/types/errors",
95 "internal/unsafeheader",
96 "internal/xcoff",
97 "internal/zstd",
98 "math/bits",
99 "sort",
100 }
101
102
103
104 var ignorePrefixes = []string{
105 ".",
106 "_",
107 "#",
108 }
109
110
111
112
113 var ignoreSuffixes = []string{
114 "_test.s",
115 "_test.go",
116
117
118
119 ".pgo",
120
121 "~",
122 }
123
124 const minBootstrap = "go1.22.6"
125
126 var tryDirs = []string{
127 "sdk/" + minBootstrap,
128 minBootstrap,
129 }
130
131 func bootstrapBuildTools() {
132 goroot_bootstrap := os.Getenv("GOROOT_BOOTSTRAP")
133 if goroot_bootstrap == "" {
134 home := os.Getenv("HOME")
135 goroot_bootstrap = pathf("%s/go1.4", home)
136 for _, d := range tryDirs {
137 if p := pathf("%s/%s", home, d); isdir(p) {
138 goroot_bootstrap = p
139 }
140 }
141 }
142
143
144 ver := run(pathf("%s/bin", goroot_bootstrap), CheckExit, pathf("%s/bin/go", goroot_bootstrap), "env", "GOVERSION")
145
146 ver = ver[:len(ver)-1]
147 if version.Compare(ver, version.Lang(minBootstrap)) > 0 && version.Compare(ver, minBootstrap) < 0 {
148 fatalf("%s does not meet the minimum bootstrap requirement of %s or later", ver, minBootstrap)
149 }
150
151 xprintf("Building Go toolchain1 using %s.\n", goroot_bootstrap)
152
153 mkbuildcfg(pathf("%s/src/internal/buildcfg/zbootstrap.go", goroot))
154 mkobjabi(pathf("%s/src/cmd/internal/objabi/zbootstrap.go", goroot))
155
156
157
158
159
160
161 workspace := pathf("%s/pkg/bootstrap", goroot)
162 xremoveall(workspace)
163 xatexit(func() { xremoveall(workspace) })
164 base := pathf("%s/src/bootstrap", workspace)
165 xmkdirall(base)
166
167
168 minBootstrapVers := requiredBootstrapVersion(goModVersion())
169 writefile("module bootstrap\ngo "+minBootstrapVers+"\n", pathf("%s/%s", base, "go.mod"), 0)
170 for _, dir := range bootstrapDirs {
171 recurse := strings.HasSuffix(dir, "/...")
172 dir = strings.TrimSuffix(dir, "/...")
173 filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
174 if err != nil {
175 fatalf("walking bootstrap dirs failed: %v: %v", path, err)
176 }
177
178 name := filepath.Base(path)
179 src := pathf("%s/src/%s", goroot, path)
180 dst := pathf("%s/%s", base, path)
181
182 if info.IsDir() {
183 if !recurse && path != dir || name == "testdata" {
184 return filepath.SkipDir
185 }
186
187 xmkdirall(dst)
188 if path == "cmd/cgo" {
189
190
191 mkzdefaultcc("", pathf("%s/zdefaultcc.go", src))
192 mkzdefaultcc("", pathf("%s/zdefaultcc.go", dst))
193 }
194 return nil
195 }
196
197 for _, pre := range ignorePrefixes {
198 if strings.HasPrefix(name, pre) {
199 return nil
200 }
201 }
202 for _, suf := range ignoreSuffixes {
203 if strings.HasSuffix(name, suf) {
204 return nil
205 }
206 }
207
208 text := bootstrapRewriteFile(src)
209 writefile(text, dst, 0)
210 return nil
211 })
212 }
213
214
215
216
217
218
219
220
221
222
223
224 defer os.Setenv("GOROOT", os.Getenv("GOROOT"))
225 os.Setenv("GOROOT", goroot_bootstrap)
226
227 defer os.Setenv("GOPATH", os.Getenv("GOPATH"))
228 os.Setenv("GOPATH", workspace)
229
230 defer os.Setenv("GOBIN", os.Getenv("GOBIN"))
231 os.Setenv("GOBIN", "")
232
233 os.Setenv("GOOS", "")
234 os.Setenv("GOHOSTOS", "")
235 os.Setenv("GOARCH", "")
236 os.Setenv("GOHOSTARCH", "")
237
238
239
240
241
242 cmd := []string{
243 pathf("%s/bin/go", goroot_bootstrap),
244 "install",
245 "-tags=math_big_pure_go compiler_bootstrap purego",
246 }
247 if vflag > 0 {
248 cmd = append(cmd, "-v")
249 }
250 if tool := os.Getenv("GOBOOTSTRAP_TOOLEXEC"); tool != "" {
251 cmd = append(cmd, "-toolexec="+tool)
252 }
253 cmd = append(cmd, "bootstrap/cmd/...")
254 run(base, ShowOutput|CheckExit, cmd...)
255
256
257 for _, name := range bootstrapDirs {
258 if !strings.HasPrefix(name, "cmd/") {
259 continue
260 }
261 name = name[len("cmd/"):]
262 if !strings.Contains(name, "/") {
263 copyfile(pathf("%s/%s%s", tooldir, name, exe), pathf("%s/bin/%s%s", workspace, name, exe), writeExec)
264 }
265 }
266
267 if vflag > 0 {
268 xprintf("\n")
269 }
270 }
271
272 var ssaRewriteFileSubstring = filepath.FromSlash("src/cmd/compile/internal/ssa/rewrite")
273
274
275
276
277
278
279
280 func isUnneededSSARewriteFile(srcFile, goArch string) (archCaps string, unneeded bool) {
281 if !strings.Contains(srcFile, ssaRewriteFileSubstring) {
282 return "", false
283 }
284 fileArch := strings.TrimSuffix(strings.TrimPrefix(filepath.Base(srcFile), "rewrite"), ".go")
285 if fileArch == "" {
286 return "", false
287 }
288 b := fileArch[0]
289 if b == '_' || ('a' <= b && b <= 'z') {
290 return "", false
291 }
292 archCaps = fileArch
293 fileArch = strings.ToLower(fileArch)
294 fileArch = strings.TrimSuffix(fileArch, "splitload")
295 fileArch = strings.TrimSuffix(fileArch, "latelower")
296 if fileArch == goArch {
297 return "", false
298 }
299 if fileArch == strings.TrimSuffix(goArch, "le") {
300 return "", false
301 }
302 return archCaps, true
303 }
304
305 func bootstrapRewriteFile(srcFile string) string {
306
307
308
309
310 if archCaps, ok := isUnneededSSARewriteFile(srcFile, gohostarch); ok {
311 return fmt.Sprintf(`%spackage ssa
312
313 func rewriteValue%s(v *Value) bool { panic("unused during bootstrap") }
314 func rewriteBlock%s(b *Block) bool { panic("unused during bootstrap") }
315 `, generatedHeader, archCaps, archCaps)
316 }
317
318 return bootstrapFixImports(srcFile)
319 }
320
321 var (
322 importRE = regexp.MustCompile(`\Aimport\s+(\.|[A-Za-z0-9_]+)?\s*"([^"]+)"\s*(//.*)?\n\z`)
323 importBlockRE = regexp.MustCompile(`\A\s*(?:(\.|[A-Za-z0-9_]+)?\s*"([^"]+)")?\s*(//.*)?\n\z`)
324 )
325
326 func bootstrapFixImports(srcFile string) string {
327 text := readfile(srcFile)
328 lines := strings.SplitAfter(text, "\n")
329 inBlock := false
330 inComment := false
331 for i, line := range lines {
332 if strings.HasSuffix(line, "*/\n") {
333 inComment = false
334 }
335 if strings.HasSuffix(line, "/*\n") {
336 inComment = true
337 }
338 if inComment {
339 continue
340 }
341 if strings.HasPrefix(line, "import (") {
342 inBlock = true
343 continue
344 }
345 if inBlock && strings.HasPrefix(line, ")") {
346 inBlock = false
347 continue
348 }
349
350 var m []string
351 if !inBlock {
352 if !strings.HasPrefix(line, "import ") {
353 continue
354 }
355 m = importRE.FindStringSubmatch(line)
356 if m == nil {
357 fatalf("%s:%d: invalid import declaration: %q", srcFile, i+1, line)
358 }
359 } else {
360 m = importBlockRE.FindStringSubmatch(line)
361 if m == nil {
362 fatalf("%s:%d: invalid import block line", srcFile, i+1)
363 }
364 if m[2] == "" {
365 continue
366 }
367 }
368
369 path := m[2]
370 if strings.HasPrefix(path, "cmd/") {
371 path = "bootstrap/" + path
372 } else {
373 for _, dir := range bootstrapDirs {
374 if path == dir {
375 path = "bootstrap/" + dir
376 break
377 }
378 }
379 }
380
381
382 if path == "internal/reflectlite" {
383 lines[i] = strings.ReplaceAll(line, `"reflect"`, `reflectlite "reflect"`)
384 continue
385 }
386
387
388
389
390
391
392
393
394 if strings.HasPrefix(path, "internal/") {
395 fatalf("%s:%d: bootstrap-copied source file cannot import %s", srcFile, i+1, path)
396 }
397 if path != m[2] {
398 lines[i] = strings.ReplaceAll(line, `"`+m[2]+`"`, `"`+path+`"`)
399 }
400 }
401
402 lines[0] = generatedHeader + "// This is a bootstrap copy of " + srcFile + "\n\n//line " + srcFile + ":1\n" + lines[0]
403
404 return strings.Join(lines, "")
405 }
406
View as plain text