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