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