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