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 defer os.Setenv("GOROOT", os.Getenv("GOROOT"))
228 os.Setenv("GOROOT", goroot_bootstrap)
229
230 defer os.Setenv("GOPATH", os.Getenv("GOPATH"))
231 os.Setenv("GOPATH", workspace)
232
233 defer os.Setenv("GOBIN", os.Getenv("GOBIN"))
234 os.Setenv("GOBIN", "")
235
236 os.Setenv("GOOS", "")
237 os.Setenv("GOHOSTOS", "")
238 os.Setenv("GOARCH", "")
239 os.Setenv("GOHOSTARCH", "")
240
241
242
243
244
245 cmd := []string{
246 pathf("%s/bin/go", goroot_bootstrap),
247 "install",
248 "-tags=math_big_pure_go compiler_bootstrap purego",
249 }
250 if vflag > 0 {
251 cmd = append(cmd, "-v")
252 }
253 if tool := os.Getenv("GOBOOTSTRAP_TOOLEXEC"); tool != "" {
254 cmd = append(cmd, "-toolexec="+tool)
255 }
256 cmd = append(cmd, "bootstrap/cmd/...")
257 run(base, ShowOutput|CheckExit, cmd...)
258
259
260 for _, name := range bootstrapDirs {
261 if !strings.HasPrefix(name, "cmd/") {
262 continue
263 }
264 name = name[len("cmd/"):]
265 if !strings.Contains(name, "/") {
266 copyfile(pathf("%s/%s%s", tooldir, name, exe), pathf("%s/bin/%s%s", workspace, name, exe), writeExec)
267 }
268 }
269
270 if vflag > 0 {
271 xprintf("\n")
272 }
273 }
274
275 var ssaRewriteFileSubstring = filepath.FromSlash("src/cmd/compile/internal/ssa/rewrite")
276
277
278
279
280
281
282
283 func isUnneededSSARewriteFile(srcFile, goArch string) (archCaps string, unneeded bool) {
284 if !strings.Contains(srcFile, ssaRewriteFileSubstring) {
285 return "", false
286 }
287 fileArch := strings.TrimSuffix(strings.TrimPrefix(filepath.Base(srcFile), "rewrite"), ".go")
288 if fileArch == "" {
289 return "", false
290 }
291 b := fileArch[0]
292 if b == '_' || ('a' <= b && b <= 'z') {
293 return "", false
294 }
295 archCaps = fileArch
296 fileArch = strings.ToLower(fileArch)
297 fileArch = strings.TrimSuffix(fileArch, "splitload")
298 fileArch = strings.TrimSuffix(fileArch, "latelower")
299 if fileArch == goArch {
300 return "", false
301 }
302 if fileArch == strings.TrimSuffix(goArch, "le") {
303 return "", false
304 }
305 return archCaps, true
306 }
307
308 func bootstrapRewriteFile(srcFile string) string {
309
310
311
312
313 if archCaps, ok := isUnneededSSARewriteFile(srcFile, gohostarch); ok {
314 return fmt.Sprintf(`%spackage ssa
315
316 func rewriteValue%s(v *Value) bool { panic("unused during bootstrap") }
317 func rewriteBlock%s(b *Block) bool { panic("unused during bootstrap") }
318 `, generatedHeader, archCaps, archCaps)
319 }
320
321 return bootstrapFixImports(srcFile)
322 }
323
324 var (
325 importRE = regexp.MustCompile(`\Aimport\s+(\.|[A-Za-z0-9_]+)?\s*"([^"]+)"\s*(//.*)?\n\z`)
326 importBlockRE = regexp.MustCompile(`\A\s*(?:(\.|[A-Za-z0-9_]+)?\s*"([^"]+)")?\s*(//.*)?\n\z`)
327 )
328
329 func bootstrapFixImports(srcFile string) string {
330 text := readfile(srcFile)
331 lines := strings.SplitAfter(text, "\n")
332 inBlock := false
333 inComment := false
334 for i, line := range lines {
335 if strings.HasSuffix(line, "*/\n") {
336 inComment = false
337 }
338 if strings.HasSuffix(line, "/*\n") {
339 inComment = true
340 }
341 if inComment {
342 continue
343 }
344 if strings.HasPrefix(line, "import (") {
345 inBlock = true
346 continue
347 }
348 if inBlock && strings.HasPrefix(line, ")") {
349 inBlock = false
350 continue
351 }
352
353 var m []string
354 if !inBlock {
355 if !strings.HasPrefix(line, "import ") {
356 continue
357 }
358 m = importRE.FindStringSubmatch(line)
359 if m == nil {
360 fatalf("%s:%d: invalid import declaration: %q", srcFile, i+1, line)
361 }
362 } else {
363 m = importBlockRE.FindStringSubmatch(line)
364 if m == nil {
365 fatalf("%s:%d: invalid import block line", srcFile, i+1)
366 }
367 if m[2] == "" {
368 continue
369 }
370 }
371
372 path := m[2]
373 if strings.HasPrefix(path, "cmd/") {
374 path = "bootstrap/" + path
375 } else {
376 for _, dir := range bootstrapDirs {
377 if path == dir {
378 path = "bootstrap/" + dir
379 break
380 }
381 }
382 }
383
384
385 if path == "internal/reflectlite" {
386 lines[i] = strings.ReplaceAll(line, `"reflect"`, `reflectlite "reflect"`)
387 continue
388 }
389
390
391
392
393
394
395
396
397 if strings.HasPrefix(path, "internal/") {
398 fatalf("%s:%d: bootstrap-copied source file cannot import %s", srcFile, i+1, path)
399 }
400 if path != m[2] {
401 lines[i] = strings.ReplaceAll(line, `"`+m[2]+`"`, `"`+path+`"`)
402 }
403 }
404
405 lines[0] = generatedHeader + "// This is a bootstrap copy of " + srcFile + "\n\n//line " + srcFile + ":1\n" + lines[0]
406
407 return strings.Join(lines, "")
408 }
409
View as plain text