Source file
src/cmd/dist/build.go
1
2
3
4
5 package main
6
7 import (
8 "bytes"
9 "encoding/json"
10 "flag"
11 "fmt"
12 "go/build/constraint"
13 "io"
14 "io/fs"
15 "log"
16 "os"
17 "os/exec"
18 "path/filepath"
19 "regexp"
20 "slices"
21 "sort"
22 "strconv"
23 "strings"
24 "sync"
25 "time"
26 )
27
28
29
30
31 var (
32 goarch string
33 gorootBin string
34 gorootBinGo string
35 gohostarch string
36 gohostos string
37 goos string
38 goarm string
39 goarm64 string
40 go386 string
41 goamd64 string
42 gomips string
43 gomips64 string
44 goppc64 string
45 goriscv64 string
46 goroot string
47 goextlinkenabled string
48 gogcflags string
49 goldflags string
50 goexperiment string
51 gofips140 string
52 workdir string
53 tooldir string
54 oldgoos string
55 oldgoarch string
56 oldgocache string
57 exe string
58 defaultcc map[string]string
59 defaultcxx map[string]string
60 defaultpkgconfig string
61 defaultldso string
62
63 rebuildall bool
64 noOpt bool
65 isRelease bool
66
67 vflag int
68 )
69
70
71 var okgoarch = []string{
72 "386",
73 "amd64",
74 "arm",
75 "arm64",
76 "loong64",
77 "mips",
78 "mipsle",
79 "mips64",
80 "mips64le",
81 "ppc64",
82 "ppc64le",
83 "riscv64",
84 "s390x",
85 "sparc64",
86 "wasm",
87 }
88
89
90 var okgoos = []string{
91 "darwin",
92 "dragonfly",
93 "illumos",
94 "ios",
95 "js",
96 "wasip1",
97 "linux",
98 "android",
99 "solaris",
100 "freebsd",
101 "nacl",
102 "netbsd",
103 "openbsd",
104 "plan9",
105 "windows",
106 "aix",
107 }
108
109
110 func xinit() {
111 b := os.Getenv("GOROOT")
112 if b == "" {
113 fatalf("$GOROOT must be set")
114 }
115 goroot = filepath.Clean(b)
116 gorootBin = pathf("%s/bin", goroot)
117
118
119
120
121
122 gorootBinGo = pathf("%s/bin/go", goroot)
123
124 b = os.Getenv("GOOS")
125 if b == "" {
126 b = gohostos
127 }
128 goos = b
129 if slices.Index(okgoos, goos) < 0 {
130 fatalf("unknown $GOOS %s", goos)
131 }
132
133 b = os.Getenv("GOARM")
134 if b == "" {
135 b = xgetgoarm()
136 }
137 goarm = b
138
139 b = os.Getenv("GOARM64")
140 if b == "" {
141 b = "v8.0"
142 }
143 goarm64 = b
144
145 b = os.Getenv("GO386")
146 if b == "" {
147 b = "sse2"
148 }
149 go386 = b
150
151 b = os.Getenv("GOAMD64")
152 if b == "" {
153 b = "v1"
154 }
155 goamd64 = b
156
157 b = os.Getenv("GOMIPS")
158 if b == "" {
159 b = "hardfloat"
160 }
161 gomips = b
162
163 b = os.Getenv("GOMIPS64")
164 if b == "" {
165 b = "hardfloat"
166 }
167 gomips64 = b
168
169 b = os.Getenv("GOPPC64")
170 if b == "" {
171 b = "power8"
172 }
173 goppc64 = b
174
175 b = os.Getenv("GORISCV64")
176 if b == "" {
177 b = "rva20u64"
178 }
179 goriscv64 = b
180
181 b = os.Getenv("GOFIPS140")
182 if b == "" {
183 b = "off"
184 }
185 gofips140 = b
186
187 if p := pathf("%s/src/all.bash", goroot); !isfile(p) {
188 fatalf("$GOROOT is not set correctly or not exported\n"+
189 "\tGOROOT=%s\n"+
190 "\t%s does not exist", goroot, p)
191 }
192
193 b = os.Getenv("GOHOSTARCH")
194 if b != "" {
195 gohostarch = b
196 }
197 if slices.Index(okgoarch, gohostarch) < 0 {
198 fatalf("unknown $GOHOSTARCH %s", gohostarch)
199 }
200
201 b = os.Getenv("GOARCH")
202 if b == "" {
203 b = gohostarch
204 }
205 goarch = b
206 if slices.Index(okgoarch, goarch) < 0 {
207 fatalf("unknown $GOARCH %s", goarch)
208 }
209
210 b = os.Getenv("GO_EXTLINK_ENABLED")
211 if b != "" {
212 if b != "0" && b != "1" {
213 fatalf("unknown $GO_EXTLINK_ENABLED %s", b)
214 }
215 goextlinkenabled = b
216 }
217
218 goexperiment = os.Getenv("GOEXPERIMENT")
219
220
221 gogcflags = os.Getenv("BOOT_GO_GCFLAGS")
222 goldflags = os.Getenv("BOOT_GO_LDFLAGS")
223
224 defaultcc = compilerEnv("CC", "")
225 defaultcxx = compilerEnv("CXX", "")
226
227 b = os.Getenv("PKG_CONFIG")
228 if b == "" {
229 b = "pkg-config"
230 }
231 defaultpkgconfig = b
232
233 defaultldso = os.Getenv("GO_LDSO")
234
235
236 os.Setenv("GO386", go386)
237 os.Setenv("GOAMD64", goamd64)
238 os.Setenv("GOARCH", goarch)
239 os.Setenv("GOARM", goarm)
240 os.Setenv("GOARM64", goarm64)
241 os.Setenv("GOHOSTARCH", gohostarch)
242 os.Setenv("GOHOSTOS", gohostos)
243 os.Setenv("GOOS", goos)
244 os.Setenv("GOMIPS", gomips)
245 os.Setenv("GOMIPS64", gomips64)
246 os.Setenv("GOPPC64", goppc64)
247 os.Setenv("GORISCV64", goriscv64)
248 os.Setenv("GOROOT", goroot)
249 os.Setenv("GOFIPS140", gofips140)
250
251
252
253
254
255 os.Setenv("GOBIN", gorootBin)
256
257
258 os.Setenv("LANG", "C")
259 os.Setenv("LANGUAGE", "en_US.UTF8")
260 os.Unsetenv("GO111MODULE")
261 os.Setenv("GOENV", "off")
262 os.Unsetenv("GOFLAGS")
263 os.Setenv("GOWORK", "off")
264
265
266
267
268 modVer := goModVersion()
269 workdir = xworkdir()
270 if err := os.WriteFile(pathf("%s/go.mod", workdir), []byte("module bootstrap\n\ngo "+modVer+"\n"), 0666); err != nil {
271 fatalf("cannot write stub go.mod: %s", err)
272 }
273 xatexit(rmworkdir)
274
275 tooldir = pathf("%s/pkg/tool/%s_%s", goroot, gohostos, gohostarch)
276
277 goversion := findgoversion()
278 isRelease = (strings.HasPrefix(goversion, "release.") || strings.HasPrefix(goversion, "go")) &&
279 !strings.Contains(goversion, "devel")
280 }
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299 func compilerEnv(envName, def string) map[string]string {
300 m := map[string]string{"": def}
301
302 if env := os.Getenv(envName); env != "" {
303 m[""] = env
304 }
305 if env := os.Getenv(envName + "_FOR_TARGET"); env != "" {
306 if gohostos != goos || gohostarch != goarch {
307 m[gohostos+"/"+gohostarch] = m[""]
308 }
309 m[""] = env
310 }
311
312 for _, goos := range okgoos {
313 for _, goarch := range okgoarch {
314 if env := os.Getenv(envName + "_FOR_" + goos + "_" + goarch); env != "" {
315 m[goos+"/"+goarch] = env
316 }
317 }
318 }
319
320 return m
321 }
322
323
324 var clangos = []string{
325 "darwin", "ios",
326 "freebsd",
327 "openbsd",
328 }
329
330
331
332 func compilerEnvLookup(kind string, m map[string]string, goos, goarch string) string {
333 if !needCC() {
334 return ""
335 }
336 if cc := m[goos+"/"+goarch]; cc != "" {
337 return cc
338 }
339 if cc := m[""]; cc != "" {
340 return cc
341 }
342 for _, os := range clangos {
343 if goos == os {
344 if kind == "CXX" {
345 return "clang++"
346 }
347 return "clang"
348 }
349 }
350 if kind == "CXX" {
351 return "g++"
352 }
353 return "gcc"
354 }
355
356
357 func rmworkdir() {
358 if vflag > 1 {
359 errprintf("rm -rf %s\n", workdir)
360 }
361 xremoveall(workdir)
362 }
363
364
365 func chomp(s string) string {
366 return strings.TrimRight(s, " \t\r\n")
367 }
368
369
370
371 func findgoversion() string {
372
373
374 path := pathf("%s/VERSION", goroot)
375 if isfile(path) {
376 b := chomp(readfile(path))
377
378
379
380
381 if i := strings.Index(b, "\n"); i >= 0 {
382 rest := b[i+1:]
383 b = chomp(b[:i])
384 for line := range strings.SplitSeq(rest, "\n") {
385 f := strings.Fields(line)
386 if len(f) == 0 {
387 continue
388 }
389 switch f[0] {
390 default:
391 fatalf("VERSION: unexpected line: %s", line)
392 case "time":
393 if len(f) != 2 {
394 fatalf("VERSION: unexpected time line: %s", line)
395 }
396 _, err := time.Parse(time.RFC3339, f[1])
397 if err != nil {
398 fatalf("VERSION: bad time: %s", err)
399 }
400 }
401 }
402 }
403
404
405
406
407
408
409 if b != "" {
410 return b
411 }
412 }
413
414
415
416
417 path = pathf("%s/VERSION.cache", goroot)
418 if isfile(path) {
419 return chomp(readfile(path))
420 }
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435 goversionSource := readfile(pathf("%s/src/internal/goversion/goversion.go", goroot))
436 m := regexp.MustCompile(`(?m)^const Version = (\d+)`).FindStringSubmatch(goversionSource)
437 if m == nil {
438 fatalf("internal/goversion/goversion.go does not contain 'const Version = ...'")
439 }
440 version := fmt.Sprintf("go1.%s-devel_", m[1])
441 switch {
442 case isGitRepo():
443 version += chomp(run(goroot, CheckExit, "git", "log", "-n", "1", "--format=format:%h %cd", "HEAD"))
444 case isJJRepo():
445 const jjTemplate = `commit_id.short(10) ++ " " ++ committer.timestamp().format("%c %z")`
446 version += chomp(run(goroot, CheckExit, "jj", "--no-pager", "--color=never", "log", "--no-graph", "-r", "@", "-T", jjTemplate))
447 default:
448
449 fatalf("FAILED: not a Git or jj repo; must put a VERSION file in $GOROOT")
450 }
451
452
453 writefile(version, path, 0)
454
455 return version
456 }
457
458
459
460
461 func goModVersion() string {
462 goMod := readfile(pathf("%s/src/go.mod", goroot))
463 m := regexp.MustCompile(`(?m)^go (1.\d+)$`).FindStringSubmatch(goMod)
464 if m == nil {
465 fatalf("std go.mod does not contain go 1.X")
466 }
467 return m[1]
468 }
469
470 func requiredBootstrapVersion(v string) string {
471 minorstr, ok := strings.CutPrefix(v, "1.")
472 if !ok {
473 fatalf("go version %q in go.mod does not start with %q", v, "1.")
474 }
475 minor, err := strconv.Atoi(minorstr)
476 if err != nil {
477 fatalf("invalid go version minor component %q: %v", minorstr, err)
478 }
479
480
481 requiredMinor := minor - 2 - minor%2
482 return "1." + strconv.Itoa(requiredMinor)
483 }
484
485
486 func isGitRepo() bool {
487
488
489
490 gitDir := chomp(run(goroot, 0, "git", "rev-parse", "--git-dir"))
491 if !filepath.IsAbs(gitDir) {
492 gitDir = filepath.Join(goroot, gitDir)
493 }
494 return isdir(gitDir)
495 }
496
497
498 func isJJRepo() bool {
499
500 jjDir := chomp(run(goroot, 0, "jj", "--no-pager", "--color=never", "root"))
501 if !filepath.IsAbs(jjDir) {
502 jjDir = filepath.Join(goroot, jjDir)
503 }
504 return isdir(jjDir)
505 }
506
507
510
511
512 var oldtool = []string{
513 "5a", "5c", "5g", "5l",
514 "6a", "6c", "6g", "6l",
515 "8a", "8c", "8g", "8l",
516 "9a", "9c", "9g", "9l",
517 "6cov",
518 "6nm",
519 "6prof",
520 "cgo",
521 "ebnflint",
522 "goapi",
523 "gofix",
524 "goinstall",
525 "gomake",
526 "gopack",
527 "gopprof",
528 "gotest",
529 "gotype",
530 "govet",
531 "goyacc",
532 "quietgcc",
533 }
534
535
536
537 var unreleased = []string{
538 "src/cmd/newlink",
539 "src/cmd/objwriter",
540 "src/debug/goobj",
541 "src/old",
542 }
543
544
545 func setup() {
546
547 if p := pathf("%s/bin", goroot); !isdir(p) {
548 xmkdir(p)
549 }
550
551
552 if p := pathf("%s/pkg", goroot); !isdir(p) {
553 xmkdir(p)
554 }
555
556 goosGoarch := pathf("%s/pkg/%s_%s", goroot, gohostos, gohostarch)
557 if rebuildall {
558 xremoveall(goosGoarch)
559 }
560 xmkdirall(goosGoarch)
561 xatexit(func() {
562 if files := xreaddir(goosGoarch); len(files) == 0 {
563 xremove(goosGoarch)
564 }
565 })
566
567 if goos != gohostos || goarch != gohostarch {
568 p := pathf("%s/pkg/%s_%s", goroot, goos, goarch)
569 if rebuildall {
570 xremoveall(p)
571 }
572 xmkdirall(p)
573 }
574
575
576
577
578
579
580 obj := pathf("%s/pkg/obj", goroot)
581 if !isdir(obj) {
582 xmkdir(obj)
583 }
584 xatexit(func() { xremove(obj) })
585
586
587 objGobuild := pathf("%s/pkg/obj/go-build", goroot)
588 if rebuildall {
589 xremoveall(objGobuild)
590 }
591 xmkdirall(objGobuild)
592 xatexit(func() { xremoveall(objGobuild) })
593
594
595 objGoBootstrap := pathf("%s/pkg/obj/go-bootstrap", goroot)
596 if rebuildall {
597 xremoveall(objGoBootstrap)
598 }
599 xmkdirall(objGoBootstrap)
600 xatexit(func() { xremoveall(objGoBootstrap) })
601
602
603
604 if rebuildall {
605 xremoveall(tooldir)
606 }
607 xmkdirall(tooldir)
608
609
610 xremoveall(pathf("%s/bin/tool", goroot))
611
612
613 for _, old := range oldtool {
614 xremove(pathf("%s/bin/%s", goroot, old))
615 }
616
617
618 if isRelease {
619
620 for _, dir := range unreleased {
621 if p := pathf("%s/%s", goroot, dir); isdir(p) {
622 fatalf("%s should not exist in release build", p)
623 }
624 }
625 }
626 }
627
628
631
632
633
634
635 func mustLinkExternal(goos, goarch string, cgoEnabled bool) bool {
636 if cgoEnabled {
637 switch goarch {
638 case "mips", "mipsle", "mips64", "mips64le":
639
640
641 return true
642 case "ppc64":
643
644 if goos == "aix" || goos == "linux" {
645 return true
646 }
647 }
648
649 switch goos {
650 case "android":
651 return true
652 case "dragonfly":
653
654
655
656 return true
657 }
658 }
659
660 switch goos {
661 case "android":
662 if goarch != "arm64" {
663 return true
664 }
665 case "ios":
666 if goarch == "arm64" {
667 return true
668 }
669 }
670 return false
671 }
672
673
674 var depsuffix = []string{
675 ".s",
676 ".go",
677 }
678
679
680
681 var gentab = []struct {
682 pkg string
683 file string
684 gen func(dir, file string)
685 }{
686 {"cmd/go/internal/cfg", "zdefaultcc.go", mkzdefaultcc},
687 {"internal/runtime/sys", "zversion.go", mkzversion},
688 {"time/tzdata", "zzipdata.go", mktzdata},
689 }
690
691
692
693 var installed = make(map[string]chan struct{})
694 var installedMu sync.Mutex
695
696 func install(dir string) {
697 <-startInstall(dir)
698 }
699
700 func startInstall(dir string) chan struct{} {
701 installedMu.Lock()
702 ch := installed[dir]
703 if ch == nil {
704 ch = make(chan struct{})
705 installed[dir] = ch
706 go runInstall(dir, ch)
707 }
708 installedMu.Unlock()
709 return ch
710 }
711
712
713
714 func runInstall(pkg string, ch chan struct{}) {
715 if pkg == "net" || pkg == "os/user" || pkg == "crypto/x509" {
716 fatalf("go_bootstrap cannot depend on cgo package %s", pkg)
717 }
718
719 defer close(ch)
720
721 if pkg == "unsafe" {
722 return
723 }
724
725 if vflag > 0 {
726 if goos != gohostos || goarch != gohostarch {
727 errprintf("%s (%s/%s)\n", pkg, goos, goarch)
728 } else {
729 errprintf("%s\n", pkg)
730 }
731 }
732
733 workdir := pathf("%s/%s", workdir, pkg)
734 xmkdirall(workdir)
735
736 var clean []string
737 defer func() {
738 for _, name := range clean {
739 xremove(name)
740 }
741 }()
742
743
744 dir := pathf("%s/src/%s", goroot, pkg)
745 name := filepath.Base(dir)
746
747
748
749
750 ispkg := !strings.HasPrefix(pkg, "cmd/") || strings.Contains(pkg, "/internal/") || strings.Contains(pkg, "/vendor/")
751
752
753
754 var (
755 link []string
756 targ int
757 ispackcmd bool
758 )
759 if ispkg {
760
761 ispackcmd = true
762 link = []string{"pack", packagefile(pkg)}
763 targ = len(link) - 1
764 xmkdirall(filepath.Dir(link[targ]))
765 } else {
766
767 elem := name
768 if elem == "go" {
769 elem = "go_bootstrap"
770 }
771 link = []string{pathf("%s/link", tooldir)}
772 if goos == "android" {
773 link = append(link, "-buildmode=pie")
774 }
775 if goldflags != "" {
776 link = append(link, goldflags)
777 }
778 link = append(link, "-extld="+compilerEnvLookup("CC", defaultcc, goos, goarch))
779 link = append(link, "-L="+pathf("%s/pkg/obj/go-bootstrap/%s_%s", goroot, goos, goarch))
780 link = append(link, "-o", pathf("%s/%s%s", tooldir, elem, exe))
781 targ = len(link) - 1
782 }
783 ttarg := mtime(link[targ])
784
785
786
787
788 files := xreaddir(dir)
789
790
791
792
793
794
795 files = filter(files, func(p string) bool {
796 return !strings.HasPrefix(p, ".") && (!strings.HasPrefix(p, "_") || !strings.HasSuffix(p, ".go"))
797 })
798
799
800 for _, gt := range gentab {
801 if gt.pkg == pkg {
802 files = append(files, gt.file)
803 }
804 }
805 files = uniq(files)
806
807
808 for i, p := range files {
809 if !filepath.IsAbs(p) {
810 files[i] = pathf("%s/%s", dir, p)
811 }
812 }
813
814
815 var gofiles, sfiles []string
816 stale := rebuildall
817 files = filter(files, func(p string) bool {
818 for _, suf := range depsuffix {
819 if strings.HasSuffix(p, suf) {
820 goto ok
821 }
822 }
823 return false
824 ok:
825 t := mtime(p)
826 if !t.IsZero() && !strings.HasSuffix(p, ".a") && !shouldbuild(p, pkg) {
827 return false
828 }
829 if strings.HasSuffix(p, ".go") {
830 gofiles = append(gofiles, p)
831 } else if strings.HasSuffix(p, ".s") {
832 sfiles = append(sfiles, p)
833 }
834 if t.After(ttarg) {
835 stale = true
836 }
837 return true
838 })
839
840
841 if len(files) == 0 {
842 return
843 }
844
845 if !stale {
846 return
847 }
848
849
850 if pkg == "runtime" {
851 xmkdirall(pathf("%s/pkg/include", goroot))
852
853 copyfile(pathf("%s/pkg/include/textflag.h", goroot),
854 pathf("%s/src/runtime/textflag.h", goroot), 0)
855 copyfile(pathf("%s/pkg/include/funcdata.h", goroot),
856 pathf("%s/src/runtime/funcdata.h", goroot), 0)
857 copyfile(pathf("%s/pkg/include/asm_ppc64x.h", goroot),
858 pathf("%s/src/runtime/asm_ppc64x.h", goroot), 0)
859 copyfile(pathf("%s/pkg/include/asm_amd64.h", goroot),
860 pathf("%s/src/runtime/asm_amd64.h", goroot), 0)
861 copyfile(pathf("%s/pkg/include/asm_riscv64.h", goroot),
862 pathf("%s/src/runtime/asm_riscv64.h", goroot), 0)
863 }
864
865
866 for _, gt := range gentab {
867 if gt.pkg != pkg {
868 continue
869 }
870 p := pathf("%s/%s", dir, gt.file)
871 if vflag > 1 {
872 errprintf("generate %s\n", p)
873 }
874 gt.gen(dir, p)
875
876
877
878
879
880
881
882 }
883
884
885
886 importMap := make(map[string]string)
887 for _, p := range gofiles {
888 for _, imp := range readimports(p) {
889 if imp == "C" {
890 fatalf("%s imports C", p)
891 }
892 importMap[imp] = resolveVendor(imp, dir)
893 }
894 }
895 sortedImports := make([]string, 0, len(importMap))
896 for imp := range importMap {
897 sortedImports = append(sortedImports, imp)
898 }
899 sort.Strings(sortedImports)
900
901 for _, dep := range importMap {
902 if dep == "C" {
903 fatalf("%s imports C", pkg)
904 }
905 startInstall(dep)
906 }
907 for _, dep := range importMap {
908 install(dep)
909 }
910
911 if goos != gohostos || goarch != gohostarch {
912
913 if vflag > 1 {
914 errprintf("skip build for cross-compile %s\n", pkg)
915 }
916 return
917 }
918
919 asmArgs := []string{
920 pathf("%s/asm", tooldir),
921 "-I", workdir,
922 "-I", pathf("%s/pkg/include", goroot),
923 "-D", "GOOS_" + goos,
924 "-D", "GOARCH_" + goarch,
925 "-D", "GOOS_GOARCH_" + goos + "_" + goarch,
926 "-p", pkg,
927 }
928 if goarch == "mips" || goarch == "mipsle" {
929
930 asmArgs = append(asmArgs, "-D", "GOMIPS_"+gomips)
931 }
932 if goarch == "mips64" || goarch == "mips64le" {
933
934 asmArgs = append(asmArgs, "-D", "GOMIPS64_"+gomips64)
935 }
936 if goarch == "ppc64" || goarch == "ppc64le" {
937
938 switch goppc64 {
939 case "power10":
940 asmArgs = append(asmArgs, "-D", "GOPPC64_power10")
941 fallthrough
942 case "power9":
943 asmArgs = append(asmArgs, "-D", "GOPPC64_power9")
944 fallthrough
945 default:
946 asmArgs = append(asmArgs, "-D", "GOPPC64_power8")
947 }
948 }
949 if goarch == "riscv64" {
950
951 asmArgs = append(asmArgs, "-D", "GORISCV64_"+goriscv64)
952 }
953 if goarch == "arm" {
954
955
956 switch {
957 case strings.Contains(goarm, "7"):
958 asmArgs = append(asmArgs, "-D", "GOARM_7")
959 fallthrough
960 case strings.Contains(goarm, "6"):
961 asmArgs = append(asmArgs, "-D", "GOARM_6")
962 fallthrough
963 default:
964 asmArgs = append(asmArgs, "-D", "GOARM_5")
965 }
966 }
967 goasmh := pathf("%s/go_asm.h", workdir)
968
969
970 var symabis string
971 if len(sfiles) > 0 {
972 symabis = pathf("%s/symabis", workdir)
973 var wg sync.WaitGroup
974 asmabis := append(asmArgs[:len(asmArgs):len(asmArgs)], "-gensymabis", "-o", symabis)
975 asmabis = append(asmabis, sfiles...)
976 if err := os.WriteFile(goasmh, nil, 0666); err != nil {
977 fatalf("cannot write empty go_asm.h: %s", err)
978 }
979 bgrun(&wg, dir, asmabis...)
980 bgwait(&wg)
981 }
982
983
984 buf := &bytes.Buffer{}
985 for _, imp := range sortedImports {
986 if imp == "unsafe" {
987 continue
988 }
989 dep := importMap[imp]
990 if imp != dep {
991 fmt.Fprintf(buf, "importmap %s=%s\n", imp, dep)
992 }
993 fmt.Fprintf(buf, "packagefile %s=%s\n", dep, packagefile(dep))
994 }
995 importcfg := pathf("%s/importcfg", workdir)
996 if err := os.WriteFile(importcfg, buf.Bytes(), 0666); err != nil {
997 fatalf("cannot write importcfg file: %v", err)
998 }
999
1000 var archive string
1001
1002
1003
1004
1005 pkgName := pkg
1006 if strings.HasPrefix(pkg, "cmd/") && strings.Count(pkg, "/") == 1 {
1007 pkgName = "main"
1008 }
1009 b := pathf("%s/_go_.a", workdir)
1010 clean = append(clean, b)
1011 if !ispackcmd {
1012 link = append(link, b)
1013 } else {
1014 archive = b
1015 }
1016
1017
1018 compile := []string{pathf("%s/compile", tooldir), "-std", "-pack", "-o", b, "-p", pkgName, "-importcfg", importcfg}
1019 if gogcflags != "" {
1020 compile = append(compile, strings.Fields(gogcflags)...)
1021 }
1022 if len(sfiles) > 0 {
1023 compile = append(compile, "-asmhdr", goasmh)
1024 }
1025 if symabis != "" {
1026 compile = append(compile, "-symabis", symabis)
1027 }
1028 if goos == "android" {
1029 compile = append(compile, "-shared")
1030 }
1031
1032 compile = append(compile, gofiles...)
1033 var wg sync.WaitGroup
1034
1035
1036
1037 bgrun(&wg, dir, compile...)
1038 bgwait(&wg)
1039
1040
1041 for _, p := range sfiles {
1042
1043 compile := asmArgs[:len(asmArgs):len(asmArgs)]
1044
1045 doclean := true
1046 b := pathf("%s/%s", workdir, filepath.Base(p))
1047
1048
1049 b = b[:len(b)-1] + "o"
1050 compile = append(compile, "-o", b, p)
1051 bgrun(&wg, dir, compile...)
1052
1053 link = append(link, b)
1054 if doclean {
1055 clean = append(clean, b)
1056 }
1057 }
1058 bgwait(&wg)
1059
1060 if ispackcmd {
1061 xremove(link[targ])
1062 dopack(link[targ], archive, link[targ+1:])
1063 return
1064 }
1065
1066
1067 xremove(link[targ])
1068 bgrun(&wg, "", link...)
1069 bgwait(&wg)
1070 }
1071
1072
1073
1074 func packagefile(pkg string) string {
1075 return pathf("%s/pkg/obj/go-bootstrap/%s_%s/%s.a", goroot, goos, goarch, pkg)
1076 }
1077
1078
1079
1080 var unixOS = map[string]bool{
1081 "aix": true,
1082 "android": true,
1083 "darwin": true,
1084 "dragonfly": true,
1085 "freebsd": true,
1086 "hurd": true,
1087 "illumos": true,
1088 "ios": true,
1089 "linux": true,
1090 "netbsd": true,
1091 "openbsd": true,
1092 "solaris": true,
1093 }
1094
1095
1096 func matchtag(tag string) bool {
1097 switch tag {
1098 case "gc", "cmd_go_bootstrap", "go1.1":
1099 return true
1100 case "linux":
1101 return goos == "linux" || goos == "android"
1102 case "solaris":
1103 return goos == "solaris" || goos == "illumos"
1104 case "darwin":
1105 return goos == "darwin" || goos == "ios"
1106 case goos, goarch:
1107 return true
1108 case "unix":
1109 return unixOS[goos]
1110 default:
1111 return false
1112 }
1113 }
1114
1115
1116
1117
1118
1119
1120
1121 func shouldbuild(file, pkg string) bool {
1122
1123 name := filepath.Base(file)
1124 excluded := func(list []string, ok string) bool {
1125 for _, x := range list {
1126 if x == ok || (ok == "android" && x == "linux") || (ok == "illumos" && x == "solaris") || (ok == "ios" && x == "darwin") {
1127 continue
1128 }
1129 i := strings.Index(name, x)
1130 if i <= 0 || name[i-1] != '_' {
1131 continue
1132 }
1133 i += len(x)
1134 if i == len(name) || name[i] == '.' || name[i] == '_' {
1135 return true
1136 }
1137 }
1138 return false
1139 }
1140 if excluded(okgoos, goos) || excluded(okgoarch, goarch) {
1141 return false
1142 }
1143
1144
1145 if strings.Contains(name, "_test") {
1146 return false
1147 }
1148
1149
1150 for p := range strings.SplitSeq(readfile(file), "\n") {
1151 p = strings.TrimSpace(p)
1152 if p == "" {
1153 continue
1154 }
1155 code := p
1156 i := strings.Index(code, "//")
1157 if i > 0 {
1158 code = strings.TrimSpace(code[:i])
1159 }
1160 if code == "package documentation" {
1161 return false
1162 }
1163 if code == "package main" && pkg != "cmd/go" && pkg != "cmd/cgo" {
1164 return false
1165 }
1166 if !strings.HasPrefix(p, "//") {
1167 break
1168 }
1169 if strings.HasPrefix(p, "//go:build ") {
1170 c, err := constraint.Parse(p)
1171 if err != nil {
1172 errprintf("%s: parsing //go:build line: %v", file, err)
1173 return false
1174 }
1175 return c.Eval(matchtag)
1176 }
1177 }
1178
1179 return true
1180 }
1181
1182
1183 func copyfile(dst, src string, flag int) {
1184 if vflag > 1 {
1185 errprintf("cp %s %s\n", src, dst)
1186 }
1187 writefile(readfile(src), dst, flag)
1188 }
1189
1190
1191
1192
1193 func dopack(dst, src string, extra []string) {
1194 bdst := bytes.NewBufferString(readfile(src))
1195 for _, file := range extra {
1196 b := readfile(file)
1197
1198 i := strings.LastIndex(file, "/") + 1
1199 j := strings.LastIndex(file, `\`) + 1
1200 if i < j {
1201 i = j
1202 }
1203 fmt.Fprintf(bdst, "%-16.16s%-12d%-6d%-6d%-8o%-10d`\n", file[i:], 0, 0, 0, 0644, len(b))
1204 bdst.WriteString(b)
1205 if len(b)&1 != 0 {
1206 bdst.WriteByte(0)
1207 }
1208 }
1209 writefile(bdst.String(), dst, 0)
1210 }
1211
1212 func clean() {
1213 generated := []byte(generatedHeader)
1214
1215
1216 filepath.WalkDir(pathf("%s/src", goroot), func(path string, d fs.DirEntry, err error) error {
1217 switch {
1218 case err != nil:
1219
1220 case d.IsDir() && (d.Name() == "vendor" || d.Name() == "testdata"):
1221 return filepath.SkipDir
1222 case d.IsDir() && d.Name() != "dist":
1223
1224 exe := filepath.Join(path, d.Name())
1225 if info, err := os.Stat(exe); err == nil && !info.IsDir() {
1226 xremove(exe)
1227 }
1228 xremove(exe + ".exe")
1229 case !d.IsDir() && strings.HasPrefix(d.Name(), "z"):
1230
1231 head := make([]byte, 512)
1232 if f, err := os.Open(path); err == nil {
1233 io.ReadFull(f, head)
1234 f.Close()
1235 }
1236 if bytes.HasPrefix(head, generated) {
1237 xremove(path)
1238 }
1239 }
1240 return nil
1241 })
1242
1243 if rebuildall {
1244
1245 xremoveall(pathf("%s/pkg/obj/%s_%s", goroot, gohostos, gohostarch))
1246
1247
1248 xremoveall(pathf("%s/pkg/%s_%s", goroot, gohostos, gohostarch))
1249 xremoveall(pathf("%s/pkg/%s_%s", goroot, goos, goarch))
1250 xremoveall(pathf("%s/pkg/%s_%s_race", goroot, gohostos, gohostarch))
1251 xremoveall(pathf("%s/pkg/%s_%s_race", goroot, goos, goarch))
1252 xremoveall(tooldir)
1253
1254
1255 xremove(pathf("%s/VERSION.cache", goroot))
1256
1257
1258 xremoveall(pathf("%s/pkg/distpack", goroot))
1259 }
1260 }
1261
1262
1265
1266
1267 func cmdenv() {
1268 path := flag.Bool("p", false, "emit updated PATH")
1269 plan9 := flag.Bool("9", gohostos == "plan9", "emit plan 9 syntax")
1270 windows := flag.Bool("w", gohostos == "windows", "emit windows syntax")
1271 xflagparse(0)
1272
1273 format := "%s=\"%s\";\n"
1274 switch {
1275 case *plan9:
1276 format = "%s='%s'\n"
1277 case *windows:
1278 format = "set %s=%s\r\n"
1279 }
1280
1281 xprintf(format, "GO111MODULE", "")
1282 xprintf(format, "GOARCH", goarch)
1283 xprintf(format, "GOBIN", gorootBin)
1284 xprintf(format, "GODEBUG", os.Getenv("GODEBUG"))
1285 xprintf(format, "GOENV", "off")
1286 xprintf(format, "GOFLAGS", "")
1287 xprintf(format, "GOHOSTARCH", gohostarch)
1288 xprintf(format, "GOHOSTOS", gohostos)
1289 xprintf(format, "GOOS", goos)
1290 xprintf(format, "GOPROXY", os.Getenv("GOPROXY"))
1291 xprintf(format, "GOROOT", goroot)
1292 xprintf(format, "GOTMPDIR", os.Getenv("GOTMPDIR"))
1293 xprintf(format, "GOTOOLDIR", tooldir)
1294 if goarch == "arm" {
1295 xprintf(format, "GOARM", goarm)
1296 }
1297 if goarch == "arm64" {
1298 xprintf(format, "GOARM64", goarm64)
1299 }
1300 if goarch == "386" {
1301 xprintf(format, "GO386", go386)
1302 }
1303 if goarch == "amd64" {
1304 xprintf(format, "GOAMD64", goamd64)
1305 }
1306 if goarch == "mips" || goarch == "mipsle" {
1307 xprintf(format, "GOMIPS", gomips)
1308 }
1309 if goarch == "mips64" || goarch == "mips64le" {
1310 xprintf(format, "GOMIPS64", gomips64)
1311 }
1312 if goarch == "ppc64" || goarch == "ppc64le" {
1313 xprintf(format, "GOPPC64", goppc64)
1314 }
1315 if goarch == "riscv64" {
1316 xprintf(format, "GORISCV64", goriscv64)
1317 }
1318 xprintf(format, "GOWORK", "off")
1319
1320 if *path {
1321 sep := ":"
1322 if gohostos == "windows" {
1323 sep = ";"
1324 }
1325 xprintf(format, "PATH", fmt.Sprintf("%s%s%s", gorootBin, sep, os.Getenv("PATH")))
1326
1327
1328
1329
1330 var exportFormat string
1331 if !*windows && !*plan9 {
1332 exportFormat = "export " + format
1333 } else {
1334 exportFormat = format
1335 }
1336 xprintf(exportFormat, "DIST_UNMODIFIED_PATH", os.Getenv("PATH"))
1337 }
1338 }
1339
1340 var (
1341 timeLogEnabled = os.Getenv("GOBUILDTIMELOGFILE") != ""
1342 timeLogMu sync.Mutex
1343 timeLogFile *os.File
1344 timeLogStart time.Time
1345 )
1346
1347 func timelog(op, name string) {
1348 if !timeLogEnabled {
1349 return
1350 }
1351 timeLogMu.Lock()
1352 defer timeLogMu.Unlock()
1353 if timeLogFile == nil {
1354 f, err := os.OpenFile(os.Getenv("GOBUILDTIMELOGFILE"), os.O_RDWR|os.O_APPEND, 0666)
1355 if err != nil {
1356 log.Fatal(err)
1357 }
1358 buf := make([]byte, 100)
1359 n, _ := f.Read(buf)
1360 s := string(buf[:n])
1361 if i := strings.Index(s, "\n"); i >= 0 {
1362 s = s[:i]
1363 }
1364 i := strings.Index(s, " start")
1365 if i < 0 {
1366 log.Fatalf("time log %s does not begin with start line", os.Getenv("GOBUILDTIMELOGFILE"))
1367 }
1368 t, err := time.Parse(time.UnixDate, s[:i])
1369 if err != nil {
1370 log.Fatalf("cannot parse time log line %q: %v", s, err)
1371 }
1372 timeLogStart = t
1373 timeLogFile = f
1374 }
1375 t := time.Now()
1376 fmt.Fprintf(timeLogFile, "%s %+.1fs %s %s\n", t.Format(time.UnixDate), t.Sub(timeLogStart).Seconds(), op, name)
1377 }
1378
1379
1380
1381
1382
1383
1384 func toolenv() []string {
1385 var env []string
1386 if !mustLinkExternal(goos, goarch, false) {
1387
1388
1389
1390
1391 env = append(env, "CGO_ENABLED=0")
1392 }
1393 if isRelease || os.Getenv("GO_BUILDER_NAME") != "" {
1394
1395
1396
1397
1398
1399 env = append(env, "GOFLAGS=-trimpath -ldflags=-w -gcflags=cmd/...=-dwarf=false")
1400 }
1401 return env
1402 }
1403
1404 var (
1405 toolchain = []string{"cmd/asm", "cmd/cgo", "cmd/compile", "cmd/link", "cmd/preprofile"}
1406
1407
1408 binExesIncludedInDistpack = []string{"cmd/go", "cmd/gofmt"}
1409
1410
1411 toolsIncludedInDistpack = []string{"cmd/asm", "cmd/cgo", "cmd/compile", "cmd/cover", "cmd/fix", "cmd/link", "cmd/preprofile", "cmd/vet"}
1412
1413
1414
1415
1416
1417 toolsToInstall = slices.Concat(binExesIncludedInDistpack, toolsIncludedInDistpack)
1418 )
1419
1420
1421
1422
1423
1424
1425
1426
1427 func cmdbootstrap() {
1428 timelog("start", "dist bootstrap")
1429 defer timelog("end", "dist bootstrap")
1430
1431 var debug, distpack, force, noBanner, noClean bool
1432 flag.BoolVar(&rebuildall, "a", rebuildall, "rebuild all")
1433 flag.BoolVar(&debug, "d", debug, "enable debugging of bootstrap process")
1434 flag.BoolVar(&distpack, "distpack", distpack, "write distribution files to pkg/distpack")
1435 flag.BoolVar(&force, "force", force, "build even if the port is marked as broken")
1436 flag.BoolVar(&noBanner, "no-banner", noBanner, "do not print banner")
1437 flag.BoolVar(&noClean, "no-clean", noClean, "print deprecation warning")
1438
1439 xflagparse(0)
1440
1441 if noClean {
1442 xprintf("warning: --no-clean is deprecated and has no effect; use 'go install std cmd' instead\n")
1443 }
1444
1445
1446 if broken[goos+"/"+goarch] && !force {
1447 fatalf("build stopped because the port %s/%s is marked as broken\n\n"+
1448 "Use the -force flag to build anyway.\n", goos, goarch)
1449 }
1450
1451
1452
1453
1454
1455
1456 os.Setenv("GOPATH", pathf("%s/pkg/obj/gopath", goroot))
1457
1458
1459
1460
1461
1462 os.Setenv("GOPROXY", "off")
1463
1464
1465
1466
1467 oldgocache = os.Getenv("GOCACHE")
1468 os.Setenv("GOCACHE", pathf("%s/pkg/obj/go-build", goroot))
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482 os.Setenv("GOEXPERIMENT", "none")
1483
1484 if isdir(pathf("%s/src/pkg", goroot)) {
1485 fatalf("\n\n"+
1486 "The Go package sources have moved to $GOROOT/src.\n"+
1487 "*** %s still exists. ***\n"+
1488 "It probably contains stale files that may confuse the build.\n"+
1489 "Please (check what's there and) remove it and try again.\n"+
1490 "See https://golang.org/s/go14nopkg\n",
1491 pathf("%s/src/pkg", goroot))
1492 }
1493
1494 if rebuildall {
1495 clean()
1496 }
1497
1498 setup()
1499
1500 timelog("build", "toolchain1")
1501 checkCC()
1502 bootstrapBuildTools()
1503
1504
1505 oldBinFiles, err := filepath.Glob(pathf("%s/bin/*", goroot))
1506 if err != nil {
1507 fatalf("glob: %v", err)
1508 }
1509
1510
1511 oldgoos = goos
1512 oldgoarch = goarch
1513 goos = gohostos
1514 goarch = gohostarch
1515 os.Setenv("GOHOSTARCH", gohostarch)
1516 os.Setenv("GOHOSTOS", gohostos)
1517 os.Setenv("GOARCH", goarch)
1518 os.Setenv("GOOS", goos)
1519
1520 timelog("build", "go_bootstrap")
1521 xprintf("Building Go bootstrap cmd/go (go_bootstrap) using Go toolchain1.\n")
1522 install("runtime")
1523 install("time/tzdata")
1524 install("cmd/go")
1525 if vflag > 0 {
1526 xprintf("\n")
1527 }
1528
1529 gogcflags = os.Getenv("GO_GCFLAGS")
1530 setNoOpt()
1531 goldflags = os.Getenv("GO_LDFLAGS")
1532 goBootstrap := pathf("%s/go_bootstrap", tooldir)
1533 if debug {
1534 run("", ShowOutput|CheckExit, pathf("%s/compile", tooldir), "-V=full")
1535 copyfile(pathf("%s/compile1", tooldir), pathf("%s/compile", tooldir), writeExec)
1536 }
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554 timelog("build", "toolchain2")
1555 if vflag > 0 {
1556 xprintf("\n")
1557 }
1558 xprintf("Building Go toolchain2 using go_bootstrap and Go toolchain1.\n")
1559 os.Setenv("CC", compilerEnvLookup("CC", defaultcc, goos, goarch))
1560
1561 os.Setenv("GOEXPERIMENT", goexperiment)
1562
1563 goInstall(toolenv(), goBootstrap, append([]string{"-pgo=off"}, toolchain...)...)
1564 if debug {
1565 run("", ShowOutput|CheckExit, pathf("%s/compile", tooldir), "-V=full")
1566 copyfile(pathf("%s/compile2", tooldir), pathf("%s/compile", tooldir), writeExec)
1567 }
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585 timelog("build", "toolchain3")
1586 if vflag > 0 {
1587 xprintf("\n")
1588 }
1589 xprintf("Building Go toolchain3 using go_bootstrap and Go toolchain2.\n")
1590 goInstall(toolenv(), goBootstrap, append([]string{"-a"}, toolchain...)...)
1591 if debug {
1592 run("", ShowOutput|CheckExit, pathf("%s/compile", tooldir), "-V=full")
1593 copyfile(pathf("%s/compile3", tooldir), pathf("%s/compile", tooldir), writeExec)
1594 }
1595
1596
1597
1598
1599
1600
1601 if _, err := os.Stat(pathf("%s/VERSION", goroot)); err == nil {
1602
1603
1604
1605
1606
1607
1608 } else {
1609 os.Setenv("GOCACHE", oldgocache)
1610 }
1611
1612 if goos == oldgoos && goarch == oldgoarch {
1613
1614 timelog("build", "toolchain")
1615 if vflag > 0 {
1616 xprintf("\n")
1617 }
1618 xprintf("Building packages and commands for %s/%s.\n", goos, goarch)
1619 } else {
1620
1621
1622
1623 timelog("build", "host toolchain")
1624 if vflag > 0 {
1625 xprintf("\n")
1626 }
1627 xprintf("Building commands for host, %s/%s.\n", goos, goarch)
1628 goInstall(toolenv(), goBootstrap, toolsToInstall...)
1629 checkNotStale(toolenv(), goBootstrap, toolsToInstall...)
1630 checkNotStale(toolenv(), gorootBinGo, toolsToInstall...)
1631
1632 timelog("build", "target toolchain")
1633 if vflag > 0 {
1634 xprintf("\n")
1635 }
1636 goos = oldgoos
1637 goarch = oldgoarch
1638 os.Setenv("GOOS", goos)
1639 os.Setenv("GOARCH", goarch)
1640 os.Setenv("CC", compilerEnvLookup("CC", defaultcc, goos, goarch))
1641 xprintf("Building packages and commands for target, %s/%s.\n", goos, goarch)
1642 }
1643 goInstall(nil, goBootstrap, "std")
1644 goInstall(toolenv(), goBootstrap, toolsToInstall...)
1645 checkNotStale(toolenv(), goBootstrap, toolchain...)
1646 checkNotStale(nil, goBootstrap, "std")
1647 checkNotStale(toolenv(), goBootstrap, toolsToInstall...)
1648 checkNotStale(nil, gorootBinGo, "std")
1649 checkNotStale(toolenv(), gorootBinGo, toolsToInstall...)
1650 if debug {
1651 run("", ShowOutput|CheckExit, pathf("%s/compile", tooldir), "-V=full")
1652 checkNotStale(toolenv(), goBootstrap, toolchain...)
1653 copyfile(pathf("%s/compile4", tooldir), pathf("%s/compile", tooldir), writeExec)
1654 }
1655
1656
1657
1658 binFiles, err := filepath.Glob(pathf("%s/bin/*", goroot))
1659 if err != nil {
1660 fatalf("glob: %v", err)
1661 }
1662
1663 ok := map[string]bool{}
1664 for _, f := range oldBinFiles {
1665 ok[f] = true
1666 }
1667 for _, f := range binFiles {
1668 if gohostos == "darwin" && filepath.Base(f) == ".DS_Store" {
1669 continue
1670 }
1671 elem := strings.TrimSuffix(filepath.Base(f), ".exe")
1672 if !ok[f] && elem != "go" && elem != "gofmt" && elem != goos+"_"+goarch {
1673 fatalf("unexpected new file in $GOROOT/bin: %s", elem)
1674 }
1675 }
1676
1677
1678 xremove(pathf("%s/go_bootstrap"+exe, tooldir))
1679
1680 if goos == "android" {
1681
1682 xremove(pathf("%s/go_android_exec-adb-sync-status", os.TempDir()))
1683 }
1684
1685 if wrapperPath := wrapperPathFor(goos, goarch); wrapperPath != "" {
1686 oldcc := os.Getenv("CC")
1687 os.Setenv("GOOS", gohostos)
1688 os.Setenv("GOARCH", gohostarch)
1689 os.Setenv("CC", compilerEnvLookup("CC", defaultcc, gohostos, gohostarch))
1690 goCmd(nil, gorootBinGo, "build", "-o", pathf("%s/go_%s_%s_exec%s", gorootBin, goos, goarch, exe), wrapperPath)
1691
1692
1693 os.Setenv("GOOS", goos)
1694 os.Setenv("GOARCH", goarch)
1695 os.Setenv("CC", oldcc)
1696 }
1697
1698 if distpack {
1699 xprintf("Packaging archives for %s/%s.\n", goos, goarch)
1700 run("", ShowOutput|CheckExit, gorootBinGo, "tool", "distpack")
1701 }
1702
1703
1704 if !noBanner {
1705 banner()
1706 }
1707 }
1708
1709 func wrapperPathFor(goos, goarch string) string {
1710 switch {
1711 case goos == "android":
1712 if gohostos != "android" {
1713 return pathf("%s/misc/go_android_exec/main.go", goroot)
1714 }
1715 case goos == "ios":
1716 if gohostos != "ios" {
1717 return pathf("%s/misc/ios/go_ios_exec.go", goroot)
1718 }
1719 }
1720 return ""
1721 }
1722
1723 func goInstall(env []string, goBinary string, args ...string) {
1724 goCmd(env, goBinary, "install", args...)
1725 }
1726
1727 func appendCompilerFlags(args []string) []string {
1728 if gogcflags != "" {
1729 args = append(args, "-gcflags=all="+gogcflags)
1730 }
1731 if goldflags != "" {
1732 args = append(args, "-ldflags=all="+goldflags)
1733 }
1734 return args
1735 }
1736
1737 func goCmd(env []string, goBinary string, cmd string, args ...string) {
1738 goCmd := []string{goBinary, cmd}
1739 if noOpt {
1740 goCmd = append(goCmd, "-tags=noopt")
1741 }
1742 goCmd = appendCompilerFlags(goCmd)
1743 if vflag > 0 {
1744 goCmd = append(goCmd, "-v")
1745 }
1746
1747
1748 if gohostos == "plan9" && os.Getenv("sysname") == "vx32" {
1749 goCmd = append(goCmd, "-p=1")
1750 }
1751
1752 runEnv(workdir, ShowOutput|CheckExit, env, append(goCmd, args...)...)
1753 }
1754
1755 func checkNotStale(env []string, goBinary string, targets ...string) {
1756 goCmd := []string{goBinary, "list"}
1757 if noOpt {
1758 goCmd = append(goCmd, "-tags=noopt")
1759 }
1760 goCmd = appendCompilerFlags(goCmd)
1761 goCmd = append(goCmd, "-f={{if .Stale}}\tSTALE {{.ImportPath}}: {{.StaleReason}}{{end}}")
1762
1763 out := runEnv(workdir, CheckExit, env, append(goCmd, targets...)...)
1764 if strings.Contains(out, "\tSTALE ") {
1765 os.Setenv("GODEBUG", "gocachehash=1")
1766 for _, target := range []string{"internal/runtime/sys", "cmd/dist", "cmd/link"} {
1767 if strings.Contains(out, "STALE "+target) {
1768 run(workdir, ShowOutput|CheckExit, goBinary, "list", "-f={{.ImportPath}} {{.Stale}}", target)
1769 break
1770 }
1771 }
1772 fatalf("unexpected stale targets reported by %s list -gcflags=\"%s\" -ldflags=\"%s\" for %v (consider rerunning with GOMAXPROCS=1 GODEBUG=gocachehash=1):\n%s", goBinary, gogcflags, goldflags, targets, out)
1773 }
1774 }
1775
1776
1777
1778
1779
1780
1781
1782
1783 var cgoEnabled = map[string]bool{
1784 "aix/ppc64": true,
1785 "darwin/amd64": true,
1786 "darwin/arm64": true,
1787 "dragonfly/amd64": true,
1788 "freebsd/386": true,
1789 "freebsd/amd64": true,
1790 "freebsd/arm": true,
1791 "freebsd/arm64": true,
1792 "freebsd/riscv64": true,
1793 "illumos/amd64": true,
1794 "linux/386": true,
1795 "linux/amd64": true,
1796 "linux/arm": true,
1797 "linux/arm64": true,
1798 "linux/loong64": true,
1799 "linux/ppc64": false,
1800 "linux/ppc64le": true,
1801 "linux/mips": true,
1802 "linux/mipsle": true,
1803 "linux/mips64": true,
1804 "linux/mips64le": true,
1805 "linux/riscv64": true,
1806 "linux/s390x": true,
1807 "linux/sparc64": true,
1808 "android/386": true,
1809 "android/amd64": true,
1810 "android/arm": true,
1811 "android/arm64": true,
1812 "ios/arm64": true,
1813 "ios/amd64": true,
1814 "js/wasm": false,
1815 "wasip1/wasm": false,
1816 "netbsd/386": true,
1817 "netbsd/amd64": true,
1818 "netbsd/arm": true,
1819 "netbsd/arm64": true,
1820 "openbsd/386": true,
1821 "openbsd/amd64": true,
1822 "openbsd/arm": true,
1823 "openbsd/arm64": true,
1824 "openbsd/ppc64": false,
1825 "openbsd/riscv64": true,
1826 "plan9/386": false,
1827 "plan9/amd64": false,
1828 "plan9/arm": false,
1829 "solaris/amd64": true,
1830 "windows/386": true,
1831 "windows/amd64": true,
1832 "windows/arm64": true,
1833 }
1834
1835
1836
1837
1838
1839 var broken = map[string]bool{
1840 "freebsd/riscv64": true,
1841 "linux/sparc64": true,
1842 }
1843
1844
1845 var firstClass = map[string]bool{
1846 "darwin/amd64": true,
1847 "darwin/arm64": true,
1848 "linux/386": true,
1849 "linux/amd64": true,
1850 "linux/arm": true,
1851 "linux/arm64": true,
1852 "windows/386": true,
1853 "windows/amd64": true,
1854 }
1855
1856
1857
1858 func needCC() bool {
1859 return os.Getenv("CGO_ENABLED") == "1" || mustLinkExternal(gohostos, gohostarch, false)
1860 }
1861
1862 func checkCC() {
1863 if !needCC() {
1864 return
1865 }
1866 cc1 := defaultcc[""]
1867 if cc1 == "" {
1868 cc1 = "gcc"
1869 for _, os := range clangos {
1870 if gohostos == os {
1871 cc1 = "clang"
1872 break
1873 }
1874 }
1875 }
1876 cc, err := quotedSplit(cc1)
1877 if err != nil {
1878 fatalf("split CC: %v", err)
1879 }
1880 var ccHelp = append(cc, "--help")
1881
1882 if output, err := exec.Command(ccHelp[0], ccHelp[1:]...).CombinedOutput(); err != nil {
1883 outputHdr := ""
1884 if len(output) > 0 {
1885 outputHdr = "\nCommand output:\n\n"
1886 }
1887 fatalf("cannot invoke C compiler %q: %v\n\n"+
1888 "Go needs a system C compiler for use with cgo.\n"+
1889 "To set a C compiler, set CC=the-compiler.\n"+
1890 "To disable cgo, set CGO_ENABLED=0.\n%s%s", cc, err, outputHdr, output)
1891 }
1892 }
1893
1894 func defaulttarg() string {
1895
1896
1897
1898
1899 pwd := xgetwd()
1900 src := pathf("%s/src/", goroot)
1901 real_src := xrealwd(src)
1902 if !strings.HasPrefix(pwd, real_src) {
1903 fatalf("current directory %s is not under %s", pwd, real_src)
1904 }
1905 pwd = pwd[len(real_src):]
1906
1907 pwd = strings.TrimPrefix(pwd, "/")
1908
1909 return pwd
1910 }
1911
1912
1913 func cmdinstall() {
1914 xflagparse(-1)
1915
1916 if flag.NArg() == 0 {
1917 install(defaulttarg())
1918 }
1919
1920 for _, arg := range flag.Args() {
1921 install(arg)
1922 }
1923 }
1924
1925
1926 func cmdclean() {
1927 xflagparse(0)
1928 clean()
1929 }
1930
1931
1932 func cmdbanner() {
1933 xflagparse(0)
1934 banner()
1935 }
1936
1937 func banner() {
1938 if vflag > 0 {
1939 xprintf("\n")
1940 }
1941 xprintf("---\n")
1942 xprintf("Installed Go for %s/%s in %s\n", goos, goarch, goroot)
1943 xprintf("Installed commands in %s\n", gorootBin)
1944
1945 if gohostos == "plan9" {
1946
1947 pid := strings.ReplaceAll(readfile("#c/pid"), " ", "")
1948 ns := fmt.Sprintf("/proc/%s/ns", pid)
1949 if !strings.Contains(readfile(ns), fmt.Sprintf("bind -b %s /bin", gorootBin)) {
1950 xprintf("*** You need to bind %s before /bin.\n", gorootBin)
1951 }
1952 } else {
1953
1954 pathsep := ":"
1955 if gohostos == "windows" {
1956 pathsep = ";"
1957 }
1958 path := os.Getenv("PATH")
1959 if p, ok := os.LookupEnv("DIST_UNMODIFIED_PATH"); ok {
1960
1961
1962
1963
1964 path = p
1965 }
1966 if !strings.Contains(pathsep+path+pathsep, pathsep+gorootBin+pathsep) {
1967 xprintf("*** You need to add %s to your PATH.\n", gorootBin)
1968 }
1969 }
1970 }
1971
1972
1973 func cmdversion() {
1974 xflagparse(0)
1975 xprintf("%s\n", findgoversion())
1976 }
1977
1978
1979 func cmdlist() {
1980 jsonFlag := flag.Bool("json", false, "produce JSON output")
1981 brokenFlag := flag.Bool("broken", false, "include broken ports")
1982 xflagparse(0)
1983
1984 var plats []string
1985 for p := range cgoEnabled {
1986 if broken[p] && !*brokenFlag {
1987 continue
1988 }
1989 plats = append(plats, p)
1990 }
1991 sort.Strings(plats)
1992
1993 if !*jsonFlag {
1994 for _, p := range plats {
1995 xprintf("%s\n", p)
1996 }
1997 return
1998 }
1999
2000 type jsonResult struct {
2001 GOOS string
2002 GOARCH string
2003 CgoSupported bool
2004 FirstClass bool
2005 Broken bool `json:",omitempty"`
2006 }
2007 var results []jsonResult
2008 for _, p := range plats {
2009 fields := strings.Split(p, "/")
2010 results = append(results, jsonResult{
2011 GOOS: fields[0],
2012 GOARCH: fields[1],
2013 CgoSupported: cgoEnabled[p],
2014 FirstClass: firstClass[p],
2015 Broken: broken[p],
2016 })
2017 }
2018 out, err := json.MarshalIndent(results, "", "\t")
2019 if err != nil {
2020 fatalf("json marshal error: %v", err)
2021 }
2022 if _, err := os.Stdout.Write(out); err != nil {
2023 fatalf("write failed: %v", err)
2024 }
2025 }
2026
2027 func setNoOpt() {
2028 for gcflag := range strings.SplitSeq(gogcflags, " ") {
2029 if gcflag == "-N" || gcflag == "-l" {
2030 noOpt = true
2031 break
2032 }
2033 }
2034 }
2035
View as plain text