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" {
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 "-std",
928 }
929 if goarch == "mips" || goarch == "mipsle" {
930
931 asmArgs = append(asmArgs, "-D", "GOMIPS_"+gomips)
932 }
933 if goarch == "mips64" || goarch == "mips64le" {
934
935 asmArgs = append(asmArgs, "-D", "GOMIPS64_"+gomips64)
936 }
937 if goarch == "ppc64" || goarch == "ppc64le" {
938
939 switch goppc64 {
940 case "power10":
941 asmArgs = append(asmArgs, "-D", "GOPPC64_power10")
942 fallthrough
943 case "power9":
944 asmArgs = append(asmArgs, "-D", "GOPPC64_power9")
945 fallthrough
946 default:
947 asmArgs = append(asmArgs, "-D", "GOPPC64_power8")
948 }
949 }
950 if goarch == "riscv64" {
951
952 asmArgs = append(asmArgs, "-D", "GORISCV64_"+goriscv64)
953 }
954 if goarch == "arm" {
955
956
957 switch {
958 case strings.Contains(goarm, "7"):
959 asmArgs = append(asmArgs, "-D", "GOARM_7")
960 fallthrough
961 case strings.Contains(goarm, "6"):
962 asmArgs = append(asmArgs, "-D", "GOARM_6")
963 fallthrough
964 default:
965 asmArgs = append(asmArgs, "-D", "GOARM_5")
966 }
967 }
968 goasmh := pathf("%s/go_asm.h", workdir)
969
970
971 var symabis string
972 if len(sfiles) > 0 {
973 symabis = pathf("%s/symabis", workdir)
974 var wg sync.WaitGroup
975 asmabis := append(asmArgs[:len(asmArgs):len(asmArgs)], "-gensymabis", "-o", symabis)
976 asmabis = append(asmabis, sfiles...)
977 if err := os.WriteFile(goasmh, nil, 0666); err != nil {
978 fatalf("cannot write empty go_asm.h: %s", err)
979 }
980 bgrun(&wg, dir, asmabis...)
981 bgwait(&wg)
982 }
983
984
985 buf := &bytes.Buffer{}
986 for _, imp := range sortedImports {
987 if imp == "unsafe" {
988 continue
989 }
990 dep := importMap[imp]
991 if imp != dep {
992 fmt.Fprintf(buf, "importmap %s=%s\n", imp, dep)
993 }
994 fmt.Fprintf(buf, "packagefile %s=%s\n", dep, packagefile(dep))
995 }
996 importcfg := pathf("%s/importcfg", workdir)
997 if err := os.WriteFile(importcfg, buf.Bytes(), 0666); err != nil {
998 fatalf("cannot write importcfg file: %v", err)
999 }
1000
1001 var archive string
1002
1003
1004
1005
1006 pkgName := pkg
1007 if strings.HasPrefix(pkg, "cmd/") && strings.Count(pkg, "/") == 1 {
1008 pkgName = "main"
1009 }
1010 b := pathf("%s/_go_.a", workdir)
1011 clean = append(clean, b)
1012 if !ispackcmd {
1013 link = append(link, b)
1014 } else {
1015 archive = b
1016 }
1017
1018
1019 compile := []string{pathf("%s/compile", tooldir), "-std", "-pack", "-o", b, "-p", pkgName, "-importcfg", importcfg}
1020 if gogcflags != "" {
1021 compile = append(compile, strings.Fields(gogcflags)...)
1022 }
1023 if len(sfiles) > 0 {
1024 compile = append(compile, "-asmhdr", goasmh)
1025 }
1026 if symabis != "" {
1027 compile = append(compile, "-symabis", symabis)
1028 }
1029 if goos == "android" {
1030 compile = append(compile, "-shared")
1031 }
1032
1033 compile = append(compile, gofiles...)
1034 var wg sync.WaitGroup
1035
1036
1037
1038 bgrun(&wg, dir, compile...)
1039 bgwait(&wg)
1040
1041
1042 for _, p := range sfiles {
1043
1044 compile := asmArgs[:len(asmArgs):len(asmArgs)]
1045
1046 doclean := true
1047 b := pathf("%s/%s", workdir, filepath.Base(p))
1048
1049
1050 b = b[:len(b)-1] + "o"
1051 compile = append(compile, "-o", b, p)
1052 bgrun(&wg, dir, compile...)
1053
1054 link = append(link, b)
1055 if doclean {
1056 clean = append(clean, b)
1057 }
1058 }
1059 bgwait(&wg)
1060
1061 if ispackcmd {
1062 xremove(link[targ])
1063 dopack(link[targ], archive, link[targ+1:])
1064 return
1065 }
1066
1067
1068 xremove(link[targ])
1069 bgrun(&wg, "", link...)
1070 bgwait(&wg)
1071 }
1072
1073
1074
1075 func packagefile(pkg string) string {
1076 return pathf("%s/pkg/obj/go-bootstrap/%s_%s/%s.a", goroot, goos, goarch, pkg)
1077 }
1078
1079
1080
1081 var unixOS = map[string]bool{
1082 "aix": true,
1083 "android": true,
1084 "darwin": true,
1085 "dragonfly": true,
1086 "freebsd": true,
1087 "hurd": true,
1088 "illumos": true,
1089 "ios": true,
1090 "linux": true,
1091 "netbsd": true,
1092 "openbsd": true,
1093 "solaris": true,
1094 }
1095
1096
1097 func matchtag(tag string) bool {
1098 switch tag {
1099 case "gc", "cmd_go_bootstrap", "go1.1":
1100 return true
1101 case "linux":
1102 return goos == "linux" || goos == "android"
1103 case "solaris":
1104 return goos == "solaris" || goos == "illumos"
1105 case "darwin":
1106 return goos == "darwin" || goos == "ios"
1107 case goos, goarch:
1108 return true
1109 case "unix":
1110 return unixOS[goos]
1111 default:
1112 return false
1113 }
1114 }
1115
1116
1117
1118
1119
1120
1121
1122 func shouldbuild(file, pkg string) bool {
1123
1124 name := filepath.Base(file)
1125 excluded := func(list []string, ok string) bool {
1126 for _, x := range list {
1127 if x == ok || (ok == "android" && x == "linux") || (ok == "illumos" && x == "solaris") || (ok == "ios" && x == "darwin") {
1128 continue
1129 }
1130 i := strings.Index(name, x)
1131 if i <= 0 || name[i-1] != '_' {
1132 continue
1133 }
1134 i += len(x)
1135 if i == len(name) || name[i] == '.' || name[i] == '_' {
1136 return true
1137 }
1138 }
1139 return false
1140 }
1141 if excluded(okgoos, goos) || excluded(okgoarch, goarch) {
1142 return false
1143 }
1144
1145
1146 if strings.Contains(name, "_test") {
1147 return false
1148 }
1149
1150
1151 for p := range strings.SplitSeq(readfile(file), "\n") {
1152 p = strings.TrimSpace(p)
1153 if p == "" {
1154 continue
1155 }
1156 code := p
1157 i := strings.Index(code, "//")
1158 if i > 0 {
1159 code = strings.TrimSpace(code[:i])
1160 }
1161 if code == "package documentation" {
1162 return false
1163 }
1164 if code == "package main" && pkg != "cmd/go" && pkg != "cmd/cgo" {
1165 return false
1166 }
1167 if !strings.HasPrefix(p, "//") {
1168 break
1169 }
1170 if strings.HasPrefix(p, "//go:build ") {
1171 c, err := constraint.Parse(p)
1172 if err != nil {
1173 errprintf("%s: parsing //go:build line: %v", file, err)
1174 return false
1175 }
1176 return c.Eval(matchtag)
1177 }
1178 }
1179
1180 return true
1181 }
1182
1183
1184 func copyfile(dst, src string, flag int) {
1185 if vflag > 1 {
1186 errprintf("cp %s %s\n", src, dst)
1187 }
1188 writefile(readfile(src), dst, flag)
1189 }
1190
1191
1192
1193
1194 func dopack(dst, src string, extra []string) {
1195 bdst := bytes.NewBufferString(readfile(src))
1196 for _, file := range extra {
1197 b := readfile(file)
1198
1199 i := strings.LastIndex(file, "/") + 1
1200 j := strings.LastIndex(file, `\`) + 1
1201 if i < j {
1202 i = j
1203 }
1204 fmt.Fprintf(bdst, "%-16.16s%-12d%-6d%-6d%-8o%-10d`\n", file[i:], 0, 0, 0, 0644, len(b))
1205 bdst.WriteString(b)
1206 if len(b)&1 != 0 {
1207 bdst.WriteByte(0)
1208 }
1209 }
1210 writefile(bdst.String(), dst, 0)
1211 }
1212
1213 func clean() {
1214 generated := []byte(generatedHeader)
1215
1216
1217 filepath.WalkDir(pathf("%s/src", goroot), func(path string, d fs.DirEntry, err error) error {
1218 switch {
1219 case err != nil:
1220
1221 case d.IsDir() && (d.Name() == "vendor" || d.Name() == "testdata"):
1222 return filepath.SkipDir
1223 case d.IsDir() && d.Name() != "dist":
1224
1225 exe := filepath.Join(path, d.Name())
1226 if info, err := os.Stat(exe); err == nil && !info.IsDir() {
1227 xremove(exe)
1228 }
1229 xremove(exe + ".exe")
1230 case !d.IsDir() && strings.HasPrefix(d.Name(), "z"):
1231
1232 head := make([]byte, 512)
1233 if f, err := os.Open(path); err == nil {
1234 io.ReadFull(f, head)
1235 f.Close()
1236 }
1237 if bytes.HasPrefix(head, generated) {
1238 xremove(path)
1239 }
1240 }
1241 return nil
1242 })
1243
1244 if rebuildall {
1245
1246 xremoveall(pathf("%s/pkg/obj/%s_%s", goroot, gohostos, gohostarch))
1247
1248
1249 xremoveall(pathf("%s/pkg/%s_%s", goroot, gohostos, gohostarch))
1250 xremoveall(pathf("%s/pkg/%s_%s", goroot, goos, goarch))
1251 xremoveall(pathf("%s/pkg/%s_%s_race", goroot, gohostos, gohostarch))
1252 xremoveall(pathf("%s/pkg/%s_%s_race", goroot, goos, goarch))
1253 xremoveall(tooldir)
1254
1255
1256 xremove(pathf("%s/VERSION.cache", goroot))
1257
1258
1259 xremoveall(pathf("%s/pkg/distpack", goroot))
1260 }
1261 }
1262
1263
1266
1267
1268 func cmdenv() {
1269 path := flag.Bool("p", false, "emit updated PATH")
1270 plan9 := flag.Bool("9", gohostos == "plan9", "emit plan 9 syntax")
1271 windows := flag.Bool("w", gohostos == "windows", "emit windows syntax")
1272 xflagparse(0)
1273
1274 format := "%s=\"%s\";\n"
1275 switch {
1276 case *plan9:
1277 format = "%s='%s'\n"
1278 case *windows:
1279 format = "set %s=%s\r\n"
1280 }
1281
1282 xprintf(format, "GO111MODULE", "")
1283 xprintf(format, "GOARCH", goarch)
1284 xprintf(format, "GOBIN", gorootBin)
1285 xprintf(format, "GODEBUG", os.Getenv("GODEBUG"))
1286 xprintf(format, "GOENV", "off")
1287 xprintf(format, "GOFLAGS", "")
1288 xprintf(format, "GOHOSTARCH", gohostarch)
1289 xprintf(format, "GOHOSTOS", gohostos)
1290 xprintf(format, "GOOS", goos)
1291 xprintf(format, "GOPROXY", os.Getenv("GOPROXY"))
1292 xprintf(format, "GOROOT", goroot)
1293 xprintf(format, "GOTMPDIR", os.Getenv("GOTMPDIR"))
1294 xprintf(format, "GOTOOLDIR", tooldir)
1295 if goarch == "arm" {
1296 xprintf(format, "GOARM", goarm)
1297 }
1298 if goarch == "arm64" {
1299 xprintf(format, "GOARM64", goarm64)
1300 }
1301 if goarch == "386" {
1302 xprintf(format, "GO386", go386)
1303 }
1304 if goarch == "amd64" {
1305 xprintf(format, "GOAMD64", goamd64)
1306 }
1307 if goarch == "mips" || goarch == "mipsle" {
1308 xprintf(format, "GOMIPS", gomips)
1309 }
1310 if goarch == "mips64" || goarch == "mips64le" {
1311 xprintf(format, "GOMIPS64", gomips64)
1312 }
1313 if goarch == "ppc64" || goarch == "ppc64le" {
1314 xprintf(format, "GOPPC64", goppc64)
1315 }
1316 if goarch == "riscv64" {
1317 xprintf(format, "GORISCV64", goriscv64)
1318 }
1319 xprintf(format, "GOWORK", "off")
1320
1321 if *path {
1322 sep := ":"
1323 if gohostos == "windows" {
1324 sep = ";"
1325 }
1326 xprintf(format, "PATH", fmt.Sprintf("%s%s%s", gorootBin, sep, os.Getenv("PATH")))
1327
1328
1329
1330
1331 var exportFormat string
1332 if !*windows && !*plan9 {
1333 exportFormat = "export " + format
1334 } else {
1335 exportFormat = format
1336 }
1337 xprintf(exportFormat, "DIST_UNMODIFIED_PATH", os.Getenv("PATH"))
1338 }
1339 }
1340
1341 var (
1342 timeLogEnabled = os.Getenv("GOBUILDTIMELOGFILE") != ""
1343 timeLogMu sync.Mutex
1344 timeLogFile *os.File
1345 timeLogStart time.Time
1346 )
1347
1348 func timelog(op, name string) {
1349 if !timeLogEnabled {
1350 return
1351 }
1352 timeLogMu.Lock()
1353 defer timeLogMu.Unlock()
1354 if timeLogFile == nil {
1355 f, err := os.OpenFile(os.Getenv("GOBUILDTIMELOGFILE"), os.O_RDWR|os.O_APPEND, 0666)
1356 if err != nil {
1357 log.Fatal(err)
1358 }
1359 buf := make([]byte, 100)
1360 n, _ := f.Read(buf)
1361 s := string(buf[:n])
1362 if i := strings.Index(s, "\n"); i >= 0 {
1363 s = s[:i]
1364 }
1365 i := strings.Index(s, " start")
1366 if i < 0 {
1367 log.Fatalf("time log %s does not begin with start line", os.Getenv("GOBUILDTIMELOGFILE"))
1368 }
1369 t, err := time.Parse(time.UnixDate, s[:i])
1370 if err != nil {
1371 log.Fatalf("cannot parse time log line %q: %v", s, err)
1372 }
1373 timeLogStart = t
1374 timeLogFile = f
1375 }
1376 t := time.Now()
1377 fmt.Fprintf(timeLogFile, "%s %+.1fs %s %s\n", t.Format(time.UnixDate), t.Sub(timeLogStart).Seconds(), op, name)
1378 }
1379
1380
1381
1382
1383
1384
1385 func toolenv() []string {
1386 var env []string
1387 if !mustLinkExternal(goos, goarch, false) {
1388
1389
1390
1391
1392 env = append(env, "CGO_ENABLED=0")
1393 }
1394 if isRelease || os.Getenv("GO_BUILDER_NAME") != "" {
1395
1396
1397
1398
1399
1400 env = append(env, "GOFLAGS=-trimpath -ldflags=-w -gcflags=cmd/...=-dwarf=false")
1401 }
1402 return env
1403 }
1404
1405 var (
1406 toolchain = []string{"cmd/asm", "cmd/cgo", "cmd/compile", "cmd/link", "cmd/preprofile"}
1407
1408
1409 binExesIncludedInDistpack = []string{"cmd/go", "cmd/gofmt"}
1410
1411
1412 toolsIncludedInDistpack = []string{"cmd/asm", "cmd/cgo", "cmd/compile", "cmd/cover", "cmd/fix", "cmd/link", "cmd/preprofile", "cmd/vet"}
1413
1414
1415
1416
1417
1418 toolsToInstall = slices.Concat(binExesIncludedInDistpack, toolsIncludedInDistpack)
1419 )
1420
1421
1422
1423
1424
1425
1426
1427
1428 func cmdbootstrap() {
1429 timelog("start", "dist bootstrap")
1430 defer timelog("end", "dist bootstrap")
1431
1432 var debug, distpack, force, noBanner, noClean bool
1433 flag.BoolVar(&rebuildall, "a", rebuildall, "rebuild all")
1434 flag.BoolVar(&debug, "d", debug, "enable debugging of bootstrap process")
1435 flag.BoolVar(&distpack, "distpack", distpack, "write distribution files to pkg/distpack")
1436 flag.BoolVar(&force, "force", force, "build even if the port is marked as broken")
1437 flag.BoolVar(&noBanner, "no-banner", noBanner, "do not print banner")
1438 flag.BoolVar(&noClean, "no-clean", noClean, "print deprecation warning")
1439
1440 xflagparse(0)
1441
1442 if noClean {
1443 xprintf("warning: --no-clean is deprecated and has no effect; use 'go install std cmd' instead\n")
1444 }
1445
1446
1447 if broken[goos+"/"+goarch] && !force {
1448 fatalf("build stopped because the port %s/%s is marked as broken\n\n"+
1449 "Use the -force flag to build anyway.\n", goos, goarch)
1450 }
1451
1452
1453
1454
1455
1456
1457 os.Setenv("GOPATH", pathf("%s/pkg/obj/gopath", goroot))
1458
1459
1460
1461
1462
1463 os.Setenv("GOPROXY", "off")
1464
1465
1466
1467
1468 oldgocache = os.Getenv("GOCACHE")
1469 os.Setenv("GOCACHE", pathf("%s/pkg/obj/go-build", goroot))
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483 os.Setenv("GOEXPERIMENT", "none")
1484
1485 if isdir(pathf("%s/src/pkg", goroot)) {
1486 fatalf("\n\n"+
1487 "The Go package sources have moved to $GOROOT/src.\n"+
1488 "*** %s still exists. ***\n"+
1489 "It probably contains stale files that may confuse the build.\n"+
1490 "Please (check what's there and) remove it and try again.\n"+
1491 "See https://golang.org/s/go14nopkg\n",
1492 pathf("%s/src/pkg", goroot))
1493 }
1494
1495 if rebuildall {
1496 clean()
1497 }
1498
1499 setup()
1500
1501 timelog("build", "toolchain1")
1502 checkCC()
1503 bootstrapBuildTools()
1504
1505
1506 oldBinFiles, err := filepath.Glob(pathf("%s/bin/*", goroot))
1507 if err != nil {
1508 fatalf("glob: %v", err)
1509 }
1510
1511
1512 oldgoos = goos
1513 oldgoarch = goarch
1514 goos = gohostos
1515 goarch = gohostarch
1516 os.Setenv("GOHOSTARCH", gohostarch)
1517 os.Setenv("GOHOSTOS", gohostos)
1518 os.Setenv("GOARCH", goarch)
1519 os.Setenv("GOOS", goos)
1520
1521 timelog("build", "go_bootstrap")
1522 xprintf("Building Go bootstrap cmd/go (go_bootstrap) using Go toolchain1.\n")
1523 install("runtime")
1524 install("time/tzdata")
1525 install("cmd/go")
1526 if vflag > 0 {
1527 xprintf("\n")
1528 }
1529
1530 gogcflags = os.Getenv("GO_GCFLAGS")
1531 setNoOpt()
1532 goldflags = os.Getenv("GO_LDFLAGS")
1533 goBootstrap := pathf("%s/go_bootstrap", tooldir)
1534 if debug {
1535 run("", ShowOutput|CheckExit, pathf("%s/compile", tooldir), "-V=full")
1536 copyfile(pathf("%s/compile1", tooldir), pathf("%s/compile", tooldir), writeExec)
1537 }
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555 timelog("build", "toolchain2")
1556 if vflag > 0 {
1557 xprintf("\n")
1558 }
1559 xprintf("Building Go toolchain2 using go_bootstrap and Go toolchain1.\n")
1560 os.Setenv("CC", compilerEnvLookup("CC", defaultcc, goos, goarch))
1561
1562 os.Setenv("GOEXPERIMENT", goexperiment)
1563
1564 goInstall(toolenv(), goBootstrap, append([]string{"-pgo=off"}, toolchain...)...)
1565 if debug {
1566 run("", ShowOutput|CheckExit, pathf("%s/compile", tooldir), "-V=full")
1567 copyfile(pathf("%s/compile2", tooldir), pathf("%s/compile", tooldir), writeExec)
1568 }
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586 timelog("build", "toolchain3")
1587 if vflag > 0 {
1588 xprintf("\n")
1589 }
1590 xprintf("Building Go toolchain3 using go_bootstrap and Go toolchain2.\n")
1591 goInstall(toolenv(), goBootstrap, append([]string{"-a"}, toolchain...)...)
1592 if debug {
1593 run("", ShowOutput|CheckExit, pathf("%s/compile", tooldir), "-V=full")
1594 copyfile(pathf("%s/compile3", tooldir), pathf("%s/compile", tooldir), writeExec)
1595 }
1596
1597
1598
1599
1600
1601
1602 if _, err := os.Stat(pathf("%s/VERSION", goroot)); err == nil {
1603
1604
1605
1606
1607
1608
1609 } else {
1610 os.Setenv("GOCACHE", oldgocache)
1611 }
1612
1613 if goos == oldgoos && goarch == oldgoarch {
1614
1615 timelog("build", "toolchain")
1616 if vflag > 0 {
1617 xprintf("\n")
1618 }
1619 xprintf("Building packages and commands for %s/%s.\n", goos, goarch)
1620 } else {
1621
1622
1623
1624 timelog("build", "host toolchain")
1625 if vflag > 0 {
1626 xprintf("\n")
1627 }
1628 xprintf("Building commands for host, %s/%s.\n", goos, goarch)
1629 goInstall(toolenv(), goBootstrap, toolsToInstall...)
1630 checkNotStale(toolenv(), goBootstrap, toolsToInstall...)
1631 checkNotStale(toolenv(), gorootBinGo, toolsToInstall...)
1632
1633 timelog("build", "target toolchain")
1634 if vflag > 0 {
1635 xprintf("\n")
1636 }
1637 goos = oldgoos
1638 goarch = oldgoarch
1639 os.Setenv("GOOS", goos)
1640 os.Setenv("GOARCH", goarch)
1641 os.Setenv("CC", compilerEnvLookup("CC", defaultcc, goos, goarch))
1642 xprintf("Building packages and commands for target, %s/%s.\n", goos, goarch)
1643 }
1644 goInstall(nil, goBootstrap, "std")
1645 goInstall(toolenv(), goBootstrap, toolsToInstall...)
1646 checkNotStale(toolenv(), goBootstrap, toolchain...)
1647 checkNotStale(nil, goBootstrap, "std")
1648 checkNotStale(toolenv(), goBootstrap, toolsToInstall...)
1649 checkNotStale(nil, gorootBinGo, "std")
1650 checkNotStale(toolenv(), gorootBinGo, toolsToInstall...)
1651 if debug {
1652 run("", ShowOutput|CheckExit, pathf("%s/compile", tooldir), "-V=full")
1653 checkNotStale(toolenv(), goBootstrap, toolchain...)
1654 copyfile(pathf("%s/compile4", tooldir), pathf("%s/compile", tooldir), writeExec)
1655 }
1656
1657
1658
1659 binFiles, err := filepath.Glob(pathf("%s/bin/*", goroot))
1660 if err != nil {
1661 fatalf("glob: %v", err)
1662 }
1663
1664 ok := map[string]bool{}
1665 for _, f := range oldBinFiles {
1666 ok[f] = true
1667 }
1668 for _, f := range binFiles {
1669 if gohostos == "darwin" && filepath.Base(f) == ".DS_Store" {
1670 continue
1671 }
1672 elem := strings.TrimSuffix(filepath.Base(f), ".exe")
1673 if !ok[f] && elem != "go" && elem != "gofmt" && elem != goos+"_"+goarch {
1674 fatalf("unexpected new file in $GOROOT/bin: %s", elem)
1675 }
1676 }
1677
1678
1679 xremove(pathf("%s/go_bootstrap"+exe, tooldir))
1680
1681 if goos == "android" {
1682
1683 xremove(pathf("%s/go_android_exec-adb-sync-status", os.TempDir()))
1684 }
1685
1686 if wrapperPath := wrapperPathFor(goos, goarch); wrapperPath != "" {
1687 oldcc := os.Getenv("CC")
1688 os.Setenv("GOOS", gohostos)
1689 os.Setenv("GOARCH", gohostarch)
1690 os.Setenv("CC", compilerEnvLookup("CC", defaultcc, gohostos, gohostarch))
1691 goCmd(nil, gorootBinGo, "build", "-o", pathf("%s/go_%s_%s_exec%s", gorootBin, goos, goarch, exe), wrapperPath)
1692
1693
1694 os.Setenv("GOOS", goos)
1695 os.Setenv("GOARCH", goarch)
1696 os.Setenv("CC", oldcc)
1697 }
1698
1699 if distpack {
1700 xprintf("Packaging archives for %s/%s.\n", goos, goarch)
1701 run("", ShowOutput|CheckExit, gorootBinGo, "tool", "distpack")
1702 }
1703
1704
1705 if !noBanner {
1706 banner()
1707 }
1708 }
1709
1710 func wrapperPathFor(goos, goarch string) string {
1711 switch {
1712 case goos == "android":
1713 if gohostos != "android" {
1714 return pathf("%s/misc/go_android_exec/main.go", goroot)
1715 }
1716 case goos == "ios":
1717 if gohostos != "ios" {
1718 return pathf("%s/misc/ios/go_ios_exec.go", goroot)
1719 }
1720 }
1721 return ""
1722 }
1723
1724 func goInstall(env []string, goBinary string, args ...string) {
1725 goCmd(env, goBinary, "install", args...)
1726 }
1727
1728 func appendCompilerFlags(args []string) []string {
1729 if gogcflags != "" {
1730 args = append(args, "-gcflags=all="+gogcflags)
1731 }
1732 if goldflags != "" {
1733 args = append(args, "-ldflags=all="+goldflags)
1734 }
1735 return args
1736 }
1737
1738 func goCmd(env []string, goBinary string, cmd string, args ...string) {
1739 goCmd := []string{goBinary, cmd}
1740 if noOpt {
1741 goCmd = append(goCmd, "-tags=noopt")
1742 }
1743 goCmd = appendCompilerFlags(goCmd)
1744 if vflag > 0 {
1745 goCmd = append(goCmd, "-v")
1746 }
1747
1748
1749 if gohostos == "plan9" && os.Getenv("sysname") == "vx32" {
1750 goCmd = append(goCmd, "-p=1")
1751 }
1752
1753 runEnv(workdir, ShowOutput|CheckExit, env, append(goCmd, args...)...)
1754 }
1755
1756 func checkNotStale(env []string, goBinary string, targets ...string) {
1757 goCmd := []string{goBinary, "list"}
1758 if noOpt {
1759 goCmd = append(goCmd, "-tags=noopt")
1760 }
1761 goCmd = appendCompilerFlags(goCmd)
1762 goCmd = append(goCmd, "-f={{if .Stale}}\tSTALE {{.ImportPath}}: {{.StaleReason}}{{end}}")
1763
1764 out := runEnv(workdir, CheckExit, env, append(goCmd, targets...)...)
1765 if strings.Contains(out, "\tSTALE ") {
1766 os.Setenv("GODEBUG", "gocachehash=1")
1767 for _, target := range []string{"internal/runtime/sys", "cmd/dist", "cmd/link"} {
1768 if strings.Contains(out, "STALE "+target) {
1769 run(workdir, ShowOutput|CheckExit, goBinary, "list", "-f={{.ImportPath}} {{.Stale}}", target)
1770 break
1771 }
1772 }
1773 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)
1774 }
1775 }
1776
1777
1778
1779
1780
1781
1782
1783
1784 var cgoEnabled = map[string]bool{
1785 "aix/ppc64": true,
1786 "darwin/amd64": true,
1787 "darwin/arm64": true,
1788 "dragonfly/amd64": true,
1789 "freebsd/386": true,
1790 "freebsd/amd64": true,
1791 "freebsd/arm": true,
1792 "freebsd/arm64": true,
1793 "freebsd/riscv64": true,
1794 "illumos/amd64": true,
1795 "linux/386": true,
1796 "linux/amd64": true,
1797 "linux/arm": true,
1798 "linux/arm64": true,
1799 "linux/loong64": true,
1800 "linux/ppc64": true,
1801 "linux/ppc64le": true,
1802 "linux/mips": true,
1803 "linux/mipsle": true,
1804 "linux/mips64": true,
1805 "linux/mips64le": true,
1806 "linux/riscv64": true,
1807 "linux/s390x": true,
1808 "linux/sparc64": true,
1809 "android/386": true,
1810 "android/amd64": true,
1811 "android/arm": true,
1812 "android/arm64": true,
1813 "ios/arm64": true,
1814 "ios/amd64": true,
1815 "js/wasm": false,
1816 "wasip1/wasm": false,
1817 "netbsd/386": true,
1818 "netbsd/amd64": true,
1819 "netbsd/arm": true,
1820 "netbsd/arm64": true,
1821 "openbsd/386": true,
1822 "openbsd/amd64": true,
1823 "openbsd/arm": true,
1824 "openbsd/arm64": true,
1825 "openbsd/ppc64": false,
1826 "openbsd/riscv64": true,
1827 "plan9/386": false,
1828 "plan9/amd64": false,
1829 "plan9/arm": false,
1830 "solaris/amd64": true,
1831 "windows/386": true,
1832 "windows/amd64": true,
1833 "windows/arm64": true,
1834 }
1835
1836
1837
1838
1839
1840 var broken = map[string]bool{
1841 "freebsd/riscv64": true,
1842 "linux/sparc64": true,
1843 }
1844
1845
1846 var firstClass = map[string]bool{
1847 "darwin/amd64": true,
1848 "darwin/arm64": true,
1849 "linux/386": true,
1850 "linux/amd64": true,
1851 "linux/arm": true,
1852 "linux/arm64": true,
1853 "windows/386": true,
1854 "windows/amd64": true,
1855 }
1856
1857
1858
1859 func needCC() bool {
1860 return os.Getenv("CGO_ENABLED") == "1" || mustLinkExternal(gohostos, gohostarch, false)
1861 }
1862
1863 func checkCC() {
1864 if !needCC() {
1865 return
1866 }
1867 cc1 := defaultcc[""]
1868 if cc1 == "" {
1869 cc1 = "gcc"
1870 for _, os := range clangos {
1871 if gohostos == os {
1872 cc1 = "clang"
1873 break
1874 }
1875 }
1876 }
1877 cc, err := quotedSplit(cc1)
1878 if err != nil {
1879 fatalf("split CC: %v", err)
1880 }
1881 var ccHelp = append(cc, "--help")
1882
1883 if output, err := exec.Command(ccHelp[0], ccHelp[1:]...).CombinedOutput(); err != nil {
1884 outputHdr := ""
1885 if len(output) > 0 {
1886 outputHdr = "\nCommand output:\n\n"
1887 }
1888 fatalf("cannot invoke C compiler %q: %v\n\n"+
1889 "Go needs a system C compiler for use with cgo.\n"+
1890 "To set a C compiler, set CC=the-compiler.\n"+
1891 "To disable cgo, set CGO_ENABLED=0.\n%s%s", cc, err, outputHdr, output)
1892 }
1893 }
1894
1895 func defaulttarg() string {
1896
1897
1898
1899
1900 pwd := xgetwd()
1901 src := pathf("%s/src/", goroot)
1902 real_src := xrealwd(src)
1903 if !strings.HasPrefix(pwd, real_src) {
1904 fatalf("current directory %s is not under %s", pwd, real_src)
1905 }
1906 pwd = pwd[len(real_src):]
1907
1908 pwd = strings.TrimPrefix(pwd, "/")
1909
1910 return pwd
1911 }
1912
1913
1914 func cmdinstall() {
1915 xflagparse(-1)
1916
1917 if flag.NArg() == 0 {
1918 install(defaulttarg())
1919 }
1920
1921 for _, arg := range flag.Args() {
1922 install(arg)
1923 }
1924 }
1925
1926
1927 func cmdclean() {
1928 xflagparse(0)
1929 clean()
1930 }
1931
1932
1933 func cmdbanner() {
1934 xflagparse(0)
1935 banner()
1936 }
1937
1938 func banner() {
1939 if vflag > 0 {
1940 xprintf("\n")
1941 }
1942 xprintf("---\n")
1943 xprintf("Installed Go for %s/%s in %s\n", goos, goarch, goroot)
1944 xprintf("Installed commands in %s\n", gorootBin)
1945
1946 if gohostos == "plan9" {
1947
1948 pid := strings.ReplaceAll(readfile("#c/pid"), " ", "")
1949 ns := fmt.Sprintf("/proc/%s/ns", pid)
1950 if !strings.Contains(readfile(ns), fmt.Sprintf("bind -b %s /bin", gorootBin)) {
1951 xprintf("*** You need to bind %s before /bin.\n", gorootBin)
1952 }
1953 } else {
1954
1955 pathsep := ":"
1956 if gohostos == "windows" {
1957 pathsep = ";"
1958 }
1959 path := os.Getenv("PATH")
1960 if p, ok := os.LookupEnv("DIST_UNMODIFIED_PATH"); ok {
1961
1962
1963
1964
1965 path = p
1966 }
1967 if !strings.Contains(pathsep+path+pathsep, pathsep+gorootBin+pathsep) {
1968 xprintf("*** You need to add %s to your PATH.\n", gorootBin)
1969 }
1970 }
1971 }
1972
1973
1974 func cmdversion() {
1975 xflagparse(0)
1976 xprintf("%s\n", findgoversion())
1977 }
1978
1979
1980 func cmdlist() {
1981 jsonFlag := flag.Bool("json", false, "produce JSON output")
1982 brokenFlag := flag.Bool("broken", false, "include broken ports")
1983 xflagparse(0)
1984
1985 var plats []string
1986 for p := range cgoEnabled {
1987 if broken[p] && !*brokenFlag {
1988 continue
1989 }
1990 plats = append(plats, p)
1991 }
1992 sort.Strings(plats)
1993
1994 if !*jsonFlag {
1995 for _, p := range plats {
1996 xprintf("%s\n", p)
1997 }
1998 return
1999 }
2000
2001 type jsonResult struct {
2002 GOOS string
2003 GOARCH string
2004 CgoSupported bool
2005 FirstClass bool
2006 Broken bool `json:",omitempty"`
2007 }
2008 var results []jsonResult
2009 for _, p := range plats {
2010 fields := strings.Split(p, "/")
2011 results = append(results, jsonResult{
2012 GOOS: fields[0],
2013 GOARCH: fields[1],
2014 CgoSupported: cgoEnabled[p],
2015 FirstClass: firstClass[p],
2016 Broken: broken[p],
2017 })
2018 }
2019 out, err := json.MarshalIndent(results, "", "\t")
2020 if err != nil {
2021 fatalf("json marshal error: %v", err)
2022 }
2023 if _, err := os.Stdout.Write(out); err != nil {
2024 fatalf("write failed: %v", err)
2025 }
2026 }
2027
2028 func setNoOpt() {
2029 for gcflag := range strings.SplitSeq(gogcflags, " ") {
2030 if gcflag == "-N" || gcflag == "-l" {
2031 noOpt = true
2032 break
2033 }
2034 }
2035 }
2036
View as plain text