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/ioutil"
13 "log"
14 "os"
15 "os/exec"
16 "path/filepath"
17 "sort"
18 "strings"
19 "sync"
20 "time"
21 )
22
23
24
25
26 var (
27 goarch string
28 gobin string
29 gohostarch string
30 gohostos string
31 goos string
32 goarm string
33 go386 string
34 gomips string
35 gomips64 string
36 goppc64 string
37 goroot string
38 goroot_final string
39 goextlinkenabled string
40 gogcflags string
41 goldflags string
42 workdir string
43 tooldir string
44 oldgoos string
45 oldgoarch string
46 exe string
47 defaultcc map[string]string
48 defaultcxx map[string]string
49 defaultcflags string
50 defaultldflags string
51 defaultpkgconfig string
52 defaultldso string
53
54 rebuildall bool
55 defaultclang bool
56
57 vflag int
58 )
59
60
61 var okgoarch = []string{
62 "386",
63 "amd64",
64 "amd64p32",
65 "arm",
66 "arm64",
67 "mips",
68 "mipsle",
69 "mips64",
70 "mips64le",
71 "ppc64",
72 "ppc64le",
73 "riscv64",
74 "s390x",
75 "sparc64",
76 "wasm",
77 }
78
79
80 var okgoos = []string{
81 "darwin",
82 "dragonfly",
83 "illumos",
84 "js",
85 "linux",
86 "android",
87 "solaris",
88 "freebsd",
89 "nacl",
90 "netbsd",
91 "openbsd",
92 "plan9",
93 "windows",
94 "aix",
95 }
96
97
98 func find(p string, l []string) int {
99 for i, s := range l {
100 if p == s {
101 return i
102 }
103 }
104 return -1
105 }
106
107
108 func xinit() {
109 b := os.Getenv("GOROOT")
110 if b == "" {
111 fatalf("$GOROOT must be set")
112 }
113 goroot = filepath.Clean(b)
114
115 b = os.Getenv("GOROOT_FINAL")
116 if b == "" {
117 b = goroot
118 }
119 goroot_final = b
120
121 b = os.Getenv("GOBIN")
122 if b == "" {
123 b = pathf("%s/bin", goroot)
124 }
125 gobin = b
126
127 b = os.Getenv("GOOS")
128 if b == "" {
129 b = gohostos
130 }
131 goos = b
132 if find(goos, okgoos) < 0 {
133 fatalf("unknown $GOOS %s", goos)
134 }
135
136 b = os.Getenv("GOARM")
137 if b == "" {
138 b = xgetgoarm()
139 }
140 goarm = b
141
142 b = os.Getenv("GO386")
143 if b == "" {
144 if cansse2() {
145 b = "sse2"
146 } else {
147 b = "387"
148 }
149 }
150 go386 = b
151
152 b = os.Getenv("GOMIPS")
153 if b == "" {
154 b = "hardfloat"
155 }
156 gomips = b
157
158 b = os.Getenv("GOMIPS64")
159 if b == "" {
160 b = "hardfloat"
161 }
162 gomips64 = b
163
164 b = os.Getenv("GOPPC64")
165 if b == "" {
166 b = "power8"
167 }
168 goppc64 = b
169
170 if p := pathf("%s/src/all.bash", goroot); !isfile(p) {
171 fatalf("$GOROOT is not set correctly or not exported\n"+
172 "\tGOROOT=%s\n"+
173 "\t%s does not exist", goroot, p)
174 }
175
176 b = os.Getenv("GOHOSTARCH")
177 if b != "" {
178 gohostarch = b
179 }
180 if find(gohostarch, okgoarch) < 0 {
181 fatalf("unknown $GOHOSTARCH %s", gohostarch)
182 }
183
184 b = os.Getenv("GOARCH")
185 if b == "" {
186 b = gohostarch
187 }
188 goarch = b
189 if find(goarch, okgoarch) < 0 {
190 fatalf("unknown $GOARCH %s", goarch)
191 }
192
193 b = os.Getenv("GO_EXTLINK_ENABLED")
194 if b != "" {
195 if b != "0" && b != "1" {
196 fatalf("unknown $GO_EXTLINK_ENABLED %s", b)
197 }
198 goextlinkenabled = b
199 }
200
201 gogcflags = os.Getenv("BOOT_GO_GCFLAGS")
202 goldflags = os.Getenv("BOOT_GO_LDFLAGS")
203
204 cc, cxx := "gcc", "g++"
205 if defaultclang {
206 cc, cxx = "clang", "clang++"
207 }
208 defaultcc = compilerEnv("CC", cc)
209 defaultcxx = compilerEnv("CXX", cxx)
210
211 defaultcflags = os.Getenv("CFLAGS")
212 defaultldflags = os.Getenv("LDFLAGS")
213
214 b = os.Getenv("PKG_CONFIG")
215 if b == "" {
216 b = "pkg-config"
217 }
218 defaultpkgconfig = b
219
220 defaultldso = os.Getenv("GO_LDSO")
221
222
223 os.Setenv("GO386", go386)
224 os.Setenv("GOARCH", goarch)
225 os.Setenv("GOARM", goarm)
226 os.Setenv("GOHOSTARCH", gohostarch)
227 os.Setenv("GOHOSTOS", gohostos)
228 os.Setenv("GOOS", goos)
229 os.Setenv("GOMIPS", gomips)
230 os.Setenv("GOMIPS64", gomips64)
231 os.Setenv("GOPPC64", goppc64)
232 os.Setenv("GOROOT", goroot)
233 os.Setenv("GOROOT_FINAL", goroot_final)
234
235
236
237
238 os.Setenv("GOCACHE", pathf("%s/pkg/obj/go-build", goroot))
239
240
241 os.Setenv("LANG", "C")
242 os.Setenv("LANGUAGE", "en_US.UTF8")
243
244 workdir = xworkdir()
245 xatexit(rmworkdir)
246
247 tooldir = pathf("%s/pkg/tool/%s_%s", goroot, gohostos, gohostarch)
248 }
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267 func compilerEnv(envName, def string) map[string]string {
268 m := map[string]string{"": def}
269
270 if env := os.Getenv(envName); env != "" {
271 m[""] = env
272 }
273 if env := os.Getenv(envName + "_FOR_TARGET"); env != "" {
274 if gohostos != goos || gohostarch != goarch {
275 m[gohostos+"/"+gohostarch] = m[""]
276 }
277 m[""] = env
278 }
279
280 for _, goos := range okgoos {
281 for _, goarch := range okgoarch {
282 if env := os.Getenv(envName + "_FOR_" + goos + "_" + goarch); env != "" {
283 m[goos+"/"+goarch] = env
284 }
285 }
286 }
287
288 return m
289 }
290
291
292 func compilerEnvLookup(m map[string]string, goos, goarch string) string {
293 if cc := m[goos+"/"+goarch]; cc != "" {
294 return cc
295 }
296 return m[""]
297 }
298
299
300 func rmworkdir() {
301 if vflag > 1 {
302 errprintf("rm -rf %s\n", workdir)
303 }
304 xremoveall(workdir)
305 }
306
307
308 func chomp(s string) string {
309 return strings.TrimRight(s, " \t\r\n")
310 }
311
312 func branchtag(branch string) (tag string, precise bool) {
313 log := run(goroot, CheckExit, "git", "log", "--decorate=full", "--format=format:%d", "master.."+branch)
314 tag = branch
315 for row, line := range strings.Split(log, "\n") {
316
317
318
319 const s = " refs/tags/"
320 i := strings.Index(line, s)
321 if i < 0 {
322 continue
323 }
324
325 line = line[i+len(s):]
326
327 j := strings.IndexAny(line, ",)")
328 if j < 0 {
329 continue
330 }
331 tag = line[:j]
332 if row == 0 {
333 precise = true
334 }
335 break
336 }
337 return
338 }
339
340
341 func findgoversion() string {
342
343
344 path := pathf("%s/VERSION", goroot)
345 if isfile(path) {
346 b := chomp(readfile(path))
347
348
349
350
351
352 if b != "" {
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367 if strings.HasPrefix(b, "devel") {
368 if hostType := os.Getenv("META_BUILDLET_HOST_TYPE"); strings.Contains(hostType, "-cross") {
369 fmt.Fprintf(os.Stderr, "warning: changing VERSION from %q to %q\n", b, "builder "+hostType)
370 b = "builder " + hostType
371 }
372 }
373 return b
374 }
375 }
376
377
378
379
380 path = pathf("%s/VERSION.cache", goroot)
381 if isfile(path) {
382 return chomp(readfile(path))
383 }
384
385
386 if !isGitRepo() {
387 fatalf("FAILED: not a Git repo; must put a VERSION file in $GOROOT")
388 }
389
390
391
392 branch := chomp(run(goroot, CheckExit, "git", "rev-parse", "--abbrev-ref", "HEAD"))
393
394
395 tag := "devel"
396 precise := false
397
398
399
400 if strings.HasPrefix(branch, "release-branch.") {
401 tag, precise = branchtag(branch)
402 }
403
404 if !precise {
405
406 tag += chomp(run(goroot, CheckExit, "git", "log", "-n", "1", "--format=format: +%h %cd", "HEAD"))
407 }
408
409
410 writefile(tag, path, 0)
411
412 return tag
413 }
414
415
416 func isGitRepo() bool {
417
418
419
420 gitDir := chomp(run(goroot, 0, "git", "rev-parse", "--git-dir"))
421 if !filepath.IsAbs(gitDir) {
422 gitDir = filepath.Join(goroot, gitDir)
423 }
424 return isdir(gitDir)
425 }
426
427
430
431
432 var oldtool = []string{
433 "5a", "5c", "5g", "5l",
434 "6a", "6c", "6g", "6l",
435 "8a", "8c", "8g", "8l",
436 "9a", "9c", "9g", "9l",
437 "6cov",
438 "6nm",
439 "6prof",
440 "cgo",
441 "ebnflint",
442 "goapi",
443 "gofix",
444 "goinstall",
445 "gomake",
446 "gopack",
447 "gopprof",
448 "gotest",
449 "gotype",
450 "govet",
451 "goyacc",
452 "quietgcc",
453 }
454
455
456
457 var unreleased = []string{
458 "src/cmd/newlink",
459 "src/cmd/objwriter",
460 "src/debug/goobj",
461 "src/old",
462 }
463
464
465 func setup() {
466
467 if p := pathf("%s/bin", goroot); !isdir(p) {
468 xmkdir(p)
469 }
470
471
472 if p := pathf("%s/pkg", goroot); !isdir(p) {
473 xmkdir(p)
474 }
475
476 p := pathf("%s/pkg/%s_%s", goroot, gohostos, gohostarch)
477 if rebuildall {
478 xremoveall(p)
479 }
480 xmkdirall(p)
481
482 if goos != gohostos || goarch != gohostarch {
483 p := pathf("%s/pkg/%s_%s", goroot, goos, goarch)
484 if rebuildall {
485 xremoveall(p)
486 }
487 xmkdirall(p)
488 }
489
490
491
492
493
494 p = pathf("%s/pkg/obj/go-build", goroot)
495 if rebuildall {
496 xremoveall(p)
497 }
498 xmkdirall(p)
499 xatexit(func() { xremoveall(p) })
500
501
502
503 if rebuildall {
504 xremoveall(tooldir)
505 }
506 xmkdirall(tooldir)
507
508
509 xremoveall(pathf("%s/bin/tool", goroot))
510
511
512 for _, old := range oldtool {
513 xremove(pathf("%s/bin/%s", goroot, old))
514 }
515
516
517 for _, char := range "56789" {
518 if isfile(pathf("%s/%c%s", gobin, char, "g")) {
519 for _, old := range oldtool {
520 xremove(pathf("%s/%s", gobin, old))
521 }
522 break
523 }
524 }
525
526
527 goversion := findgoversion()
528 if strings.HasPrefix(goversion, "release.") || (strings.HasPrefix(goversion, "go") && !strings.Contains(goversion, "beta")) {
529 for _, dir := range unreleased {
530 if p := pathf("%s/%s", goroot, dir); isdir(p) {
531 fatalf("%s should not exist in release build", p)
532 }
533 }
534 }
535 }
536
537
540
541
542
543
544
545
546 var deptab = []struct {
547 prefix string
548 dep []string
549 }{
550 {"cmd/go/internal/cfg", []string{
551 "zdefaultcc.go",
552 "zosarch.go",
553 }},
554 {"runtime/internal/sys", []string{
555 "zversion.go",
556 }},
557 {"go/build", []string{
558 "zcgo.go",
559 }},
560 }
561
562
563 var depsuffix = []string{
564 ".s",
565 ".go",
566 }
567
568
569 var gentab = []struct {
570 nameprefix string
571 gen func(string, string)
572 }{
573 {"zdefaultcc.go", mkzdefaultcc},
574 {"zosarch.go", mkzosarch},
575 {"zversion.go", mkzversion},
576 {"zcgo.go", mkzcgo},
577
578
579 {"enam.c", nil},
580 {"anames5.c", nil},
581 {"anames6.c", nil},
582 {"anames8.c", nil},
583 {"anames9.c", nil},
584 }
585
586
587
588 var installed = make(map[string]chan struct{})
589 var installedMu sync.Mutex
590
591 func install(dir string) {
592 <-startInstall(dir)
593 }
594
595 func startInstall(dir string) chan struct{} {
596 installedMu.Lock()
597 ch := installed[dir]
598 if ch == nil {
599 ch = make(chan struct{})
600 installed[dir] = ch
601 go runInstall(dir, ch)
602 }
603 installedMu.Unlock()
604 return ch
605 }
606
607
608
609 func runInstall(dir string, ch chan struct{}) {
610 if dir == "net" || dir == "os/user" || dir == "crypto/x509" {
611 fatalf("go_bootstrap cannot depend on cgo package %s", dir)
612 }
613
614 defer close(ch)
615
616 if dir == "unsafe" {
617 return
618 }
619
620 if vflag > 0 {
621 if goos != gohostos || goarch != gohostarch {
622 errprintf("%s (%s/%s)\n", dir, goos, goarch)
623 } else {
624 errprintf("%s\n", dir)
625 }
626 }
627
628 workdir := pathf("%s/%s", workdir, dir)
629 xmkdirall(workdir)
630
631 var clean []string
632 defer func() {
633 for _, name := range clean {
634 xremove(name)
635 }
636 }()
637
638
639 path := pathf("%s/src/%s", goroot, dir)
640 name := filepath.Base(dir)
641
642 ispkg := !strings.HasPrefix(dir, "cmd/") || strings.Contains(dir, "/internal/")
643
644
645
646 var (
647 link []string
648 targ int
649 ispackcmd bool
650 )
651 if ispkg {
652
653 ispackcmd = true
654 link = []string{"pack", pathf("%s/pkg/%s_%s/%s.a", goroot, goos, goarch, dir)}
655 targ = len(link) - 1
656 xmkdirall(filepath.Dir(link[targ]))
657 } else {
658
659 elem := name
660 if elem == "go" {
661 elem = "go_bootstrap"
662 }
663 link = []string{pathf("%s/link", tooldir)}
664 if goos == "android" {
665 link = append(link, "-buildmode=pie")
666 }
667 if goldflags != "" {
668 link = append(link, goldflags)
669 }
670 link = append(link, "-extld="+compilerEnvLookup(defaultcc, goos, goarch))
671 link = append(link, "-o", pathf("%s/%s%s", tooldir, elem, exe))
672 targ = len(link) - 1
673 }
674 ttarg := mtime(link[targ])
675
676
677
678
679 files := xreaddir(path)
680
681
682
683
684
685
686 files = filter(files, func(p string) bool {
687 return !strings.HasPrefix(p, ".") && (!strings.HasPrefix(p, "_") || !strings.HasSuffix(p, ".go"))
688 })
689
690 for _, dt := range deptab {
691 if dir == dt.prefix || strings.HasSuffix(dt.prefix, "/") && strings.HasPrefix(dir, dt.prefix) {
692 for _, p := range dt.dep {
693 p = os.ExpandEnv(p)
694 files = append(files, p)
695 }
696 }
697 }
698 files = uniq(files)
699
700
701 for i, p := range files {
702 if !filepath.IsAbs(p) {
703 files[i] = pathf("%s/%s", path, p)
704 }
705 }
706
707
708 var gofiles, sfiles, missing []string
709 stale := rebuildall
710 files = filter(files, func(p string) bool {
711 for _, suf := range depsuffix {
712 if strings.HasSuffix(p, suf) {
713 goto ok
714 }
715 }
716 return false
717 ok:
718 t := mtime(p)
719 if !t.IsZero() && !strings.HasSuffix(p, ".a") && !shouldbuild(p, dir) {
720 return false
721 }
722 if strings.HasSuffix(p, ".go") {
723 gofiles = append(gofiles, p)
724 } else if strings.HasSuffix(p, ".s") {
725 sfiles = append(sfiles, p)
726 }
727 if t.After(ttarg) {
728 stale = true
729 }
730 if t.IsZero() {
731 missing = append(missing, p)
732 }
733 return true
734 })
735
736
737 if len(files) == 0 {
738 return
739 }
740
741 if !stale {
742 return
743 }
744
745
746 if dir == "runtime" {
747 xmkdirall(pathf("%s/pkg/include", goroot))
748
749 copyfile(pathf("%s/pkg/include/textflag.h", goroot),
750 pathf("%s/src/runtime/textflag.h", goroot), 0)
751 copyfile(pathf("%s/pkg/include/funcdata.h", goroot),
752 pathf("%s/src/runtime/funcdata.h", goroot), 0)
753 copyfile(pathf("%s/pkg/include/asm_ppc64x.h", goroot),
754 pathf("%s/src/runtime/asm_ppc64x.h", goroot), 0)
755 }
756
757
758 for _, p := range files {
759 elem := filepath.Base(p)
760 for _, gt := range gentab {
761 if gt.gen == nil {
762 continue
763 }
764 if strings.HasPrefix(elem, gt.nameprefix) {
765 if vflag > 1 {
766 errprintf("generate %s\n", p)
767 }
768 gt.gen(path, p)
769
770
771
772
773
774
775
776 goto built
777 }
778 }
779
780 if find(p, missing) >= 0 {
781 fatalf("missing file %s", p)
782 }
783 built:
784 }
785
786
787 var deps []string
788 for _, p := range gofiles {
789 deps = append(deps, readimports(p)...)
790 }
791 for _, dir1 := range deps {
792 startInstall(dir1)
793 }
794 for _, dir1 := range deps {
795 install(dir1)
796 }
797
798 if goos != gohostos || goarch != gohostarch {
799
800 if vflag > 1 {
801 errprintf("skip build for cross-compile %s\n", dir)
802 }
803 return
804 }
805
806 asmArgs := []string{
807 pathf("%s/asm", tooldir),
808 "-I", workdir,
809 "-I", pathf("%s/pkg/include", goroot),
810 "-D", "GOOS_" + goos,
811 "-D", "GOARCH_" + goarch,
812 "-D", "GOOS_GOARCH_" + goos + "_" + goarch,
813 }
814 if goarch == "mips" || goarch == "mipsle" {
815
816 asmArgs = append(asmArgs, "-D", "GOMIPS_"+gomips)
817 }
818 if goarch == "mips64" || goarch == "mipsle64" {
819
820 asmArgs = append(asmArgs, "-D", "GOMIPS64_"+gomips64)
821 }
822 goasmh := pathf("%s/go_asm.h", workdir)
823
824
825 var symabis string
826 if len(sfiles) > 0 {
827 symabis = pathf("%s/symabis", workdir)
828 var wg sync.WaitGroup
829 asmabis := append(asmArgs[:len(asmArgs):len(asmArgs)], "-gensymabis", "-o", symabis)
830 asmabis = append(asmabis, sfiles...)
831 if err := ioutil.WriteFile(goasmh, nil, 0666); err != nil {
832 fatalf("cannot write empty go_asm.h: %s", err)
833 }
834 bgrun(&wg, path, asmabis...)
835 bgwait(&wg)
836 }
837
838 var archive string
839
840
841
842
843 pkg := dir
844 if strings.HasPrefix(dir, "cmd/") && strings.Count(dir, "/") == 1 {
845 pkg = "main"
846 }
847 b := pathf("%s/_go_.a", workdir)
848 clean = append(clean, b)
849 if !ispackcmd {
850 link = append(link, b)
851 } else {
852 archive = b
853 }
854
855
856 compile := []string{pathf("%s/compile", tooldir), "-std", "-pack", "-o", b, "-p", pkg}
857 if gogcflags != "" {
858 compile = append(compile, strings.Fields(gogcflags)...)
859 }
860 if dir == "runtime" {
861 compile = append(compile, "-+")
862 }
863 if len(sfiles) > 0 {
864 compile = append(compile, "-asmhdr", goasmh)
865 }
866 if symabis != "" {
867 compile = append(compile, "-symabis", symabis)
868 }
869 if goos == "android" {
870 compile = append(compile, "-shared")
871 }
872
873 compile = append(compile, gofiles...)
874 var wg sync.WaitGroup
875
876
877
878 bgrun(&wg, path, compile...)
879 bgwait(&wg)
880
881
882 for _, p := range sfiles {
883
884 compile := asmArgs[:len(asmArgs):len(asmArgs)]
885
886 doclean := true
887 b := pathf("%s/%s", workdir, filepath.Base(p))
888
889
890 b = b[:len(b)-1] + "o"
891 compile = append(compile, "-o", b, p)
892 bgrun(&wg, path, compile...)
893
894 link = append(link, b)
895 if doclean {
896 clean = append(clean, b)
897 }
898 }
899 bgwait(&wg)
900
901 if ispackcmd {
902 xremove(link[targ])
903 dopack(link[targ], archive, link[targ+1:])
904 return
905 }
906
907
908 xremove(link[targ])
909 bgrun(&wg, "", link...)
910 bgwait(&wg)
911 }
912
913
914
915 func matchfield(f string) bool {
916 for _, tag := range strings.Split(f, ",") {
917 if !matchtag(tag) {
918 return false
919 }
920 }
921 return true
922 }
923
924
925 func matchtag(tag string) bool {
926 if tag == "" {
927 return false
928 }
929 if tag[0] == '!' {
930 if len(tag) == 1 || tag[1] == '!' {
931 return false
932 }
933 return !matchtag(tag[1:])
934 }
935 return tag == "gc" || tag == goos || tag == goarch || tag == "cmd_go_bootstrap" || tag == "go1.1" || (goos == "android" && tag == "linux") || (goos == "illumos" && tag == "solaris")
936 }
937
938
939
940
941
942
943
944 func shouldbuild(file, dir string) bool {
945
946 name := filepath.Base(file)
947 excluded := func(list []string, ok string) bool {
948 for _, x := range list {
949 if x == ok || (ok == "android" && x == "linux") || (ok == "illumos" && x == "solaris") {
950 continue
951 }
952 i := strings.Index(name, x)
953 if i <= 0 || name[i-1] != '_' {
954 continue
955 }
956 i += len(x)
957 if i == len(name) || name[i] == '.' || name[i] == '_' {
958 return true
959 }
960 }
961 return false
962 }
963 if excluded(okgoos, goos) || excluded(okgoarch, goarch) {
964 return false
965 }
966
967
968 if strings.Contains(name, "_test") {
969 return false
970 }
971
972
973 for _, p := range strings.Split(readfile(file), "\n") {
974 p = strings.TrimSpace(p)
975 if p == "" {
976 continue
977 }
978 code := p
979 i := strings.Index(code, "//")
980 if i > 0 {
981 code = strings.TrimSpace(code[:i])
982 }
983 if code == "package documentation" {
984 return false
985 }
986 if code == "package main" && dir != "cmd/go" && dir != "cmd/cgo" {
987 return false
988 }
989 if !strings.HasPrefix(p, "//") {
990 break
991 }
992 if !strings.Contains(p, "+build") {
993 continue
994 }
995 fields := strings.Fields(p[2:])
996 if len(fields) < 1 || fields[0] != "+build" {
997 continue
998 }
999 for _, p := range fields[1:] {
1000 if matchfield(p) {
1001 goto fieldmatch
1002 }
1003 }
1004 return false
1005 fieldmatch:
1006 }
1007
1008 return true
1009 }
1010
1011
1012 func copyfile(dst, src string, flag int) {
1013 if vflag > 1 {
1014 errprintf("cp %s %s\n", src, dst)
1015 }
1016 writefile(readfile(src), dst, flag)
1017 }
1018
1019
1020
1021
1022 func dopack(dst, src string, extra []string) {
1023 bdst := bytes.NewBufferString(readfile(src))
1024 for _, file := range extra {
1025 b := readfile(file)
1026
1027 i := strings.LastIndex(file, "/") + 1
1028 j := strings.LastIndex(file, `\`) + 1
1029 if i < j {
1030 i = j
1031 }
1032 fmt.Fprintf(bdst, "%-16.16s%-12d%-6d%-6d%-8o%-10d`\n", file[i:], 0, 0, 0, 0644, len(b))
1033 bdst.WriteString(b)
1034 if len(b)&1 != 0 {
1035 bdst.WriteByte(0)
1036 }
1037 }
1038 writefile(bdst.String(), dst, 0)
1039 }
1040
1041 var runtimegen = []string{
1042 "zaexperiment.h",
1043 "zversion.go",
1044 }
1045
1046
1047 var cleanlist = []string{
1048 "runtime/internal/sys",
1049 "cmd/cgo",
1050 "cmd/go/internal/cfg",
1051 "go/build",
1052 }
1053
1054 func clean() {
1055 for _, name := range cleanlist {
1056 path := pathf("%s/src/%s", goroot, name)
1057
1058 for _, elem := range xreaddir(path) {
1059 for _, gt := range gentab {
1060 if strings.HasPrefix(elem, gt.nameprefix) {
1061 xremove(pathf("%s/%s", path, elem))
1062 }
1063 }
1064 }
1065
1066 if strings.HasPrefix(name, "cmd/") {
1067 xremove(pathf("%s/%s", path, name[4:]))
1068 }
1069 }
1070
1071
1072 path := pathf("%s/src/runtime", goroot)
1073 for _, elem := range runtimegen {
1074 xremove(pathf("%s/%s", path, elem))
1075 }
1076
1077 if rebuildall {
1078
1079 xremoveall(pathf("%s/pkg/obj/%s_%s", goroot, gohostos, gohostarch))
1080
1081
1082 xremoveall(pathf("%s/pkg/%s_%s", goroot, gohostos, gohostarch))
1083 xremoveall(pathf("%s/pkg/%s_%s", goroot, goos, goarch))
1084 xremoveall(pathf("%s/pkg/%s_%s_race", goroot, gohostos, gohostarch))
1085 xremoveall(pathf("%s/pkg/%s_%s_race", goroot, goos, goarch))
1086 xremoveall(tooldir)
1087
1088
1089 xremove(pathf("%s/VERSION.cache", goroot))
1090 }
1091 }
1092
1093
1096
1097
1098 func cmdenv() {
1099 path := flag.Bool("p", false, "emit updated PATH")
1100 plan9 := flag.Bool("9", false, "emit plan 9 syntax")
1101 windows := flag.Bool("w", false, "emit windows syntax")
1102 xflagparse(0)
1103
1104 format := "%s=\"%s\"\n"
1105 switch {
1106 case *plan9:
1107 format = "%s='%s'\n"
1108 case *windows:
1109 format = "set %s=%s\r\n"
1110 }
1111
1112 xprintf(format, "GOARCH", goarch)
1113 xprintf(format, "GOBIN", gobin)
1114 xprintf(format, "GOCACHE", os.Getenv("GOCACHE"))
1115 xprintf(format, "GODEBUG", os.Getenv("GODEBUG"))
1116 xprintf(format, "GOHOSTARCH", gohostarch)
1117 xprintf(format, "GOHOSTOS", gohostos)
1118 xprintf(format, "GOOS", goos)
1119 xprintf(format, "GOPROXY", os.Getenv("GOPROXY"))
1120 xprintf(format, "GOROOT", goroot)
1121 xprintf(format, "GOTMPDIR", os.Getenv("GOTMPDIR"))
1122 xprintf(format, "GOTOOLDIR", tooldir)
1123 if goarch == "arm" {
1124 xprintf(format, "GOARM", goarm)
1125 }
1126 if goarch == "386" {
1127 xprintf(format, "GO386", go386)
1128 }
1129 if goarch == "mips" || goarch == "mipsle" {
1130 xprintf(format, "GOMIPS", gomips)
1131 }
1132 if goarch == "mips64" || goarch == "mips64le" {
1133 xprintf(format, "GOMIPS64", gomips64)
1134 }
1135 if goarch == "ppc64" || goarch == "ppc64le" {
1136 xprintf(format, "GOPPC64", goppc64)
1137 }
1138
1139 if *path {
1140 sep := ":"
1141 if gohostos == "windows" {
1142 sep = ";"
1143 }
1144 xprintf(format, "PATH", fmt.Sprintf("%s%s%s", gobin, sep, os.Getenv("PATH")))
1145 }
1146 }
1147
1148 var (
1149 timeLogEnabled = os.Getenv("GOBUILDTIMELOGFILE") != ""
1150 timeLogMu sync.Mutex
1151 timeLogFile *os.File
1152 timeLogStart time.Time
1153 )
1154
1155 func timelog(op, name string) {
1156 if !timeLogEnabled {
1157 return
1158 }
1159 timeLogMu.Lock()
1160 defer timeLogMu.Unlock()
1161 if timeLogFile == nil {
1162 f, err := os.OpenFile(os.Getenv("GOBUILDTIMELOGFILE"), os.O_RDWR|os.O_APPEND, 0666)
1163 if err != nil {
1164 log.Fatal(err)
1165 }
1166 buf := make([]byte, 100)
1167 n, _ := f.Read(buf)
1168 s := string(buf[:n])
1169 if i := strings.Index(s, "\n"); i >= 0 {
1170 s = s[:i]
1171 }
1172 i := strings.Index(s, " start")
1173 if i < 0 {
1174 log.Fatalf("time log %s does not begin with start line", os.Getenv("GOBULDTIMELOGFILE"))
1175 }
1176 t, err := time.Parse(time.UnixDate, s[:i])
1177 if err != nil {
1178 log.Fatalf("cannot parse time log line %q: %v", s, err)
1179 }
1180 timeLogStart = t
1181 timeLogFile = f
1182 }
1183 t := time.Now()
1184 fmt.Fprintf(timeLogFile, "%s %+.1fs %s %s\n", t.Format(time.UnixDate), t.Sub(timeLogStart).Seconds(), op, name)
1185 }
1186
1187 var toolchain = []string{"cmd/asm", "cmd/cgo", "cmd/compile", "cmd/link"}
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202 func cmdbootstrap() {
1203 timelog("start", "dist bootstrap")
1204 defer timelog("end", "dist bootstrap")
1205
1206 var noBanner bool
1207 var debug bool
1208 flag.BoolVar(&rebuildall, "a", rebuildall, "rebuild all")
1209 flag.BoolVar(&debug, "d", debug, "enable debugging of bootstrap process")
1210 flag.BoolVar(&noBanner, "no-banner", noBanner, "do not print banner")
1211
1212 xflagparse(0)
1213
1214
1215
1216
1217
1218
1219 os.Setenv("GOPATH", pathf("%s/pkg/obj/gopath", goroot))
1220
1221 if debug {
1222
1223 toolchain = append(toolchain, "cmd/buildid")
1224 }
1225
1226 if isdir(pathf("%s/src/pkg", goroot)) {
1227 fatalf("\n\n"+
1228 "The Go package sources have moved to $GOROOT/src.\n"+
1229 "*** %s still exists. ***\n"+
1230 "It probably contains stale files that may confuse the build.\n"+
1231 "Please (check what's there and) remove it and try again.\n"+
1232 "See https://golang.org/s/go14nopkg\n",
1233 pathf("%s/src/pkg", goroot))
1234 }
1235
1236 if rebuildall {
1237 clean()
1238 }
1239
1240 setup()
1241
1242 timelog("build", "toolchain1")
1243 checkCC()
1244 bootstrapBuildTools()
1245
1246
1247 oldBinFiles, _ := filepath.Glob(pathf("%s/bin/*", goroot))
1248
1249
1250 oldgoos = goos
1251 oldgoarch = goarch
1252 goos = gohostos
1253 goarch = gohostarch
1254 os.Setenv("GOHOSTARCH", gohostarch)
1255 os.Setenv("GOHOSTOS", gohostos)
1256 os.Setenv("GOARCH", goarch)
1257 os.Setenv("GOOS", goos)
1258
1259 timelog("build", "go_bootstrap")
1260 xprintf("Building Go bootstrap cmd/go (go_bootstrap) using Go toolchain1.\n")
1261 install("runtime")
1262 install("cmd/go")
1263 if vflag > 0 {
1264 xprintf("\n")
1265 }
1266
1267 gogcflags = os.Getenv("GO_GCFLAGS")
1268 goldflags = os.Getenv("GO_LDFLAGS")
1269 goBootstrap := pathf("%s/go_bootstrap", tooldir)
1270 cmdGo := pathf("%s/go", gobin)
1271 if debug {
1272 run("", ShowOutput|CheckExit, pathf("%s/compile", tooldir), "-V=full")
1273 copyfile(pathf("%s/compile1", tooldir), pathf("%s/compile", tooldir), writeExec)
1274 }
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292 timelog("build", "toolchain2")
1293 if vflag > 0 {
1294 xprintf("\n")
1295 }
1296 xprintf("Building Go toolchain2 using go_bootstrap and Go toolchain1.\n")
1297 os.Setenv("CC", compilerEnvLookup(defaultcc, goos, goarch))
1298 goInstall(goBootstrap, append([]string{"-i"}, toolchain...)...)
1299 if debug {
1300 run("", ShowOutput|CheckExit, pathf("%s/compile", tooldir), "-V=full")
1301 run("", ShowOutput|CheckExit, pathf("%s/buildid", tooldir), pathf("%s/pkg/%s_%s/runtime/internal/sys.a", goroot, goos, goarch))
1302 copyfile(pathf("%s/compile2", tooldir), pathf("%s/compile", tooldir), writeExec)
1303 }
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321 timelog("build", "toolchain3")
1322 if vflag > 0 {
1323 xprintf("\n")
1324 }
1325 xprintf("Building Go toolchain3 using go_bootstrap and Go toolchain2.\n")
1326 goInstall(goBootstrap, append([]string{"-a", "-i"}, toolchain...)...)
1327 if debug {
1328 run("", ShowOutput|CheckExit, pathf("%s/compile", tooldir), "-V=full")
1329 run("", ShowOutput|CheckExit, pathf("%s/buildid", tooldir), pathf("%s/pkg/%s_%s/runtime/internal/sys.a", goroot, goos, goarch))
1330 copyfile(pathf("%s/compile3", tooldir), pathf("%s/compile", tooldir), writeExec)
1331 }
1332 checkNotStale(goBootstrap, append(toolchain, "runtime/internal/sys")...)
1333
1334 if goos == oldgoos && goarch == oldgoarch {
1335
1336 timelog("build", "toolchain")
1337 if vflag > 0 {
1338 xprintf("\n")
1339 }
1340 xprintf("Building packages and commands for %s/%s.\n", goos, goarch)
1341 } else {
1342
1343
1344
1345 timelog("build", "host toolchain")
1346 if vflag > 0 {
1347 xprintf("\n")
1348 }
1349 xprintf("Building packages and commands for host, %s/%s.\n", goos, goarch)
1350 goInstall(goBootstrap, "std", "cmd")
1351 checkNotStale(goBootstrap, "std", "cmd")
1352 checkNotStale(cmdGo, "std", "cmd")
1353
1354 timelog("build", "target toolchain")
1355 if vflag > 0 {
1356 xprintf("\n")
1357 }
1358 goos = oldgoos
1359 goarch = oldgoarch
1360 os.Setenv("GOOS", goos)
1361 os.Setenv("GOARCH", goarch)
1362 os.Setenv("CC", compilerEnvLookup(defaultcc, goos, goarch))
1363 xprintf("Building packages and commands for target, %s/%s.\n", goos, goarch)
1364 }
1365 targets := []string{"std", "cmd"}
1366 if goos == "js" && goarch == "wasm" {
1367
1368 targets = targets[:1]
1369 }
1370 goInstall(goBootstrap, targets...)
1371 checkNotStale(goBootstrap, targets...)
1372 checkNotStale(cmdGo, targets...)
1373 if debug {
1374 run("", ShowOutput|CheckExit, pathf("%s/compile", tooldir), "-V=full")
1375 run("", ShowOutput|CheckExit, pathf("%s/buildid", tooldir), pathf("%s/pkg/%s_%s/runtime/internal/sys.a", goroot, goos, goarch))
1376 checkNotStale(goBootstrap, append(toolchain, "runtime/internal/sys")...)
1377 copyfile(pathf("%s/compile4", tooldir), pathf("%s/compile", tooldir), writeExec)
1378 }
1379
1380
1381
1382 binFiles, _ := filepath.Glob(pathf("%s/bin/*", goroot))
1383 ok := map[string]bool{}
1384 for _, f := range oldBinFiles {
1385 ok[f] = true
1386 }
1387 for _, f := range binFiles {
1388 elem := strings.TrimSuffix(filepath.Base(f), ".exe")
1389 if !ok[f] && elem != "go" && elem != "gofmt" && elem != goos+"_"+goarch {
1390 fatalf("unexpected new file in $GOROOT/bin: %s", elem)
1391 }
1392 }
1393
1394
1395 xremove(pathf("%s/go_bootstrap", tooldir))
1396
1397 if goos == "android" {
1398
1399 xremove(pathf("%s/go_android_exec-adb-sync-status", os.TempDir()))
1400 }
1401
1402 if wrapperPath := wrapperPathFor(goos, goarch); wrapperPath != "" {
1403 oldcc := os.Getenv("CC")
1404 os.Setenv("GOOS", gohostos)
1405 os.Setenv("GOARCH", gohostarch)
1406 os.Setenv("CC", compilerEnvLookup(defaultcc, gohostos, gohostarch))
1407 goCmd(cmdGo, "build", "-o", pathf("%s/go_%s_%s_exec%s", gobin, goos, goarch, exe), wrapperPath)
1408
1409
1410 os.Setenv("GOOS", goos)
1411 os.Setenv("GOARCH", goarch)
1412 os.Setenv("CC", oldcc)
1413 }
1414
1415
1416 if !noBanner {
1417 banner()
1418 }
1419 }
1420
1421 func wrapperPathFor(goos, goarch string) string {
1422 switch {
1423 case goos == "android":
1424 if gohostos != "android" {
1425 return pathf("%s/misc/android/go_android_exec.go", goroot)
1426 }
1427 case goos == "darwin" && (goarch == "arm" || goarch == "arm64"):
1428 if gohostos != "darwin" || (gohostarch != "arm" && gohostarch != "arm64") {
1429 return pathf("%s/misc/ios/go_darwin_arm_exec.go", goroot)
1430 }
1431 }
1432 return ""
1433 }
1434
1435 func goInstall(goBinary string, args ...string) {
1436 goCmd(goBinary, "install", args...)
1437 }
1438
1439 func goCmd(goBinary string, cmd string, args ...string) {
1440 goCmd := []string{goBinary, cmd, "-gcflags=all=" + gogcflags, "-ldflags=all=" + goldflags}
1441 if vflag > 0 {
1442 goCmd = append(goCmd, "-v")
1443 }
1444
1445
1446 if gohostos == "plan9" && os.Getenv("sysname") == "vx32" {
1447 goCmd = append(goCmd, "-p=1")
1448 }
1449
1450 run(goroot, ShowOutput|CheckExit, append(goCmd, args...)...)
1451 }
1452
1453 func checkNotStale(goBinary string, targets ...string) {
1454 out := run(goroot, CheckExit,
1455 append([]string{
1456 goBinary,
1457 "list", "-gcflags=all=" + gogcflags, "-ldflags=all=" + goldflags,
1458 "-f={{if .Stale}}\tSTALE {{.ImportPath}}: {{.StaleReason}}{{end}}",
1459 }, targets...)...)
1460 if strings.Contains(out, "\tSTALE ") {
1461 os.Setenv("GODEBUG", "gocachehash=1")
1462 for _, target := range []string{"runtime/internal/sys", "cmd/dist", "cmd/link"} {
1463 if strings.Contains(out, "STALE "+target) {
1464 run(goroot, ShowOutput|CheckExit, goBinary, "list", "-f={{.ImportPath}} {{.Stale}}", target)
1465 break
1466 }
1467 }
1468 fatalf("unexpected stale targets reported by %s list -gcflags=\"%s\" -ldflags=\"%s\" for %v:\n%s", goBinary, gogcflags, goldflags, targets, out)
1469 }
1470 }
1471
1472
1473
1474
1475
1476
1477
1478
1479 var cgoEnabled = map[string]bool{
1480 "aix/ppc64": true,
1481 "darwin/386": false,
1482 "darwin/amd64": true,
1483 "darwin/arm": true,
1484 "darwin/arm64": true,
1485 "dragonfly/amd64": true,
1486 "freebsd/386": true,
1487 "freebsd/amd64": true,
1488 "freebsd/arm": true,
1489 "illumos/amd64": true,
1490 "linux/386": true,
1491 "linux/amd64": true,
1492 "linux/arm": true,
1493 "linux/arm64": true,
1494 "linux/ppc64": false,
1495 "linux/ppc64le": true,
1496 "linux/mips": true,
1497 "linux/mipsle": true,
1498 "linux/mips64": true,
1499 "linux/mips64le": true,
1500 "linux/riscv64": true,
1501 "linux/s390x": true,
1502 "linux/sparc64": true,
1503 "android/386": true,
1504 "android/amd64": true,
1505 "android/arm": true,
1506 "android/arm64": true,
1507 "js/wasm": false,
1508 "nacl/386": false,
1509 "nacl/amd64p32": false,
1510 "nacl/arm": false,
1511 "netbsd/386": true,
1512 "netbsd/amd64": true,
1513 "netbsd/arm": true,
1514 "netbsd/arm64": true,
1515 "openbsd/386": true,
1516 "openbsd/amd64": true,
1517 "openbsd/arm": true,
1518 "openbsd/arm64": true,
1519 "plan9/386": false,
1520 "plan9/amd64": false,
1521 "plan9/arm": false,
1522 "solaris/amd64": true,
1523 "windows/386": true,
1524 "windows/amd64": true,
1525 "windows/arm": false,
1526 }
1527
1528
1529
1530 var incomplete = map[string]bool{
1531 "linux/riscv64": true,
1532 "linux/sparc64": true,
1533 }
1534
1535 func needCC() bool {
1536 switch os.Getenv("CGO_ENABLED") {
1537 case "1":
1538 return true
1539 case "0":
1540 return false
1541 }
1542 return cgoEnabled[gohostos+"/"+gohostarch]
1543 }
1544
1545 func checkCC() {
1546 if !needCC() {
1547 return
1548 }
1549 if output, err := exec.Command(defaultcc[""], "--help").CombinedOutput(); err != nil {
1550 outputHdr := ""
1551 if len(output) > 0 {
1552 outputHdr = "\nCommand output:\n\n"
1553 }
1554 fatalf("cannot invoke C compiler %q: %v\n\n"+
1555 "Go needs a system C compiler for use with cgo.\n"+
1556 "To set a C compiler, set CC=the-compiler.\n"+
1557 "To disable cgo, set CGO_ENABLED=0.\n%s%s", defaultcc[""], err, outputHdr, output)
1558 }
1559 }
1560
1561 func defaulttarg() string {
1562
1563
1564
1565
1566 pwd := xgetwd()
1567 src := pathf("%s/src/", goroot)
1568 real_src := xrealwd(src)
1569 if !strings.HasPrefix(pwd, real_src) {
1570 fatalf("current directory %s is not under %s", pwd, real_src)
1571 }
1572 pwd = pwd[len(real_src):]
1573
1574 pwd = strings.TrimPrefix(pwd, "/")
1575
1576 return pwd
1577 }
1578
1579
1580 func cmdinstall() {
1581 xflagparse(-1)
1582
1583 if flag.NArg() == 0 {
1584 install(defaulttarg())
1585 }
1586
1587 for _, arg := range flag.Args() {
1588 install(arg)
1589 }
1590 }
1591
1592
1593 func cmdclean() {
1594 xflagparse(0)
1595 clean()
1596 }
1597
1598
1599 func cmdbanner() {
1600 xflagparse(0)
1601 banner()
1602 }
1603
1604 func banner() {
1605 if vflag > 0 {
1606 xprintf("\n")
1607 }
1608 xprintf("---\n")
1609 xprintf("Installed Go for %s/%s in %s\n", goos, goarch, goroot)
1610 xprintf("Installed commands in %s\n", gobin)
1611
1612 if !xsamefile(goroot_final, goroot) {
1613
1614
1615 } else if gohostos == "plan9" {
1616
1617 pid := strings.Replace(readfile("#c/pid"), " ", "", -1)
1618 ns := fmt.Sprintf("/proc/%s/ns", pid)
1619 if !strings.Contains(readfile(ns), fmt.Sprintf("bind -b %s /bin", gobin)) {
1620 xprintf("*** You need to bind %s before /bin.\n", gobin)
1621 }
1622 } else {
1623
1624 pathsep := ":"
1625 if gohostos == "windows" {
1626 pathsep = ";"
1627 }
1628 if !strings.Contains(pathsep+os.Getenv("PATH")+pathsep, pathsep+gobin+pathsep) {
1629 xprintf("*** You need to add %s to your PATH.\n", gobin)
1630 }
1631 }
1632
1633 if !xsamefile(goroot_final, goroot) {
1634 xprintf("\n"+
1635 "The binaries expect %s to be copied or moved to %s\n",
1636 goroot, goroot_final)
1637 }
1638 }
1639
1640
1641 func cmdversion() {
1642 xflagparse(0)
1643 xprintf("%s\n", findgoversion())
1644 }
1645
1646
1647 func cmdlist() {
1648 jsonFlag := flag.Bool("json", false, "produce JSON output")
1649 xflagparse(0)
1650
1651 var plats []string
1652 for p := range cgoEnabled {
1653 if incomplete[p] {
1654 continue
1655 }
1656 plats = append(plats, p)
1657 }
1658 sort.Strings(plats)
1659
1660 if !*jsonFlag {
1661 for _, p := range plats {
1662 xprintf("%s\n", p)
1663 }
1664 return
1665 }
1666
1667 type jsonResult struct {
1668 GOOS string
1669 GOARCH string
1670 CgoSupported bool
1671 }
1672 var results []jsonResult
1673 for _, p := range plats {
1674 fields := strings.Split(p, "/")
1675 results = append(results, jsonResult{
1676 GOOS: fields[0],
1677 GOARCH: fields[1],
1678 CgoSupported: cgoEnabled[p]})
1679 }
1680 out, err := json.MarshalIndent(results, "", "\t")
1681 if err != nil {
1682 fatalf("json marshal error: %v", err)
1683 }
1684 if _, err := os.Stdout.Write(out); err != nil {
1685 fatalf("write failed: %v", err)
1686 }
1687 }
1688
View as plain text