]> Cypherpunks.ru repositories - gostls13.git/blob - src/cmd/dist/build.go
cmd/go: fail with nice error message on bad GOOS/GOARCH pair
[gostls13.git] / src / cmd / dist / build.go
1 // Copyright 2012 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
4
5 package main
6
7 import (
8         "bytes"
9         "encoding/json"
10         "flag"
11         "fmt"
12         "os"
13         "os/exec"
14         "path/filepath"
15         "sort"
16         "strings"
17         "sync"
18 )
19
20 // Initialization for any invocation.
21
22 // The usual variables.
23 var (
24         goarch           string
25         gobin            string
26         gohostarch       string
27         gohostos         string
28         goos             string
29         goarm            string
30         go386            string
31         goroot           string
32         goroot_final     string
33         goextlinkenabled string
34         gogcflags        string // For running built compiler
35         workdir          string
36         tooldir          string
37         oldgoos          string
38         oldgoarch        string
39         slash            string
40         exe              string
41         defaultcc        string
42         defaultcflags    string
43         defaultldflags   string
44         defaultcxxtarget string
45         defaultcctarget  string
46         rebuildall       bool
47         defaultclang     bool
48
49         vflag int // verbosity
50 )
51
52 // The known architectures.
53 var okgoarch = []string{
54         "386",
55         "amd64",
56         "amd64p32",
57         "arm",
58         "arm64",
59         "mips64",
60         "mips64le",
61         "ppc64",
62         "ppc64le",
63         "s390x",
64 }
65
66 // The known operating systems.
67 var okgoos = []string{
68         "darwin",
69         "dragonfly",
70         "linux",
71         "android",
72         "solaris",
73         "freebsd",
74         "nacl",
75         "netbsd",
76         "openbsd",
77         "plan9",
78         "windows",
79 }
80
81 // find reports the first index of p in l[0:n], or else -1.
82 func find(p string, l []string) int {
83         for i, s := range l {
84                 if p == s {
85                         return i
86                 }
87         }
88         return -1
89 }
90
91 // xinit handles initialization of the various global state, like goroot and goarch.
92 func xinit() {
93         goroot = os.Getenv("GOROOT")
94         if slash == "/" && len(goroot) > 1 || slash == `\` && len(goroot) > 3 {
95                 // if not "/" or "c:\", then strip trailing path separator
96                 goroot = strings.TrimSuffix(goroot, slash)
97         }
98         if goroot == "" {
99                 fatal("$GOROOT must be set")
100         }
101
102         goroot_final = os.Getenv("GOROOT_FINAL")
103         if goroot_final == "" {
104                 goroot_final = goroot
105         }
106
107         b := os.Getenv("GOBIN")
108         if b == "" {
109                 b = goroot + slash + "bin"
110         }
111         gobin = b
112
113         b = os.Getenv("GOOS")
114         if b == "" {
115                 b = gohostos
116         }
117         goos = b
118         if find(goos, okgoos) < 0 {
119                 fatal("unknown $GOOS %s", goos)
120         }
121
122         b = os.Getenv("GOARM")
123         if b == "" {
124                 b = xgetgoarm()
125         }
126         goarm = b
127
128         b = os.Getenv("GO386")
129         if b == "" {
130                 if cansse2() {
131                         b = "sse2"
132                 } else {
133                         b = "387"
134                 }
135         }
136         go386 = b
137
138         p := pathf("%s/src/all.bash", goroot)
139         if !isfile(p) {
140                 fatal("$GOROOT is not set correctly or not exported\n"+
141                         "\tGOROOT=%s\n"+
142                         "\t%s does not exist", goroot, p)
143         }
144
145         b = os.Getenv("GOHOSTARCH")
146         if b != "" {
147                 gohostarch = b
148         }
149
150         if find(gohostarch, okgoarch) < 0 {
151                 fatal("unknown $GOHOSTARCH %s", gohostarch)
152         }
153
154         b = os.Getenv("GOARCH")
155         if b == "" {
156                 b = gohostarch
157         }
158         goarch = b
159         if find(goarch, okgoarch) < 0 {
160                 fatal("unknown $GOARCH %s", goarch)
161         }
162
163         b = os.Getenv("GO_EXTLINK_ENABLED")
164         if b != "" {
165                 if b != "0" && b != "1" {
166                         fatal("unknown $GO_EXTLINK_ENABLED %s", b)
167                 }
168                 goextlinkenabled = b
169         }
170
171         gogcflags = os.Getenv("BOOT_GO_GCFLAGS")
172
173         b = os.Getenv("CC")
174         if b == "" {
175                 // Use clang on OS X, because gcc is deprecated there.
176                 // Xcode for OS X 10.9 Mavericks will ship a fake "gcc" binary that
177                 // actually runs clang. We prepare different command
178                 // lines for the two binaries, so it matters what we call it.
179                 // See golang.org/issue/5822.
180                 if defaultclang {
181                         b = "clang"
182                 } else {
183                         b = "gcc"
184                 }
185         }
186         defaultcc = b
187
188         defaultcflags = os.Getenv("CFLAGS")
189
190         defaultldflags = os.Getenv("LDFLAGS")
191
192         b = os.Getenv("CC_FOR_TARGET")
193         if b == "" {
194                 b = defaultcc
195         }
196         defaultcctarget = b
197
198         b = os.Getenv("CXX_FOR_TARGET")
199         if b == "" {
200                 b = os.Getenv("CXX")
201                 if b == "" {
202                         if defaultclang {
203                                 b = "clang++"
204                         } else {
205                                 b = "g++"
206                         }
207                 }
208         }
209         defaultcxxtarget = b
210
211         // For tools being invoked but also for os.ExpandEnv.
212         os.Setenv("GO386", go386)
213         os.Setenv("GOARCH", goarch)
214         os.Setenv("GOARM", goarm)
215         os.Setenv("GOHOSTARCH", gohostarch)
216         os.Setenv("GOHOSTOS", gohostos)
217         os.Setenv("GOOS", goos)
218         os.Setenv("GOROOT", goroot)
219         os.Setenv("GOROOT_FINAL", goroot_final)
220
221         // Make the environment more predictable.
222         os.Setenv("LANG", "C")
223         os.Setenv("LANGUAGE", "en_US.UTF8")
224
225         workdir = xworkdir()
226         xatexit(rmworkdir)
227
228         tooldir = pathf("%s/pkg/tool/%s_%s", goroot, gohostos, gohostarch)
229 }
230
231 // rmworkdir deletes the work directory.
232 func rmworkdir() {
233         if vflag > 1 {
234                 errprintf("rm -rf %s\n", workdir)
235         }
236         xremoveall(workdir)
237 }
238
239 // Remove trailing spaces.
240 func chomp(s string) string {
241         return strings.TrimRight(s, " \t\r\n")
242 }
243
244 func branchtag(branch string) (tag string, precise bool) {
245         b := run(goroot, CheckExit, "git", "log", "--decorate=full", "--format=format:%d", "master.."+branch)
246         tag = branch
247         for _, line := range splitlines(b) {
248                 // Each line is either blank, or looks like
249                 //        (tag: refs/tags/go1.4rc2, refs/remotes/origin/release-branch.go1.4, refs/heads/release-branch.go1.4)
250                 // We need to find an element starting with refs/tags/.
251                 i := strings.Index(line, " refs/tags/")
252                 if i < 0 {
253                         continue
254                 }
255                 i += len(" refs/tags/")
256                 // The tag name ends at a comma or paren (prefer the first).
257                 j := strings.Index(line[i:], ",")
258                 if j < 0 {
259                         j = strings.Index(line[i:], ")")
260                 }
261                 if j < 0 {
262                         continue // malformed line; ignore it
263                 }
264                 tag = line[i : i+j]
265                 if i == 0 {
266                         precise = true // tag denotes HEAD
267                 }
268                 break
269         }
270         return
271 }
272
273 // findgoversion determines the Go version to use in the version string.
274 func findgoversion() string {
275         // The $GOROOT/VERSION file takes priority, for distributions
276         // without the source repo.
277         path := pathf("%s/VERSION", goroot)
278         if isfile(path) {
279                 b := chomp(readfile(path))
280                 // Commands such as "dist version > VERSION" will cause
281                 // the shell to create an empty VERSION file and set dist's
282                 // stdout to its fd. dist in turn looks at VERSION and uses
283                 // its content if available, which is empty at this point.
284                 // Only use the VERSION file if it is non-empty.
285                 if b != "" {
286                         return b
287                 }
288         }
289
290         // The $GOROOT/VERSION.cache file is a cache to avoid invoking
291         // git every time we run this command. Unlike VERSION, it gets
292         // deleted by the clean command.
293         path = pathf("%s/VERSION.cache", goroot)
294         if isfile(path) {
295                 return chomp(readfile(path))
296         }
297
298         // Show a nicer error message if this isn't a Git repo.
299         if !isGitRepo() {
300                 fatal("FAILED: not a Git repo; must put a VERSION file in $GOROOT")
301         }
302
303         // Otherwise, use Git.
304         // What is the current branch?
305         branch := chomp(run(goroot, CheckExit, "git", "rev-parse", "--abbrev-ref", "HEAD"))
306
307         // What are the tags along the current branch?
308         tag := "devel"
309         precise := false
310
311         // If we're on a release branch, use the closest matching tag
312         // that is on the release branch (and not on the master branch).
313         if strings.HasPrefix(branch, "release-branch.") {
314                 tag, precise = branchtag(branch)
315         }
316
317         if !precise {
318                 // Tag does not point at HEAD; add hash and date to version.
319                 tag += chomp(run(goroot, CheckExit, "git", "log", "-n", "1", "--format=format: +%h %cd", "HEAD"))
320         }
321
322         // Cache version.
323         writefile(tag, path, 0)
324
325         return tag
326 }
327
328 // isGitRepo reports whether the working directory is inside a Git repository.
329 func isGitRepo() bool {
330         // NB: simply checking the exit code of `git rev-parse --git-dir` would
331         // suffice here, but that requires deviating from the infrastructure
332         // provided by `run`.
333         gitDir := chomp(run(goroot, 0, "git", "rev-parse", "--git-dir"))
334         if !filepath.IsAbs(gitDir) {
335                 gitDir = filepath.Join(goroot, gitDir)
336         }
337         fi, err := os.Stat(gitDir)
338         return err == nil && fi.IsDir()
339 }
340
341 /*
342  * Initial tree setup.
343  */
344
345 // The old tools that no longer live in $GOBIN or $GOROOT/bin.
346 var oldtool = []string{
347         "5a", "5c", "5g", "5l",
348         "6a", "6c", "6g", "6l",
349         "8a", "8c", "8g", "8l",
350         "9a", "9c", "9g", "9l",
351         "6cov",
352         "6nm",
353         "6prof",
354         "cgo",
355         "ebnflint",
356         "goapi",
357         "gofix",
358         "goinstall",
359         "gomake",
360         "gopack",
361         "gopprof",
362         "gotest",
363         "gotype",
364         "govet",
365         "goyacc",
366         "quietgcc",
367 }
368
369 // Unreleased directories (relative to $GOROOT) that should
370 // not be in release branches.
371 var unreleased = []string{
372         "src/cmd/newlink",
373         "src/cmd/objwriter",
374         "src/debug/goobj",
375         "src/old",
376 }
377
378 // setup sets up the tree for the initial build.
379 func setup() {
380         // Create bin directory.
381         if p := pathf("%s/bin", goroot); !isdir(p) {
382                 xmkdir(p)
383         }
384
385         // Create package directory.
386         if p := pathf("%s/pkg", goroot); !isdir(p) {
387                 xmkdir(p)
388         }
389
390         p := pathf("%s/pkg/%s_%s", goroot, gohostos, gohostarch)
391         if rebuildall {
392                 xremoveall(p)
393         }
394         xmkdirall(p)
395
396         if goos != gohostos || goarch != gohostarch {
397                 p := pathf("%s/pkg/%s_%s", goroot, goos, goarch)
398                 if rebuildall {
399                         xremoveall(p)
400                 }
401                 xmkdirall(p)
402         }
403
404         // Create object directory.
405         // We keep it in pkg/ so that all the generated binaries
406         // are in one tree. If pkg/obj/libgc.a exists, it is a dreg from
407         // before we used subdirectories of obj. Delete all of obj
408         // to clean up.
409         if p := pathf("%s/pkg/obj/libgc.a", goroot); isfile(p) {
410                 xremoveall(pathf("%s/pkg/obj", goroot))
411         }
412         p = pathf("%s/pkg/obj/%s_%s", goroot, gohostos, gohostarch)
413         if rebuildall {
414                 xremoveall(p)
415         }
416         xmkdirall(p)
417
418         // Create tool directory.
419         // We keep it in pkg/, just like the object directory above.
420         if rebuildall {
421                 xremoveall(tooldir)
422         }
423         xmkdirall(tooldir)
424
425         // Remove tool binaries from before the tool/gohostos_gohostarch
426         xremoveall(pathf("%s/bin/tool", goroot))
427
428         // Remove old pre-tool binaries.
429         for _, old := range oldtool {
430                 xremove(pathf("%s/bin/%s", goroot, old))
431         }
432
433         // If $GOBIN is set and has a Go compiler, it must be cleaned.
434         for _, char := range "56789" {
435                 if isfile(pathf("%s%s%c%s", gobin, slash, char, "g")) {
436                         for _, old := range oldtool {
437                                 xremove(pathf("%s/%s", gobin, old))
438                         }
439                         break
440                 }
441         }
442
443         // For release, make sure excluded things are excluded.
444         goversion := findgoversion()
445         if strings.HasPrefix(goversion, "release.") || (strings.HasPrefix(goversion, "go") && !strings.Contains(goversion, "beta")) {
446                 for _, dir := range unreleased {
447                         if p := pathf("%s/%s", goroot, dir); isdir(p) {
448                                 fatal("%s should not exist in release build", p)
449                         }
450                 }
451         }
452 }
453
454 /*
455  * Tool building
456  */
457
458 // deptab lists changes to the default dependencies for a given prefix.
459 // deps ending in /* read the whole directory; deps beginning with -
460 // exclude files with that prefix.
461 var deptab = []struct {
462         prefix string   // prefix of target
463         dep    []string // dependency tweaks for targets with that prefix
464 }{
465         {"cmd/go", []string{
466                 "zdefaultcc.go",
467                 "zosarch.go",
468         }},
469         {"runtime/internal/sys", []string{
470                 "zversion.go",
471         }},
472         {"go/build", []string{
473                 "zcgo.go",
474         }},
475 }
476
477 // depsuffix records the allowed suffixes for source files.
478 var depsuffix = []string{
479         ".s",
480         ".go",
481 }
482
483 // gentab records how to generate some trivial files.
484 var gentab = []struct {
485         nameprefix string
486         gen        func(string, string)
487 }{
488         {"zdefaultcc.go", mkzdefaultcc},
489         {"zosarch.go", mkzosarch},
490         {"zversion.go", mkzversion},
491         {"zcgo.go", mkzcgo},
492
493         // not generated anymore, but delete the file if we see it
494         {"enam.c", nil},
495         {"anames5.c", nil},
496         {"anames6.c", nil},
497         {"anames8.c", nil},
498         {"anames9.c", nil},
499 }
500
501 // installed maps from a dir name (as given to install) to a chan
502 // closed when the dir's package is installed.
503 var installed = make(map[string]chan struct{})
504
505 // install installs the library, package, or binary associated with dir,
506 // which is relative to $GOROOT/src.
507 func install(dir string) {
508         if ch, ok := installed[dir]; ok {
509                 defer close(ch)
510         }
511         for _, dep := range builddeps[dir] {
512                 <-installed[dep]
513         }
514
515         if vflag > 0 {
516                 if goos != gohostos || goarch != gohostarch {
517                         errprintf("%s (%s/%s)\n", dir, goos, goarch)
518                 } else {
519                         errprintf("%s\n", dir)
520                 }
521         }
522
523         workdir := pathf("%s/%s", workdir, dir)
524         xmkdirall(workdir)
525
526         var clean []string
527         defer func() {
528                 for _, name := range clean {
529                         xremove(name)
530                 }
531         }()
532
533         // path = full path to dir.
534         path := pathf("%s/src/%s", goroot, dir)
535         name := filepath.Base(dir)
536
537         ispkg := !strings.HasPrefix(dir, "cmd/") || strings.HasPrefix(dir, "cmd/internal/") || strings.HasPrefix(dir, "cmd/asm/internal/")
538
539         // Start final link command line.
540         // Note: code below knows that link.p[targ] is the target.
541         var (
542                 link      []string
543                 targ      int
544                 ispackcmd bool
545         )
546         if ispkg {
547                 // Go library (package).
548                 ispackcmd = true
549                 link = []string{"pack", pathf("%s/pkg/%s_%s/%s.a", goroot, goos, goarch, dir)}
550                 targ = len(link) - 1
551                 xmkdirall(filepath.Dir(link[targ]))
552         } else {
553                 // Go command.
554                 elem := name
555                 if elem == "go" {
556                         elem = "go_bootstrap"
557                 }
558                 link = []string{pathf("%s/link", tooldir), "-o", pathf("%s/%s%s", tooldir, elem, exe)}
559                 targ = len(link) - 1
560         }
561         ttarg := mtime(link[targ])
562
563         // Gather files that are sources for this target.
564         // Everything in that directory, and any target-specific
565         // additions.
566         files := xreaddir(path)
567
568         // Remove files beginning with . or _,
569         // which are likely to be editor temporary files.
570         // This is the same heuristic build.ScanDir uses.
571         // There do exist real C files beginning with _,
572         // so limit that check to just Go files.
573         files = filter(files, func(p string) bool {
574                 return !strings.HasPrefix(p, ".") && (!strings.HasPrefix(p, "_") || !strings.HasSuffix(p, ".go"))
575         })
576
577         for _, dt := range deptab {
578                 if dir == dt.prefix || strings.HasSuffix(dt.prefix, "/") && strings.HasPrefix(dir, dt.prefix) {
579                         for _, p := range dt.dep {
580                                 p = os.ExpandEnv(p)
581                                 files = append(files, p)
582                         }
583                 }
584         }
585         files = uniq(files)
586
587         // Convert to absolute paths.
588         for i, p := range files {
589                 if !isabs(p) {
590                         files[i] = pathf("%s/%s", path, p)
591                 }
592         }
593
594         // Is the target up-to-date?
595         var gofiles, missing []string
596         stale := rebuildall
597         files = filter(files, func(p string) bool {
598                 for _, suf := range depsuffix {
599                         if strings.HasSuffix(p, suf) {
600                                 goto ok
601                         }
602                 }
603                 return false
604         ok:
605                 t := mtime(p)
606                 if !t.IsZero() && !strings.HasSuffix(p, ".a") && !shouldbuild(p, dir) {
607                         return false
608                 }
609                 if strings.HasSuffix(p, ".go") {
610                         gofiles = append(gofiles, p)
611                 }
612                 if t.After(ttarg) {
613                         stale = true
614                 }
615                 if t.IsZero() {
616                         missing = append(missing, p)
617                 }
618                 return true
619         })
620
621         // If there are no files to compile, we're done.
622         if len(files) == 0 {
623                 return
624         }
625
626         if !stale {
627                 return
628         }
629
630         // For package runtime, copy some files into the work space.
631         if dir == "runtime" || strings.HasPrefix(dir, "runtime/internal/") {
632                 xmkdirall(pathf("%s/pkg/include", goroot))
633                 // For use by assembly and C files.
634                 copyfile(pathf("%s/pkg/include/textflag.h", goroot),
635                         pathf("%s/src/runtime/textflag.h", goroot), 0)
636                 copyfile(pathf("%s/pkg/include/funcdata.h", goroot),
637                         pathf("%s/src/runtime/funcdata.h", goroot), 0)
638                 copyfile(pathf("%s/pkg/include/asm_ppc64x.h", goroot),
639                         pathf("%s/src/runtime/asm_ppc64x.h", goroot), 0)
640         }
641
642         // Generate any missing files; regenerate existing ones.
643         for _, p := range files {
644                 elem := filepath.Base(p)
645                 for _, gt := range gentab {
646                         if gt.gen == nil {
647                                 continue
648                         }
649                         if strings.HasPrefix(elem, gt.nameprefix) {
650                                 if vflag > 1 {
651                                         errprintf("generate %s\n", p)
652                                 }
653                                 gt.gen(path, p)
654                                 // Do not add generated file to clean list.
655                                 // In runtime, we want to be able to
656                                 // build the package with the go tool,
657                                 // and it assumes these generated files already
658                                 // exist (it does not know how to build them).
659                                 // The 'clean' command can remove
660                                 // the generated files.
661                                 goto built
662                         }
663                 }
664                 // Did not rebuild p.
665                 if find(p, missing) >= 0 {
666                         fatal("missing file %s", p)
667                 }
668         built:
669         }
670
671         if goos != gohostos || goarch != gohostarch {
672                 // We've generated the right files; the go command can do the build.
673                 if vflag > 1 {
674                         errprintf("skip build for cross-compile %s\n", dir)
675                 }
676                 return
677         }
678
679         var archive string
680         // The next loop will compile individual non-Go files.
681         // Hand the Go files to the compiler en masse.
682         // For package runtime, this writes go_asm.h, which
683         // the assembly files will need.
684         pkg := dir
685         if strings.HasPrefix(dir, "cmd/") {
686                 pkg = "main"
687         }
688         b := pathf("%s/_go_.a", workdir)
689         clean = append(clean, b)
690         if !ispackcmd {
691                 link = append(link, b)
692         } else {
693                 archive = b
694         }
695         compile := []string{pathf("%s/compile", tooldir), "-pack", "-o", b, "-p", pkg}
696         if gogcflags != "" {
697                 compile = append(compile, strings.Fields(gogcflags)...)
698         }
699         if dir == "runtime" {
700                 compile = append(compile, "-+", "-asmhdr", pathf("%s/go_asm.h", workdir))
701         }
702         compile = append(compile, gofiles...)
703         run(path, CheckExit|ShowOutput, compile...)
704
705         // Compile the files.
706         var wg sync.WaitGroup
707         for _, p := range files {
708                 if !strings.HasSuffix(p, ".s") {
709                         continue
710                 }
711
712                 var compile []string
713                 // Assembly file for a Go package.
714                 compile = []string{
715                         pathf("%s/asm", tooldir),
716                         "-I", workdir,
717                         "-I", pathf("%s/pkg/include", goroot),
718                         "-D", "GOOS_" + goos,
719                         "-D", "GOARCH_" + goarch,
720                         "-D", "GOOS_GOARCH_" + goos + "_" + goarch,
721                 }
722
723                 doclean := true
724                 b := pathf("%s/%s", workdir, filepath.Base(p))
725
726                 // Change the last character of the output file (which was c or s).
727                 b = b[:len(b)-1] + "o"
728                 compile = append(compile, "-o", b, p)
729                 bgrun(&wg, path, compile...)
730
731                 link = append(link, b)
732                 if doclean {
733                         clean = append(clean, b)
734                 }
735         }
736         bgwait(&wg)
737
738         if ispackcmd {
739                 xremove(link[targ])
740                 dopack(link[targ], archive, link[targ+1:])
741                 return
742         }
743
744         // Remove target before writing it.
745         xremove(link[targ])
746         run("", CheckExit|ShowOutput, link...)
747 }
748
749 // matchfield reports whether the field (x,y,z) matches this build.
750 // all the elements in the field must be satisfied.
751 func matchfield(f string) bool {
752         for _, tag := range strings.Split(f, ",") {
753                 if !matchtag(tag) {
754                         return false
755                 }
756         }
757         return true
758 }
759
760 // matchtag reports whether the tag (x or !x) matches this build.
761 func matchtag(tag string) bool {
762         if tag == "" {
763                 return false
764         }
765         if tag[0] == '!' {
766                 if len(tag) == 1 || tag[1] == '!' {
767                         return false
768                 }
769                 return !matchtag(tag[1:])
770         }
771         return tag == "gc" || tag == goos || tag == goarch || tag == "cmd_go_bootstrap" || tag == "go1.1" || (goos == "android" && tag == "linux")
772 }
773
774 // shouldbuild reports whether we should build this file.
775 // It applies the same rules that are used with context tags
776 // in package go/build, except that the GOOS and GOARCH
777 // can appear anywhere in the file name, not just after _.
778 // In particular, they can be the entire file name (like windows.c).
779 // We also allow the special tag cmd_go_bootstrap.
780 // See ../go/bootstrap.go and package go/build.
781 func shouldbuild(file, dir string) bool {
782         // Check file name for GOOS or GOARCH.
783         name := filepath.Base(file)
784         excluded := func(list []string, ok string) bool {
785                 for _, x := range list {
786                         if x == ok {
787                                 continue
788                         }
789                         i := strings.Index(name, x)
790                         if i < 0 {
791                                 continue
792                         }
793                         i += len(x)
794                         if i == len(name) || name[i] == '.' || name[i] == '_' {
795                                 return true
796                         }
797                 }
798                 return false
799         }
800         if excluded(okgoos, goos) || excluded(okgoarch, goarch) {
801                 return false
802         }
803
804         // Omit test files.
805         if strings.Contains(name, "_test") {
806                 return false
807         }
808
809         // Check file contents for // +build lines.
810         for _, p := range splitlines(readfile(file)) {
811                 p = strings.TrimSpace(p)
812                 if p == "" {
813                         continue
814                 }
815                 code := p
816                 i := strings.Index(code, "//")
817                 if i > 0 {
818                         code = strings.TrimSpace(code[:i])
819                 }
820                 if code == "package documentation" {
821                         return false
822                 }
823                 if code == "package main" && dir != "cmd/go" && dir != "cmd/cgo" {
824                         return false
825                 }
826                 if !strings.HasPrefix(p, "//") {
827                         break
828                 }
829                 if !strings.Contains(p, "+build") {
830                         continue
831                 }
832                 fields := splitfields(p[2:])
833                 if len(fields) < 1 || fields[0] != "+build" {
834                         continue
835                 }
836                 for _, p := range fields[1:] {
837                         if matchfield(p) {
838                                 goto fieldmatch
839                         }
840                 }
841                 return false
842         fieldmatch:
843         }
844
845         return true
846 }
847
848 // copy copies the file src to dst, via memory (so only good for small files).
849 func copyfile(dst, src string, flag int) {
850         if vflag > 1 {
851                 errprintf("cp %s %s\n", src, dst)
852         }
853         writefile(readfile(src), dst, flag)
854 }
855
856 // dopack copies the package src to dst,
857 // appending the files listed in extra.
858 // The archive format is the traditional Unix ar format.
859 func dopack(dst, src string, extra []string) {
860         bdst := bytes.NewBufferString(readfile(src))
861         for _, file := range extra {
862                 b := readfile(file)
863                 // find last path element for archive member name
864                 i := strings.LastIndex(file, "/") + 1
865                 j := strings.LastIndex(file, `\`) + 1
866                 if i < j {
867                         i = j
868                 }
869                 fmt.Fprintf(bdst, "%-16.16s%-12d%-6d%-6d%-8o%-10d`\n", file[i:], 0, 0, 0, 0644, len(b))
870                 bdst.WriteString(b)
871                 if len(b)&1 != 0 {
872                         bdst.WriteByte(0)
873                 }
874         }
875         writefile(bdst.String(), dst, 0)
876 }
877
878 // builddeps records the build dependencies for the 'go bootstrap' command.
879 // It is a map[string][]string and generated by mkdeps.bash into deps.go.
880
881 // buildlist is the list of directories being built, sorted by name.
882 var buildlist = makeBuildlist()
883
884 func makeBuildlist() []string {
885         var all []string
886         for dir := range builddeps {
887                 all = append(all, dir)
888         }
889         sort.Strings(all)
890         return all
891 }
892
893 var runtimegen = []string{
894         "zaexperiment.h",
895         "zversion.go",
896 }
897
898 func clean() {
899         for _, name := range buildlist {
900                 path := pathf("%s/src/%s", goroot, name)
901                 // Remove generated files.
902                 for _, elem := range xreaddir(path) {
903                         for _, gt := range gentab {
904                                 if strings.HasPrefix(elem, gt.nameprefix) {
905                                         xremove(pathf("%s/%s", path, elem))
906                                 }
907                         }
908                 }
909                 // Remove generated binary named for directory.
910                 if strings.HasPrefix(name, "cmd/") {
911                         xremove(pathf("%s/%s", path, name[4:]))
912                 }
913         }
914
915         // remove runtimegen files.
916         path := pathf("%s/src/runtime", goroot)
917         for _, elem := range runtimegen {
918                 xremove(pathf("%s/%s", path, elem))
919         }
920
921         if rebuildall {
922                 // Remove object tree.
923                 xremoveall(pathf("%s/pkg/obj/%s_%s", goroot, gohostos, gohostarch))
924
925                 // Remove installed packages and tools.
926                 xremoveall(pathf("%s/pkg/%s_%s", goroot, gohostos, gohostarch))
927                 xremoveall(pathf("%s/pkg/%s_%s", goroot, goos, goarch))
928                 xremoveall(pathf("%s/pkg/%s_%s_race", goroot, gohostos, gohostarch))
929                 xremoveall(pathf("%s/pkg/%s_%s_race", goroot, goos, goarch))
930                 xremoveall(tooldir)
931
932                 // Remove cached version info.
933                 xremove(pathf("%s/VERSION.cache", goroot))
934         }
935 }
936
937 /*
938  * command implementations
939  */
940
941 func usage() {
942         xprintf("usage: go tool dist [command]\n" +
943                 "Commands are:\n" +
944                 "\n" +
945                 "banner         print installation banner\n" +
946                 "bootstrap      rebuild everything\n" +
947                 "clean          deletes all built files\n" +
948                 "env [-p]       print environment (-p: include $PATH)\n" +
949                 "install [dir]  install individual directory\n" +
950                 "list [-json]   list all supported platforms\n" +
951                 "test [-h]      run Go test(s)\n" +
952                 "version        print Go version\n" +
953                 "\n" +
954                 "All commands take -v flags to emit extra information.\n",
955         )
956         xexit(2)
957 }
958
959 // The env command prints the default environment.
960 func cmdenv() {
961         path := flag.Bool("p", false, "emit updated PATH")
962         plan9 := flag.Bool("9", false, "emit plan 9 syntax")
963         windows := flag.Bool("w", false, "emit windows syntax")
964         xflagparse(0)
965
966         format := "%s=\"%s\"\n"
967         switch {
968         case *plan9:
969                 format = "%s='%s'\n"
970         case *windows:
971                 format = "set %s=%s\r\n"
972         }
973
974         xprintf(format, "CC", defaultcc)
975         xprintf(format, "CC_FOR_TARGET", defaultcctarget)
976         xprintf(format, "GOROOT", goroot)
977         xprintf(format, "GOBIN", gobin)
978         xprintf(format, "GOARCH", goarch)
979         xprintf(format, "GOOS", goos)
980         xprintf(format, "GOHOSTARCH", gohostarch)
981         xprintf(format, "GOHOSTOS", gohostos)
982         xprintf(format, "GOTOOLDIR", tooldir)
983         if goarch == "arm" {
984                 xprintf(format, "GOARM", goarm)
985         }
986         if goarch == "386" {
987                 xprintf(format, "GO386", go386)
988         }
989
990         if *path {
991                 sep := ":"
992                 if gohostos == "windows" {
993                         sep = ";"
994                 }
995                 xprintf(format, "PATH", fmt.Sprintf("%s%s%s", gobin, sep, os.Getenv("PATH")))
996         }
997 }
998
999 // The bootstrap command runs a build from scratch,
1000 // stopping at having installed the go_bootstrap command.
1001 func cmdbootstrap() {
1002         flag.BoolVar(&rebuildall, "a", rebuildall, "rebuild all")
1003         xflagparse(0)
1004
1005         if isdir(pathf("%s/src/pkg", goroot)) {
1006                 fatal("\n\n"+
1007                         "The Go package sources have moved to $GOROOT/src.\n"+
1008                         "*** %s still exists. ***\n"+
1009                         "It probably contains stale files that may confuse the build.\n"+
1010                         "Please (check what's there and) remove it and try again.\n"+
1011                         "See https://golang.org/s/go14nopkg\n",
1012                         pathf("%s/src/pkg", goroot))
1013         }
1014
1015         if rebuildall {
1016                 clean()
1017         }
1018
1019         setup()
1020
1021         checkCC()
1022         bootstrapBuildTools()
1023
1024         // For the main bootstrap, building for host os/arch.
1025         oldgoos = goos
1026         oldgoarch = goarch
1027         goos = gohostos
1028         goarch = gohostarch
1029         os.Setenv("GOHOSTARCH", gohostarch)
1030         os.Setenv("GOHOSTOS", gohostos)
1031         os.Setenv("GOARCH", goarch)
1032         os.Setenv("GOOS", goos)
1033
1034         // TODO(rsc): Enable when appropriate.
1035         // This step is only needed if we believe that the Go compiler built from Go 1.4
1036         // will produce different object files than the Go compiler built from itself.
1037         // In the absence of bugs, that should not happen.
1038         // And if there are bugs, they're more likely in the current development tree
1039         // than in a standard release like Go 1.4, so don't do this rebuild by default.
1040         if false {
1041                 xprintf("##### Building Go toolchain using itself.\n")
1042                 for _, dir := range buildlist {
1043                         installed[dir] = make(chan struct{})
1044                 }
1045                 var wg sync.WaitGroup
1046                 for _, dir := range builddeps["cmd/go"] {
1047                         wg.Add(1)
1048                         dir := dir
1049                         go func() {
1050                                 defer wg.Done()
1051                                 install(dir)
1052                         }()
1053                 }
1054                 wg.Wait()
1055                 xprintf("\n")
1056         }
1057
1058         xprintf("##### Building go_bootstrap for host, %s/%s.\n", gohostos, gohostarch)
1059         for _, dir := range buildlist {
1060                 installed[dir] = make(chan struct{})
1061         }
1062         for _, dir := range buildlist {
1063                 go install(dir)
1064         }
1065         <-installed["cmd/go"]
1066
1067         goos = oldgoos
1068         goarch = oldgoarch
1069         os.Setenv("GOARCH", goarch)
1070         os.Setenv("GOOS", goos)
1071
1072         // Build runtime for actual goos/goarch too.
1073         if goos != gohostos || goarch != gohostarch {
1074                 installed["runtime"] = make(chan struct{})
1075                 install("runtime")
1076         }
1077 }
1078
1079 // Cannot use go/build directly because cmd/dist for a new release
1080 // builds against an old release's go/build, which may be out of sync.
1081 // To reduce duplication, we generate the list for go/build from this.
1082 //
1083 // We list all supported platforms in this list, so that this is the
1084 // single point of truth for supported platforms. This list is used
1085 // by 'go tool dist list'.
1086 var cgoEnabled = map[string]bool{
1087         "darwin/386":      true,
1088         "darwin/amd64":    true,
1089         "darwin/arm":      true,
1090         "darwin/arm64":    true,
1091         "dragonfly/amd64": true,
1092         "freebsd/386":     true,
1093         "freebsd/amd64":   true,
1094         "freebsd/arm":     false,
1095         "linux/386":       true,
1096         "linux/amd64":     true,
1097         "linux/arm":       true,
1098         "linux/arm64":     true,
1099         "linux/ppc64":     false,
1100         "linux/ppc64le":   true,
1101         "linux/mips64":    true,
1102         "linux/mips64le":  true,
1103         "linux/s390x":     true,
1104         "android/386":     true,
1105         "android/amd64":   true,
1106         "android/arm":     true,
1107         "android/arm64":   true,
1108         "nacl/386":        false,
1109         "nacl/amd64p32":   false,
1110         "nacl/arm":        false,
1111         "netbsd/386":      true,
1112         "netbsd/amd64":    true,
1113         "netbsd/arm":      true,
1114         "openbsd/386":     true,
1115         "openbsd/amd64":   true,
1116         "openbsd/arm":     false,
1117         "plan9/386":       false,
1118         "plan9/amd64":     false,
1119         "plan9/arm":       false,
1120         "solaris/amd64":   true,
1121         "windows/386":     true,
1122         "windows/amd64":   true,
1123 }
1124
1125 func needCC() bool {
1126         switch os.Getenv("CGO_ENABLED") {
1127         case "1":
1128                 return true
1129         case "0":
1130                 return false
1131         }
1132         return cgoEnabled[gohostos+"/"+gohostarch]
1133 }
1134
1135 func checkCC() {
1136         if !needCC() {
1137                 return
1138         }
1139         if output, err := exec.Command(defaultcc, "--help").CombinedOutput(); err != nil {
1140                 outputHdr := ""
1141                 if len(output) > 0 {
1142                         outputHdr = "\nCommand output:\n\n"
1143                 }
1144                 fatal("cannot invoke C compiler %q: %v\n\n"+
1145                         "Go needs a system C compiler for use with cgo.\n"+
1146                         "To set a C compiler, export CC=the-compiler.\n"+
1147                         "To disable cgo, export CGO_ENABLED=0.\n%s%s", defaultcc, err, outputHdr, output)
1148         }
1149 }
1150
1151 func defaulttarg() string {
1152         // xgetwd might return a path with symlinks fully resolved, and if
1153         // there happens to be symlinks in goroot, then the hasprefix test
1154         // will never succeed. Instead, we use xrealwd to get a canonical
1155         // goroot/src before the comparison to avoid this problem.
1156         pwd := xgetwd()
1157         src := pathf("%s/src/", goroot)
1158         real_src := xrealwd(src)
1159         if !strings.HasPrefix(pwd, real_src) {
1160                 fatal("current directory %s is not under %s", pwd, real_src)
1161         }
1162         pwd = pwd[len(real_src):]
1163         // guard against xrealwd returning the directory without the trailing /
1164         pwd = strings.TrimPrefix(pwd, "/")
1165
1166         return pwd
1167 }
1168
1169 // Install installs the list of packages named on the command line.
1170 func cmdinstall() {
1171         xflagparse(-1)
1172
1173         if flag.NArg() == 0 {
1174                 install(defaulttarg())
1175         }
1176
1177         for _, arg := range flag.Args() {
1178                 install(arg)
1179         }
1180 }
1181
1182 // Clean deletes temporary objects.
1183 func cmdclean() {
1184         xflagparse(0)
1185         clean()
1186 }
1187
1188 // Banner prints the 'now you've installed Go' banner.
1189 func cmdbanner() {
1190         xflagparse(0)
1191
1192         xprintf("\n")
1193         xprintf("---\n")
1194         xprintf("Installed Go for %s/%s in %s\n", goos, goarch, goroot)
1195         xprintf("Installed commands in %s\n", gobin)
1196
1197         if !xsamefile(goroot_final, goroot) {
1198                 // If the files are to be moved, don't check that gobin
1199                 // is on PATH; assume they know what they are doing.
1200         } else if gohostos == "plan9" {
1201                 // Check that gobin is bound before /bin.
1202                 pid := strings.Replace(readfile("#c/pid"), " ", "", -1)
1203                 ns := fmt.Sprintf("/proc/%s/ns", pid)
1204                 if !strings.Contains(readfile(ns), fmt.Sprintf("bind -b %s /bin", gobin)) {
1205                         xprintf("*** You need to bind %s before /bin.\n", gobin)
1206                 }
1207         } else {
1208                 // Check that gobin appears in $PATH.
1209                 pathsep := ":"
1210                 if gohostos == "windows" {
1211                         pathsep = ";"
1212                 }
1213                 if !strings.Contains(pathsep+os.Getenv("PATH")+pathsep, pathsep+gobin+pathsep) {
1214                         xprintf("*** You need to add %s to your PATH.\n", gobin)
1215                 }
1216         }
1217
1218         if !xsamefile(goroot_final, goroot) {
1219                 xprintf("\n"+
1220                         "The binaries expect %s to be copied or moved to %s\n",
1221                         goroot, goroot_final)
1222         }
1223 }
1224
1225 // Version prints the Go version.
1226 func cmdversion() {
1227         xflagparse(0)
1228         xprintf("%s\n", findgoversion())
1229 }
1230
1231 // cmdlist lists all supported platforms.
1232 func cmdlist() {
1233         jsonFlag := flag.Bool("json", false, "produce JSON output")
1234         xflagparse(0)
1235
1236         var plats []string
1237         for p := range cgoEnabled {
1238                 plats = append(plats, p)
1239         }
1240         sort.Strings(plats)
1241
1242         if !*jsonFlag {
1243                 for _, p := range plats {
1244                         xprintf("%s\n", p)
1245                 }
1246                 return
1247         }
1248
1249         type jsonResult struct {
1250                 GOOS         string
1251                 GOARCH       string
1252                 CgoSupported bool
1253         }
1254         var results []jsonResult
1255         for _, p := range plats {
1256                 fields := strings.Split(p, "/")
1257                 results = append(results, jsonResult{
1258                         GOOS:         fields[0],
1259                         GOARCH:       fields[1],
1260                         CgoSupported: cgoEnabled[p]})
1261         }
1262         out, err := json.MarshalIndent(results, "", "\t")
1263         if err != nil {
1264                 fatal("json marshal error: %v", err)
1265         }
1266         if _, err := os.Stdout.Write(out); err != nil {
1267                 fatal("write failed: %v", err)
1268         }
1269 }