]> Cypherpunks.ru repositories - gostls13.git/blob - src/cmd/dist/build.go
[dev.cc] all: merge master (5f1efe7) into dev.cc
[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         "flag"
10         "fmt"
11         "os"
12         "path/filepath"
13         "runtime"
14         "strings"
15 )
16
17 // Initialization for any invocation.
18
19 // The usual variables.
20 var (
21         goarch           string
22         gobin            string
23         gohostarch       string
24         gohostchar       string
25         gohostos         string
26         goos             string
27         goarm            string
28         go386            string
29         goroot           string
30         goroot_final     string
31         goextlinkenabled string
32         workdir          string
33         tooldir          string
34         gochar           string
35         oldgoos          string
36         oldgoarch        string
37         oldgochar        string
38         slash            string
39         exe              string
40         defaultcc        string
41         defaultcflags    string
42         defaultldflags   string
43         defaultcxxtarget string
44         defaultcctarget  string
45         rebuildall       bool
46         defaultclang     bool
47
48         sflag bool // build static binaries
49         vflag int  // verbosity
50 )
51
52 // The known architecture letters.
53 var gochars = "566899"
54
55 // The known architectures.
56 var okgoarch = []string{
57         // same order as gochars
58         "arm",
59         "amd64",
60         "amd64p32",
61         "386",
62         "ppc64",
63         "ppc64le",
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/include/u.h", 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         i := find(gohostarch, okgoarch)
151         if i < 0 {
152                 fatal("unknown $GOHOSTARCH %s", gohostarch)
153         }
154         gohostchar = gochars[i : i+1]
155
156         b = os.Getenv("GOARCH")
157         if b == "" {
158                 b = gohostarch
159         }
160         goarch = b
161         i = find(goarch, okgoarch)
162         if i < 0 {
163                 fatal("unknown $GOARCH %s", goarch)
164         }
165         gochar = gochars[i : i+1]
166
167         b = os.Getenv("GO_EXTLINK_ENABLED")
168         if b != "" {
169                 if b != "0" && b != "1" {
170                         fatal("unknown $GO_EXTLINK_ENABLED %s", b)
171                 }
172                 goextlinkenabled = b
173         }
174
175         b = os.Getenv("CC")
176         if b == "" {
177                 // Use clang on OS X, because gcc is deprecated there.
178                 // Xcode for OS X 10.9 Mavericks will ship a fake "gcc" binary that
179                 // actually runs clang. We prepare different command
180                 // lines for the two binaries, so it matters what we call it.
181                 // See golang.org/issue/5822.
182                 if defaultclang {
183                         b = "clang"
184                 } else {
185                         b = "gcc"
186                 }
187         }
188         defaultcc = b
189
190         defaultcflags = os.Getenv("CFLAGS")
191
192         defaultldflags = os.Getenv("LDFLAGS")
193
194         b = os.Getenv("CC_FOR_TARGET")
195         if b == "" {
196                 b = defaultcc
197         }
198         defaultcctarget = b
199
200         b = os.Getenv("CXX_FOR_TARGET")
201         if b == "" {
202                 b = os.Getenv("CXX")
203                 if b == "" {
204                         if defaultclang {
205                                 b = "clang++"
206                         } else {
207                                 b = "g++"
208                         }
209                 }
210         }
211         defaultcxxtarget = b
212
213         // For tools being invoked but also for os.ExpandEnv.
214         os.Setenv("GO386", go386)
215         os.Setenv("GOARCH", goarch)
216         os.Setenv("GOARM", goarm)
217         os.Setenv("GOHOSTARCH", gohostarch)
218         os.Setenv("GOHOSTOS", gohostos)
219         os.Setenv("GOOS", goos)
220         os.Setenv("GOROOT", goroot)
221         os.Setenv("GOROOT_FINAL", goroot_final)
222
223         // Make the environment more predictable.
224         os.Setenv("LANG", "C")
225         os.Setenv("LANGUAGE", "en_US.UTF8")
226
227         workdir = xworkdir()
228         xatexit(rmworkdir)
229
230         tooldir = pathf("%s/pkg/tool/%s_%s", goroot, gohostos, gohostarch)
231 }
232
233 // rmworkdir deletes the work directory.
234 func rmworkdir() {
235         if vflag > 1 {
236                 errprintf("rm -rf %s\n", workdir)
237         }
238         xremoveall(workdir)
239 }
240
241 // Remove trailing spaces.
242 func chomp(s string) string {
243         return strings.TrimRight(s, " \t\r\n")
244 }
245
246 func branchtag(branch string) (tag string, precise bool) {
247         b := run(goroot, CheckExit, "git", "log", "--decorate=full", "--format=format:%d", "master.."+branch)
248         tag = branch
249         for _, line := range splitlines(b) {
250                 // Each line is either blank, or looks like
251                 //        (tag: refs/tags/go1.4rc2, refs/remotes/origin/release-branch.go1.4, refs/heads/release-branch.go1.4)
252                 // We need to find an element starting with refs/tags/.
253                 i := strings.Index(line, " refs/tags/")
254                 if i < 0 {
255                         continue
256                 }
257                 i += len(" refs/tags/")
258                 // The tag name ends at a comma or paren (prefer the first).
259                 j := strings.Index(line[i:], ",")
260                 if j < 0 {
261                         j = strings.Index(line[i:], ")")
262                 }
263                 if j < 0 {
264                         continue // malformed line; ignore it
265                 }
266                 tag = line[i : i+j]
267                 if i == 0 {
268                         precise = true // tag denotes HEAD
269                 }
270                 break
271         }
272         return
273 }
274
275 // findgoversion determines the Go version to use in the version string.
276 func findgoversion() string {
277         // The $GOROOT/VERSION file takes priority, for distributions
278         // without the source repo.
279         path := pathf("%s/VERSION", goroot)
280         if isfile(path) {
281                 b := chomp(readfile(path))
282                 // Commands such as "dist version > VERSION" will cause
283                 // the shell to create an empty VERSION file and set dist's
284                 // stdout to its fd. dist in turn looks at VERSION and uses
285                 // its content if available, which is empty at this point.
286                 // Only use the VERSION file if it is non-empty.
287                 if b != "" {
288                         return b
289                 }
290         }
291
292         // The $GOROOT/VERSION.cache file is a cache to avoid invoking
293         // git every time we run this command.  Unlike VERSION, it gets
294         // deleted by the clean command.
295         path = pathf("%s/VERSION.cache", goroot)
296         if isfile(path) {
297                 return chomp(readfile(path))
298         }
299
300         // Otherwise, use Git.
301         // What is the current branch?
302         branch := chomp(run(goroot, CheckExit, "git", "rev-parse", "--abbrev-ref", "HEAD"))
303
304         // What are the tags along the current branch?
305         tag := "devel"
306         precise := false
307
308         // If we're on a release branch, use the closest matching tag
309         // that is on the release branch (and not on the master branch).
310         if strings.HasPrefix(branch, "release-branch.") {
311                 tag, precise = branchtag(branch)
312         }
313
314         if !precise {
315                 // Tag does not point at HEAD; add hash and date to version.
316                 tag += chomp(run(goroot, CheckExit, "git", "log", "-n", "1", "--format=format: +%h %cd", "HEAD"))
317         }
318
319         // Cache version.
320         writefile(tag, path, 0)
321
322         return tag
323 }
324
325 /*
326  * Initial tree setup.
327  */
328
329 // The old tools that no longer live in $GOBIN or $GOROOT/bin.
330 var oldtool = []string{
331         "5a", "5c", "5g", "5l",
332         "6a", "6c", "6g", "6l",
333         "8a", "8c", "8g", "8l",
334         "9a", "9c", "9g", "9l",
335         "6cov",
336         "6nm",
337         "6prof",
338         "cgo",
339         "ebnflint",
340         "goapi",
341         "gofix",
342         "goinstall",
343         "gomake",
344         "gopack",
345         "gopprof",
346         "gotest",
347         "gotype",
348         "govet",
349         "goyacc",
350         "quietgcc",
351 }
352
353 // Unreleased directories (relative to $GOROOT) that should
354 // not be in release branches.
355 var unreleased = []string{
356         "src/cmd/link",
357         "src/cmd/objwriter",
358         "src/debug/goobj",
359         "src/old",
360 }
361
362 // setup sets up the tree for the initial build.
363 func setup() {
364         // Create bin directory.
365         if p := pathf("%s/bin", goroot); !isdir(p) {
366                 xmkdir(p)
367         }
368
369         // Create package directory.
370         if p := pathf("%s/pkg", goroot); !isdir(p) {
371                 xmkdir(p)
372         }
373
374         p := pathf("%s/pkg/%s_%s", goroot, gohostos, gohostarch)
375         if rebuildall {
376                 xremoveall(p)
377         }
378         xmkdirall(p)
379
380         if goos != gohostos || goarch != gohostarch {
381                 p := pathf("%s/pkg/%s_%s", goroot, goos, goarch)
382                 if rebuildall {
383                         xremoveall(p)
384                 }
385                 xmkdirall(p)
386         }
387
388         // Create object directory.
389         // We keep it in pkg/ so that all the generated binaries
390         // are in one tree.  If pkg/obj/libgc.a exists, it is a dreg from
391         // before we used subdirectories of obj.  Delete all of obj
392         // to clean up.
393         if p := pathf("%s/pkg/obj/libgc.a", goroot); isfile(p) {
394                 xremoveall(pathf("%s/pkg/obj", goroot))
395         }
396         p = pathf("%s/pkg/obj/%s_%s", goroot, gohostos, gohostarch)
397         if rebuildall {
398                 xremoveall(p)
399         }
400         xmkdirall(p)
401
402         // Create tool directory.
403         // We keep it in pkg/, just like the object directory above.
404         if rebuildall {
405                 xremoveall(tooldir)
406         }
407         xmkdirall(tooldir)
408
409         // Remove tool binaries from before the tool/gohostos_gohostarch
410         xremoveall(pathf("%s/bin/tool", goroot))
411
412         // Remove old pre-tool binaries.
413         for _, old := range oldtool {
414                 xremove(pathf("%s/bin/%s", goroot, old))
415         }
416
417         // If $GOBIN is set and has a Go compiler, it must be cleaned.
418         for _, char := range gochars {
419                 if isfile(pathf("%s%s%c%s", gobin, slash, char, "g")) {
420                         for _, old := range oldtool {
421                                 xremove(pathf("%s/%s", gobin, old))
422                         }
423                         break
424                 }
425         }
426
427         // For release, make sure excluded things are excluded.
428         goversion := findgoversion()
429         if strings.HasPrefix(goversion, "release.") || (strings.HasPrefix(goversion, "go") && !strings.Contains(goversion, "beta")) {
430                 for _, dir := range unreleased {
431                         if p := pathf("%s/%s", goroot, dir); isdir(p) {
432                                 fatal("%s should not exist in release build", p)
433                         }
434                 }
435         }
436 }
437
438 /*
439  * C library and tool building
440  */
441
442 // gccargs is the gcc command line to use for compiling a single C file.
443 var proto_gccargs = []string{
444         "-Wall",
445         // native Plan 9 compilers don't like non-standard prototypes
446         // so let gcc catch them.
447         "-Wstrict-prototypes",
448         "-Wextra",
449         "-Wunused",
450         "-Wno-sign-compare",
451         "-Wno-missing-braces",
452         "-Wno-parentheses",
453         "-Wno-unknown-pragmas",
454         "-Wno-switch",
455         "-Wno-comment",
456         "-Wno-missing-field-initializers",
457         "-Werror",
458         "-fno-common",
459         "-ggdb",
460         "-pipe",
461 }
462
463 // gccargs2 is the second part of gccargs.
464 // it is used if the environment isn't defining CFLAGS.
465 var proto_gccargs2 = []string{
466         // on older versions of GCC, -Wuninitialized is not supported
467         // without -O, so put it here together with -O settings in case
468         // the user's $CFLAGS doesn't include -O.
469         "-Wuninitialized",
470         "-O2",
471 }
472
473 func init() {
474         if runtime.GOOS == "netbsd" && runtime.GOARCH == "arm" {
475                 // GCC 4.5.4 (NetBSD nb1 20120916) on ARM is known to mis-optimize gc/mparith3.c
476                 // Fix available at http://patchwork.ozlabs.org/patch/64562/.
477                 proto_gccargs2[1] = "-O1"
478         }
479 }
480
481 var gccargs, ldargs []string
482
483 // deptab lists changes to the default dependencies for a given prefix.
484 // deps ending in /* read the whole directory; deps beginning with -
485 // exclude files with that prefix.
486 var deptab = []struct {
487         prefix string   // prefix of target
488         dep    []string // dependency tweaks for targets with that prefix
489 }{
490         {"lib9", []string{
491                 "$GOROOT/include/u.h",
492                 "$GOROOT/include/utf.h",
493                 "$GOROOT/include/fmt.h",
494                 "$GOROOT/include/libc.h",
495                 "fmt/*",
496                 "utf/*",
497         }},
498         {"libbio", []string{
499                 "$GOROOT/include/u.h",
500                 "$GOROOT/include/utf.h",
501                 "$GOROOT/include/fmt.h",
502                 "$GOROOT/include/libc.h",
503                 "$GOROOT/include/bio.h",
504         }},
505         {"liblink", []string{
506                 "$GOROOT/include/u.h",
507                 "$GOROOT/include/utf.h",
508                 "$GOROOT/include/fmt.h",
509                 "$GOROOT/include/libc.h",
510                 "$GOROOT/include/bio.h",
511                 "$GOROOT/include/ar.h",
512                 "$GOROOT/include/link.h",
513                 "anames5.c",
514                 "anames6.c",
515                 "anames8.c",
516                 "anames9.c",
517         }},
518         {"cmd/gc", []string{
519                 "opnames.h",
520         }},
521         {"cmd/5g", []string{
522                 "$GOROOT/pkg/obj/${GOHOSTOS}_$GOHOSTARCH/libgc.a",
523         }},
524         {"cmd/6g", []string{
525                 "$GOROOT/pkg/obj/${GOHOSTOS}_$GOHOSTARCH/libgc.a",
526         }},
527         {"cmd/8g", []string{
528                 "$GOROOT/pkg/obj/${GOHOSTOS}_$GOHOSTARCH/libgc.a",
529         }},
530         {"cmd/9g", []string{
531                 "$GOROOT/pkg/obj/${GOHOSTOS}_$GOHOSTARCH/libgc.a",
532         }},
533         {"cmd/5l", []string{
534                 "$GOROOT/pkg/obj/${GOHOSTOS}_$GOHOSTARCH/libld.a",
535         }},
536         {"cmd/6l", []string{
537                 "$GOROOT/pkg/obj/${GOHOSTOS}_$GOHOSTARCH/libld.a",
538         }},
539         {"cmd/8l", []string{
540                 "$GOROOT/pkg/obj/${GOHOSTOS}_$GOHOSTARCH/libld.a",
541         }},
542         {"cmd/9l", []string{
543                 "$GOROOT/pkg/obj/${GOHOSTOS}_$GOHOSTARCH/libld.a",
544         }},
545         {"cmd/go", []string{
546                 "zdefaultcc.go",
547         }},
548         {"cmd/", []string{
549                 "$GOROOT/pkg/obj/${GOHOSTOS}_$GOHOSTARCH/liblink.a",
550                 "$GOROOT/pkg/obj/${GOHOSTOS}_$GOHOSTARCH/libbio.a",
551                 "$GOROOT/pkg/obj/${GOHOSTOS}_$GOHOSTARCH/lib9.a",
552         }},
553         {"runtime", []string{
554                 "zversion.go",
555         }},
556 }
557
558 // depsuffix records the allowed suffixes for source files.
559 var depsuffix = []string{
560         ".c",
561         ".h",
562         ".s",
563         ".go",
564 }
565
566 // gentab records how to generate some trivial files.
567 var gentab = []struct {
568         nameprefix string
569         gen        func(string, string)
570 }{
571         {"opnames.h", gcopnames},
572         {"anames5.c", mkanames},
573         {"anames6.c", mkanames},
574         {"anames8.c", mkanames},
575         {"anames9.c", mkanames},
576         {"zdefaultcc.go", mkzdefaultcc},
577         {"zversion.go", mkzversion},
578
579         // not generated anymore, but delete the file if we see it
580         {"enam.c", nil},
581 }
582
583 // install installs the library, package, or binary associated with dir,
584 // which is relative to $GOROOT/src.
585 func install(dir string) {
586         if vflag > 0 {
587                 if goos != gohostos || goarch != gohostarch {
588                         errprintf("%s (%s/%s)\n", dir, goos, goarch)
589                 } else {
590                         errprintf("%s\n", dir)
591                 }
592         }
593
594         var clean []string
595         defer func() {
596                 for _, name := range clean {
597                         xremove(name)
598                 }
599         }()
600
601         // path = full path to dir.
602         path := pathf("%s/src/%s", goroot, dir)
603         name := filepath.Base(dir)
604
605         // set up gcc command line on first run.
606         if gccargs == nil {
607                 gccargs = splitfields(defaultcc + " " + defaultcflags)
608                 gccargs = append(gccargs, proto_gccargs...)
609                 if defaultcflags == "" {
610                         gccargs = append(gccargs, proto_gccargs2...)
611                 }
612                 if strings.Contains(gccargs[0], "clang") {
613                         // disable ASCII art in clang errors, if possible
614                         gccargs = append(gccargs, "-fno-caret-diagnostics")
615                         // clang is too smart about unused command-line arguments
616                         gccargs = append(gccargs, "-Qunused-arguments")
617                 }
618                 // disable word wrapping in error messages
619                 gccargs = append(gccargs, "-fmessage-length=0")
620                 if gohostos == "darwin" && gohostarch != "arm" {
621                         // golang.org/issue/5261
622                         gccargs = append(gccargs, "-mmacosx-version-min=10.6")
623                 }
624         }
625         if ldargs == nil && defaultldflags != "" {
626                 ldargs = splitfields(defaultldflags)
627         }
628
629         isgo := true
630         ispkg := !strings.HasPrefix(dir, "cmd/") || strings.HasPrefix(dir, "cmd/internal/") || strings.HasPrefix(dir, "cmd/asm/internal/")
631         islib := false
632
633         // Legacy C exceptions.
634         switch dir {
635         case "lib9", "libbio", "liblink", "cmd/gc", "cmd/ld":
636                 islib = true
637                 isgo = false
638         case "cmd/5a", "cmd/5g", "cmd/5l",
639                 "cmd/6a", "cmd/6g", "cmd/6l",
640                 "cmd/8a", "cmd/8g", "cmd/8l",
641                 "cmd/9a", "cmd/9g", "cmd/9l":
642                 isgo = false
643         }
644
645         // Start final link command line.
646         // Note: code below knows that link.p[targ] is the target.
647         var (
648                 link      []string
649                 targ      int
650                 ispackcmd bool
651         )
652         switch {
653         case islib:
654                 // C library.
655                 prefix := ""
656                 if !strings.HasPrefix(name, "lib") {
657                         prefix = "lib"
658                 }
659                 link = []string{"ar", "rsc", pathf("%s/pkg/obj/%s_%s/%s%s.a", goroot, gohostos, gohostarch, prefix, name)}
660                 if gohostos == "plan9" {
661                         link[1] = "rc"
662                 }
663                 targ = len(link) - 1
664
665         case ispkg:
666                 // Go library (package).
667                 ispackcmd = true
668                 link = []string{"pack", pathf("%s/pkg/%s_%s/%s.a", goroot, goos, goarch, dir)}
669                 targ = len(link) - 1
670                 xmkdirall(filepath.Dir(link[targ]))
671
672         case dir == "cmd/go" || dir == "cmd/cgo":
673                 // Go command.
674                 elem := name
675                 if elem == "go" {
676                         elem = "go_bootstrap"
677                 }
678                 link = []string{fmt.Sprintf("%s/%sl", tooldir, gochar), "-o", pathf("%s/%s%s", tooldir, elem, exe)}
679                 targ = len(link) - 1
680
681         default:
682                 // C command. Use gccargs and ldargs.
683                 if gohostos == "plan9" {
684                         link = []string{fmt.Sprintf("%sl", gohostchar), "-o", pathf("%s/%s", tooldir, name)}
685                         targ = len(link) - 1
686                 } else {
687                         link = append(link, gccargs...)
688                         link = append(link, ldargs...)
689                         if sflag {
690                                 link = append(link, "-static")
691                         }
692                         link = append(link, "-o", pathf("%s/%s%s", tooldir, name, exe))
693                         targ = len(link) - 1
694                         switch gohostarch {
695                         case "amd64":
696                                 link = append(link, "-m64")
697                         case "386":
698                                 link = append(link, "-m32")
699                         }
700                 }
701         }
702         ttarg := mtime(link[targ])
703
704         // Gather files that are sources for this target.
705         // Everything in that directory, and any target-specific
706         // additions.
707         files := xreaddir(path)
708
709         // Remove files beginning with . or _,
710         // which are likely to be editor temporary files.
711         // This is the same heuristic build.ScanDir uses.
712         // There do exist real C files beginning with _,
713         // so limit that check to just Go files.
714         files = filter(files, func(p string) bool {
715                 return !strings.HasPrefix(p, ".") && (!strings.HasPrefix(p, "_") || !strings.HasSuffix(p, ".go"))
716         })
717
718         var libs []string
719
720         for _, dt := range deptab {
721                 if dir == dt.prefix || strings.HasSuffix(dt.prefix, "/") && strings.HasPrefix(dir, dt.prefix) {
722                         for _, p := range dt.dep {
723                                 p = os.ExpandEnv(p)
724                                 switch {
725                                 case strings.HasSuffix(p, ".a"):
726                                         libs = append(libs, p)
727
728                                 case strings.HasSuffix(p, "/*"):
729                                         dir := strings.TrimSuffix(p, "/*")
730                                         for _, name := range xreaddir(pathf("%s/%s", path, dir)) {
731                                                 files = append(files, pathf("%s/%s", dir, name))
732                                         }
733
734                                 case strings.HasPrefix(p, "-"):
735                                         files = filter(files, func(s string) bool {
736                                                 return !strings.HasPrefix(s, p[1:])
737                                         })
738
739                                 default:
740                                         files = append(files, p)
741                                 }
742                         }
743                 }
744         }
745         files = uniq(files)
746
747         // Convert to absolute paths.
748         for i, p := range files {
749                 if !isabs(p) {
750                         files[i] = pathf("%s/%s", path, p)
751                 }
752         }
753
754         // Is the target up-to-date?
755         var gofiles, missing []string
756         stale := rebuildall
757         files = filter(files, func(p string) bool {
758                 for _, suf := range depsuffix {
759                         if strings.HasSuffix(p, suf) {
760                                 goto ok
761                         }
762                 }
763                 return false
764         ok:
765                 t := mtime(p)
766                 if !t.IsZero() && !strings.HasSuffix(p, ".a") && !shouldbuild(p, dir) {
767                         return false
768                 }
769                 if strings.HasSuffix(p, ".go") {
770                         gofiles = append(gofiles, p)
771                 }
772                 if t.After(ttarg) {
773                         stale = true
774                 }
775                 if t.IsZero() {
776                         missing = append(missing, p)
777                 }
778                 return true
779         })
780
781         // If there are no files to compile, we're done.
782         if len(files) == 0 {
783                 return
784         }
785
786         if !stale {
787                 for _, p := range libs {
788                         if mtime(p).After(ttarg) {
789                                 stale = true
790                                 break
791                         }
792                 }
793         }
794
795         if !stale {
796                 return
797         }
798
799         // For package runtime, copy some files into the work space.
800         if dir == "runtime" {
801                 // For use by assembly and C files.
802                 copyfile(pathf("%s/pkg/%s_%s/textflag.h", goroot, goos, goarch),
803                         pathf("%s/src/cmd/ld/textflag.h", goroot), 0)
804                 copyfile(pathf("%s/pkg/%s_%s/funcdata.h", goroot, goos, goarch),
805                         pathf("%s/src/runtime/funcdata.h", goroot), 0)
806         }
807
808         // Generate any missing files; regenerate existing ones.
809         for _, p := range files {
810                 elem := filepath.Base(p)
811                 for _, gt := range gentab {
812                         if gt.gen == nil {
813                                 continue
814                         }
815                         if strings.HasPrefix(elem, gt.nameprefix) {
816                                 if vflag > 1 {
817                                         errprintf("generate %s\n", p)
818                                 }
819                                 gt.gen(path, p)
820                                 // Do not add generated file to clean list.
821                                 // In runtime, we want to be able to
822                                 // build the package with the go tool,
823                                 // and it assumes these generated files already
824                                 // exist (it does not know how to build them).
825                                 // The 'clean' command can remove
826                                 // the generated files.
827                                 goto built
828                         }
829                 }
830                 // Did not rebuild p.
831                 if find(p, missing) >= 0 {
832                         fatal("missing file %s", p)
833                 }
834         built:
835         }
836
837         if (goos != gohostos || goarch != gohostarch) && isgo {
838                 // We've generated the right files; the go command can do the build.
839                 if vflag > 1 {
840                         errprintf("skip build for cross-compile %s\n", dir)
841                 }
842                 return
843         }
844
845         var archive string
846         if isgo {
847                 // The next loop will compile individual non-Go files.
848                 // Hand the Go files to the compiler en masse.
849                 // For package runtime, this writes go_asm.h, which
850                 // the assembly files will need.
851                 pkg := dir
852                 if strings.HasPrefix(dir, "cmd/") {
853                         pkg = "main"
854                 }
855                 b := pathf("%s/_go_.a", workdir)
856                 clean = append(clean, b)
857                 if !ispackcmd {
858                         link = append(link, b)
859                 } else {
860                         archive = b
861                 }
862                 compile := []string{pathf("%s/%sg", tooldir, gochar), "-pack", "-o", b, "-p", pkg}
863                 if dir == "runtime" {
864                         compile = append(compile, "-+", "-asmhdr", pathf("%s/go_asm.h", workdir))
865                 }
866                 compile = append(compile, gofiles...)
867                 run(path, CheckExit|ShowOutput, compile...)
868         }
869
870         // Compile the files.
871         for _, p := range files {
872                 if !strings.HasSuffix(p, ".c") && !strings.HasSuffix(p, ".s") {
873                         continue
874                 }
875                 name := filepath.Base(p)
876
877                 var compile []string
878                 if !isgo {
879                         // C library or tool.
880                         if gohostos == "plan9" {
881                                 compile = []string{
882                                         gohostchar + "c", "-FTVwp",
883                                         "-DPLAN9",
884                                         "-D__STDC__=1",
885                                         "-D__SIZE_TYPE__=ulong", // for GNU bison
886                                         pathf("-I%s/include/plan9", goroot),
887                                         pathf("-I%s/include/plan9/%s", goroot, gohostarch),
888                                 }
889                         } else {
890                                 compile = gccargs[0:len(gccargs):len(gccargs)]
891                                 compile = append(compile, "-c")
892                                 switch gohostarch {
893                                 case "amd64":
894                                         compile = append(compile, "-m64")
895                                 case "386":
896                                         compile = append(compile, "-m32")
897                                 }
898                                 compile = append(compile, "-I", pathf("%s/include", goroot))
899                         }
900
901                         if dir == "lib9" {
902                                 compile = append(compile, "-DPLAN9PORT")
903                         }
904
905                         compile = append(compile, "-I", path)
906
907                         // lib9/goos.c gets the default constants hard-coded.
908                         if name == "goos.c" {
909                                 compile = append(compile,
910                                         "-D", fmt.Sprintf("GOOS=%q", goos),
911                                         "-D", fmt.Sprintf("GOARCH=%q", goarch),
912                                         "-D", fmt.Sprintf("GOHOSTOS=%q", gohostos),
913                                         "-D", fmt.Sprintf("GOHOSTARCH=%q", gohostarch),
914                                         "-D", fmt.Sprintf("GOROOT=%q", goroot_final),
915                                         "-D", fmt.Sprintf("GOVERSION=%q", findgoversion()),
916                                         "-D", fmt.Sprintf("GOARM=%q", goarm),
917                                         "-D", fmt.Sprintf("GO386=%q", go386),
918                                         "-D", fmt.Sprintf("GO_EXTLINK_ENABLED=%q", goextlinkenabled),
919                                 )
920                         }
921
922                         // liblink/go.c records the GOEXPERIMENT setting used during the build.
923                         if name == "go.c" {
924                                 compile = append(compile,
925                                         "-D", fmt.Sprintf("GOEXPERIMENT=%q", os.Getenv("GOEXPERIMENT")))
926                         }
927                 } else {
928                         // Assembly file for a Go package.
929                         compile = []string{
930                                 pathf("%s/%sa", tooldir, gochar),
931                                 "-I", workdir,
932                                 "-I", pathf("%s/pkg/%s_%s", goroot, goos, goarch),
933                                 "-D", "GOOS_" + goos,
934                                 "-D", "GOARCH_" + goarch,
935                                 "-D", "GOOS_GOARCH_" + goos + "_" + goarch,
936                         }
937                 }
938
939                 doclean := true
940                 b := pathf("%s/%s", workdir, filepath.Base(p))
941                 if !isgo && gohostos == "darwin" {
942                         // To debug C programs on OS X, it is not enough to say -ggdb
943                         // on the command line.  You have to leave the object files
944                         // lying around too.  Leave them in pkg/obj/, which does not
945                         // get removed when this tool exits.
946                         obj := pathf("%s/pkg/obj/%s", goroot, dir)
947                         xmkdirall(obj)
948                         b = pathf("%s/%s", obj, filepath.Base(p))
949                         doclean = false
950                 }
951
952                 // Change the last character of the output file (which was c or s).
953                 if gohostos == "plan9" {
954                         b = b[:len(b)-1] + gohostchar
955                 } else {
956                         b = b[:len(b)-1] + "o"
957                 }
958                 compile = append(compile, "-o", b, p)
959                 bgrun(path, compile...)
960
961                 link = append(link, b)
962                 if doclean {
963                         clean = append(clean, b)
964                 }
965         }
966         bgwait()
967
968         if isgo && ispackcmd {
969                 xremove(link[targ])
970                 dopack(link[targ], archive, link[targ+1:])
971                 return
972         }
973
974         if !islib && !isgo {
975                 // C binaries need the libraries explicitly, and -lm.
976                 link = append(link, libs...)
977                 if gohostos != "plan9" {
978                         link = append(link, "-lm")
979                 }
980         }
981
982         // Remove target before writing it.
983         xremove(link[targ])
984         run("", CheckExit|ShowOutput, link...)
985 }
986
987 // matchfield reports whether the field matches this build.
988 func matchfield(f string) bool {
989         for _, tag := range strings.Split(f, ",") {
990                 if tag == goos || tag == goarch || tag == "cmd_go_bootstrap" || tag == "go1.1" || (goos == "android" && tag == "linux") {
991                         continue
992                 }
993                 return false
994         }
995         return true
996 }
997
998 // shouldbuild reports whether we should build this file.
999 // It applies the same rules that are used with context tags
1000 // in package go/build, except that the GOOS and GOARCH
1001 // can appear anywhere in the file name, not just after _.
1002 // In particular, they can be the entire file name (like windows.c).
1003 // We also allow the special tag cmd_go_bootstrap.
1004 // See ../go/bootstrap.go and package go/build.
1005 func shouldbuild(file, dir string) bool {
1006         // Check file name for GOOS or GOARCH.
1007         name := filepath.Base(file)
1008         excluded := func(list []string, ok string) bool {
1009                 for _, x := range list {
1010                         if x == ok {
1011                                 continue
1012                         }
1013                         i := strings.Index(name, x)
1014                         if i < 0 {
1015                                 continue
1016                         }
1017                         i += len(x)
1018                         if i == len(name) || name[i] == '.' || name[i] == '_' {
1019                                 return true
1020                         }
1021                 }
1022                 return false
1023         }
1024         if excluded(okgoos, goos) || excluded(okgoarch, goarch) {
1025                 return false
1026         }
1027
1028         // Omit test files.
1029         if strings.Contains(name, "_test") {
1030                 return false
1031         }
1032
1033         // cmd/go/doc.go has a giant /* */ comment before
1034         // it gets to the important detail that it is not part of
1035         // package main.  We don't parse those comments,
1036         // so special case that file.
1037         if strings.HasSuffix(file, "cmd/go/doc.go") || strings.HasSuffix(file, "cmd\\go\\doc.go") {
1038                 return false
1039         }
1040         if strings.HasSuffix(file, "cmd/cgo/doc.go") || strings.HasSuffix(file, "cmd\\cgo\\doc.go") {
1041                 return false
1042         }
1043
1044         // Check file contents for // +build lines.
1045         for _, p := range splitlines(readfile(file)) {
1046                 p = strings.TrimSpace(p)
1047                 if p == "" {
1048                         continue
1049                 }
1050                 if strings.Contains(p, "package documentation") {
1051                         return false
1052                 }
1053                 if strings.Contains(p, "package main") && dir != "cmd/go" && dir != "cmd/cgo" {
1054                         return false
1055                 }
1056                 if !strings.HasPrefix(p, "//") {
1057                         break
1058                 }
1059                 if !strings.Contains(p, "+build") {
1060                         continue
1061                 }
1062                 fields := splitfields(p)
1063                 if len(fields) < 2 || fields[1] != "+build" {
1064                         continue
1065                 }
1066                 for _, p := range fields[2:] {
1067                         if (p[0] == '!' && !matchfield(p[1:])) || matchfield(p) {
1068                                 goto fieldmatch
1069                         }
1070                 }
1071                 return false
1072         fieldmatch:
1073         }
1074
1075         return true
1076 }
1077
1078 // copy copies the file src to dst, via memory (so only good for small files).
1079 func copyfile(dst, src string, exec int) {
1080         if vflag > 1 {
1081                 errprintf("cp %s %s\n", src, dst)
1082         }
1083         writefile(readfile(src), dst, exec)
1084 }
1085
1086 // dopack copies the package src to dst,
1087 // appending the files listed in extra.
1088 // The archive format is the traditional Unix ar format.
1089 func dopack(dst, src string, extra []string) {
1090         bdst := bytes.NewBufferString(readfile(src))
1091         for _, file := range extra {
1092                 b := readfile(file)
1093                 // find last path element for archive member name
1094                 i := strings.LastIndex(file, "/") + 1
1095                 j := strings.LastIndex(file, `\`) + 1
1096                 if i < j {
1097                         i = j
1098                 }
1099                 fmt.Fprintf(bdst, "%-16.16s%-12d%-6d%-6d%-8o%-10d`\n", file[i:], 0, 0, 0, 0644, len(b))
1100                 bdst.WriteString(b)
1101                 if len(b)&1 != 0 {
1102                         bdst.WriteByte(0)
1103                 }
1104         }
1105         writefile(bdst.String(), dst, 0)
1106 }
1107
1108 // buildorder records the order of builds for the 'go bootstrap' command.
1109 // The Go packages and commands must be in dependency order,
1110 // maintained by hand, but the order doesn't change often.
1111 var buildorder = []string{
1112         // Legacy C programs.
1113         "lib9",
1114         "libbio",
1115         "liblink",
1116
1117         "cmd/gc",  // must be before g
1118         "cmd/ld",  // must be before l
1119         "cmd/%sl", // must be before a, g
1120         "cmd/%sa",
1121         "cmd/%sg",
1122
1123         // Go libraries and programs for bootstrap.
1124         "runtime",
1125         "errors",
1126         "sync/atomic",
1127         "sync",
1128         "io",
1129         "unicode",
1130         "unicode/utf8",
1131         "unicode/utf16",
1132         "bytes",
1133         "math",
1134         "strings",
1135         "strconv",
1136         "bufio",
1137         "sort",
1138         "container/heap",
1139         "encoding/base64",
1140         "syscall",
1141         "time",
1142         "os",
1143         "reflect",
1144         "fmt",
1145         "encoding",
1146         "encoding/binary",
1147         "encoding/json",
1148         "flag",
1149         "path/filepath",
1150         "path",
1151         "io/ioutil",
1152         "log",
1153         "regexp/syntax",
1154         "regexp",
1155         "go/token",
1156         "go/scanner",
1157         "go/ast",
1158         "go/parser",
1159         "os/exec",
1160         "os/signal",
1161         "net/url",
1162         "text/template/parse",
1163         "text/template",
1164         "go/doc",
1165         "go/build",
1166         "cmd/internal/obj",
1167         "cmd/internal/obj/arm",
1168         "cmd/internal/obj/i386",
1169         "cmd/internal/obj/ppc64",
1170         "cmd/internal/obj/x86",
1171         "cmd/objwriter",
1172         "cmd/go",
1173 }
1174
1175 // cleantab records the directories to clean in 'go clean'.
1176 // It is bigger than the buildorder because we clean all the
1177 // compilers but build only the $GOARCH ones.
1178 var cleantab = []string{
1179         // Commands and C libraries.
1180         "cmd/5a",
1181         "cmd/5g",
1182         "cmd/5l",
1183         "cmd/6a",
1184         "cmd/6g",
1185         "cmd/6l",
1186         "cmd/8a",
1187         "cmd/8g",
1188         "cmd/8l",
1189         "cmd/9a",
1190         "cmd/9g",
1191         "cmd/9l",
1192         "cmd/gc",
1193         "cmd/go",
1194         "lib9",
1195         "libbio",
1196         "liblink",
1197
1198         // Go packages.
1199         "bufio",
1200         "bytes",
1201         "container/heap",
1202         "encoding",
1203         "encoding/base64",
1204         "encoding/json",
1205         "errors",
1206         "flag",
1207         "fmt",
1208         "go/ast",
1209         "go/build",
1210         "go/doc",
1211         "go/parser",
1212         "go/scanner",
1213         "go/token",
1214         "io",
1215         "io/ioutil",
1216         "log",
1217         "math",
1218         "net/url",
1219         "os",
1220         "os/exec",
1221         "path",
1222         "path/filepath",
1223         "reflect",
1224         "regexp",
1225         "regexp/syntax",
1226         "runtime",
1227         "sort",
1228         "strconv",
1229         "strings",
1230         "sync",
1231         "sync/atomic",
1232         "syscall",
1233         "text/template",
1234         "text/template/parse",
1235         "time",
1236         "unicode",
1237         "unicode/utf16",
1238         "unicode/utf8",
1239 }
1240
1241 var runtimegen = []string{
1242         "zaexperiment.h",
1243         "zversion.go",
1244 }
1245
1246 func clean() {
1247         for _, name := range cleantab {
1248                 path := pathf("%s/src/%s", goroot, name)
1249                 // Remove generated files.
1250                 for _, elem := range xreaddir(path) {
1251                         for _, gt := range gentab {
1252                                 if strings.HasPrefix(elem, gt.nameprefix) {
1253                                         xremove(pathf("%s/%s", path, elem))
1254                                 }
1255                         }
1256                 }
1257                 // Remove generated binary named for directory.
1258                 if strings.HasPrefix(name, "cmd/") {
1259                         xremove(pathf("%s/%s", path, name[4:]))
1260                 }
1261         }
1262
1263         // remove runtimegen files.
1264         path := pathf("%s/src/runtime", goroot)
1265         for _, elem := range runtimegen {
1266                 xremove(pathf("%s/%s", path, elem))
1267         }
1268
1269         if rebuildall {
1270                 // Remove object tree.
1271                 xremoveall(pathf("%s/pkg/obj/%s_%s", goroot, gohostos, gohostarch))
1272
1273                 // Remove installed packages and tools.
1274                 xremoveall(pathf("%s/pkg/%s_%s", goroot, gohostos, gohostarch))
1275                 xremoveall(pathf("%s/pkg/%s_%s", goroot, goos, goarch))
1276                 xremoveall(tooldir)
1277
1278                 // Remove cached version info.
1279                 xremove(pathf("%s/VERSION.cache", goroot))
1280         }
1281 }
1282
1283 /*
1284  * command implementations
1285  */
1286
1287 func usage() {
1288         xprintf("usage: go tool dist [command]\n" +
1289                 "Commands are:\n" +
1290                 "\n" +
1291                 "banner         print installation banner\n" +
1292                 "bootstrap      rebuild everything\n" +
1293                 "clean          deletes all built files\n" +
1294                 "env [-p]       print environment (-p: include $PATH)\n" +
1295                 "install [dir]  install individual directory\n" +
1296                 "version        print Go version\n" +
1297                 "\n" +
1298                 "All commands take -v flags to emit extra information.\n",
1299         )
1300         xexit(2)
1301 }
1302
1303 // The env command prints the default environment.
1304 func cmdenv() {
1305         path := flag.Bool("p", false, "emit updated PATH")
1306         plan9 := flag.Bool("9", false, "emit plan 9 syntax")
1307         windows := flag.Bool("w", false, "emit windows syntax")
1308         xflagparse(0)
1309
1310         format := "%s=\"%s\"\n"
1311         switch {
1312         case *plan9:
1313                 format = "%s='%s'\n"
1314         case *windows:
1315                 format = "set %s=%s\r\n"
1316         }
1317
1318         xprintf(format, "CC", defaultcc)
1319         xprintf(format, "CC_FOR_TARGET", defaultcctarget)
1320         xprintf(format, "GOROOT", goroot)
1321         xprintf(format, "GOBIN", gobin)
1322         xprintf(format, "GOARCH", goarch)
1323         xprintf(format, "GOOS", goos)
1324         xprintf(format, "GOHOSTARCH", gohostarch)
1325         xprintf(format, "GOHOSTOS", gohostos)
1326         xprintf(format, "GOTOOLDIR", tooldir)
1327         xprintf(format, "GOCHAR", gochar)
1328         if goarch == "arm" {
1329                 xprintf(format, "GOARM", goarm)
1330         }
1331         if goarch == "386" {
1332                 xprintf(format, "GO386", go386)
1333         }
1334
1335         if *path {
1336                 sep := ":"
1337                 if gohostos == "windows" {
1338                         sep = ";"
1339                 }
1340                 xprintf(format, "PATH", fmt.Sprintf("%s%s%s", gobin, sep, os.Getenv("PATH")))
1341         }
1342 }
1343
1344 // The bootstrap command runs a build from scratch,
1345 // stopping at having installed the go_bootstrap command.
1346 func cmdbootstrap() {
1347         flag.BoolVar(&rebuildall, "a", rebuildall, "rebuild all")
1348         flag.BoolVar(&sflag, "s", sflag, "build static binaries")
1349         xflagparse(0)
1350
1351         if isdir(pathf("%s/src/pkg", goroot)) {
1352                 fatal("\n\n"+
1353                         "The Go package sources have moved to $GOROOT/src.\n"+
1354                         "*** %s still exists. ***\n"+
1355                         "It probably contains stale files that may confuse the build.\n"+
1356                         "Please (check what's there and) remove it and try again.\n"+
1357                         "See http://golang.org/s/go14nopkg\n",
1358                         pathf("%s/src/pkg", goroot))
1359         }
1360
1361         if rebuildall {
1362                 clean()
1363         }
1364
1365         setup()
1366
1367         bootstrapBuildTools()
1368
1369         // For the main bootstrap, building for host os/arch.
1370         oldgoos = goos
1371         oldgoarch = goarch
1372         oldgochar = gochar
1373         goos = gohostos
1374         goarch = gohostarch
1375         gochar = gohostchar
1376         os.Setenv("GOHOSTARCH", gohostarch)
1377         os.Setenv("GOHOSTOS", gohostos)
1378         os.Setenv("GOARCH", goarch)
1379         os.Setenv("GOOS", goos)
1380
1381         // TODO(rsc): Enable when appropriate.
1382         // This step is only needed if we believe that the Go compiler built from Go 1.4
1383         // will produce different object files than the Go compiler built from itself.
1384         // In the absence of bugs, that should not happen.
1385         // And if there are bugs, they're more likely in the current development tree
1386         // than in a standard release like Go 1.4, so don't do this rebuild by default.
1387         if false {
1388                 xprintf("##### Building Go toolchain using itself.\n")
1389                 for _, pattern := range buildorder {
1390                         if pattern == "cmd/go" {
1391                                 break
1392                         }
1393                         dir := pattern
1394                         if strings.Contains(pattern, "%s") {
1395                                 dir = fmt.Sprintf(pattern, gohostchar)
1396                         }
1397                         install(dir)
1398                         if oldgochar != gohostchar && strings.Contains(pattern, "%s") {
1399                                 install(fmt.Sprintf(pattern, oldgochar))
1400                         }
1401                 }
1402                 xprintf("\n")
1403         }
1404
1405         xprintf("##### Building compilers and go_bootstrap for host, %s/%s.\n", gohostos, gohostarch)
1406         for _, pattern := range buildorder {
1407                 dir := pattern
1408                 if strings.Contains(pattern, "%s") {
1409                         dir = fmt.Sprintf(pattern, gohostchar)
1410                 }
1411                 install(dir)
1412                 if oldgochar != gohostchar && strings.Contains(pattern, "%s") {
1413                         install(fmt.Sprintf(pattern, oldgochar))
1414                 }
1415         }
1416
1417         goos = oldgoos
1418         goarch = oldgoarch
1419         gochar = oldgochar
1420         os.Setenv("GOARCH", goarch)
1421         os.Setenv("GOOS", goos)
1422
1423         // Build runtime for actual goos/goarch too.
1424         if goos != gohostos || goarch != gohostarch {
1425                 install("runtime")
1426         }
1427 }
1428
1429 func defaulttarg() string {
1430         // xgetwd might return a path with symlinks fully resolved, and if
1431         // there happens to be symlinks in goroot, then the hasprefix test
1432         // will never succeed. Instead, we use xrealwd to get a canonical
1433         // goroot/src before the comparison to avoid this problem.
1434         pwd := xgetwd()
1435         src := pathf("%s/src/", goroot)
1436         real_src := xrealwd(src)
1437         if !strings.HasPrefix(pwd, real_src) {
1438                 fatal("current directory %s is not under %s", pwd, real_src)
1439         }
1440         pwd = pwd[len(real_src):]
1441         // guard againt xrealwd return the directory without the trailing /
1442         pwd = strings.TrimPrefix(pwd, "/")
1443
1444         return pwd
1445 }
1446
1447 // Install installs the list of packages named on the command line.
1448 func cmdinstall() {
1449         flag.BoolVar(&sflag, "s", sflag, "build static binaries")
1450         xflagparse(-1)
1451
1452         if flag.NArg() == 0 {
1453                 install(defaulttarg())
1454         }
1455
1456         for _, arg := range flag.Args() {
1457                 install(arg)
1458         }
1459 }
1460
1461 // Clean deletes temporary objects.
1462 func cmdclean() {
1463         xflagparse(0)
1464         clean()
1465 }
1466
1467 // Banner prints the 'now you've installed Go' banner.
1468 func cmdbanner() {
1469         xflagparse(0)
1470
1471         xprintf("\n")
1472         xprintf("---\n")
1473         xprintf("Installed Go for %s/%s in %s\n", goos, goarch, goroot)
1474         xprintf("Installed commands in %s\n", gobin)
1475
1476         if !xsamefile(goroot_final, goroot) {
1477                 // If the files are to be moved, don't check that gobin
1478                 // is on PATH; assume they know what they are doing.
1479         } else if gohostos == "plan9" {
1480                 // Check that gobin is bound before /bin.
1481                 pid := strings.Replace(readfile("#c/pid"), " ", "", -1)
1482                 ns := fmt.Sprintf("/proc/%s/ns", pid)
1483                 if !strings.Contains(readfile(ns), fmt.Sprintf("bind -b %s /bin", gobin)) {
1484                         xprintf("*** You need to bind %s before /bin.\n", gobin)
1485                 }
1486         } else {
1487                 // Check that gobin appears in $PATH.
1488                 pathsep := ":"
1489                 if gohostos == "windows" {
1490                         pathsep = ";"
1491                 }
1492                 if !strings.Contains(pathsep+os.Getenv("PATH")+pathsep, pathsep+gobin+pathsep) {
1493                         xprintf("*** You need to add %s to your PATH.\n", gobin)
1494                 }
1495         }
1496
1497         if !xsamefile(goroot_final, goroot) {
1498                 xprintf("\n"+
1499                         "The binaries expect %s to be copied or moved to %s\n",
1500                         goroot, goroot_final)
1501         }
1502 }
1503
1504 // Version prints the Go version.
1505 func cmdversion() {
1506         xflagparse(0)
1507         xprintf("%s\n", findgoversion())
1508 }