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