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