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