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