]> Cypherpunks.ru repositories - gostls13.git/commitdiff
[dev.cc] all: merge master (d1210ac) into dev.cc
authorRuss Cox <rsc@golang.org>
Thu, 15 Jan 2015 00:39:34 +0000 (19:39 -0500)
committerRuss Cox <rsc@golang.org>
Thu, 15 Jan 2015 00:40:28 +0000 (19:40 -0500)
Change-Id: I068d617175776c2f5df00b17ff0d404a584ab570

30 files changed:
src/cmd/dist/README
src/cmd/dist/a.h [deleted file]
src/cmd/dist/arg.h [deleted file]
src/cmd/dist/arm.c [deleted file]
src/cmd/dist/buf.c [deleted file]
src/cmd/dist/build.c [deleted file]
src/cmd/dist/build.go [new file with mode: 0644]
src/cmd/dist/buildgc.c [deleted file]
src/cmd/dist/buildgc.go [new file with mode: 0644]
src/cmd/dist/buildgo.c [deleted file]
src/cmd/dist/buildgo.go [new file with mode: 0644]
src/cmd/dist/buildruntime.c [deleted file]
src/cmd/dist/buildruntime.go [new file with mode: 0644]
src/cmd/dist/cpuid_386.s [new file with mode: 0644]
src/cmd/dist/cpuid_amd64.s [new file with mode: 0644]
src/cmd/dist/cpuid_default.s [new file with mode: 0644]
src/cmd/dist/main.c [deleted file]
src/cmd/dist/main.go [new file with mode: 0644]
src/cmd/dist/plan9.c [deleted file]
src/cmd/dist/sys_default.go [new file with mode: 0644]
src/cmd/dist/sys_windows.go [new file with mode: 0644]
src/cmd/dist/unix.c [deleted file]
src/cmd/dist/util.go [new file with mode: 0644]
src/cmd/dist/vfp_arm.s [new file with mode: 0644]
src/cmd/dist/vfp_default.s [new file with mode: 0644]
src/cmd/dist/windows.c [deleted file]
src/make.bash
src/make.bat
src/make.rc
src/sudo.bash [deleted file]

index e6d08cf0284be3c75c9856755e66bf8fe1233be8..0649e887f45a4e162bef8e8279cc4b1ffaba5b5e 100644 (file)
@@ -1,45 +1,27 @@
 This program, dist, is the bootstrapping tool for the Go distribution.
-It takes care of building the C programs (like the Go compiler) and
-the initial bootstrap copy of the go tool.  It also serves as a catch-all
-to replace odd jobs previously done with shell scripts.
 
-Dist is itself written in very simple C.  All interaction with C libraries,
-even standard C libraries, is confined to a single system-specific file
-(plan9.c, unix.c, windows.c), to aid portability.  Functionality needed
-by other files should be exposed via the portability layer.  Functions
-in the portability layer begin with an x prefix when they would otherwise
-use the same name as or be confused for an existing function.
-For example, xprintf is the portable printf.
+As of Go 1.5, dist and other parts of the compiler toolchain are written
+in Go, making bootstrapping a little more involved than in the past.
+The approach is to build the current release of Go with an earlier one.
 
-By far the most common data types in dist are strings and arrays of
-strings.  Instead of using char* and char**, though, dist uses two named
-data structures, Buf and Vec, which own all the data they point at.
-The Buf operations are functions beginning with b; the Vec operations
-are functions beginning with v.  The basic form of any function declaring
-Bufs or Vecs on the stack should be
+The process to install Go 1.x, for x ≥ 5, is:
 
-       void
-       myfunc(void)
-       {
-               Buf b1, b2;
-               Vec v1;
-               
-               binit(&b1);
-               binit(&b2);
-               vinit(&v1);
-               
-               ... main code ...
-               bprintf(&b1, "hello, world");
-               vadd(&v1, bstr(&b1));  // v1 takes a copy of its argument
-               bprintf(&b2, "another string");
-               vadd(&v1, bstr(&b2));  // v1 now has two strings
-               
-               bfree(&b1);
-               bfree(&b2);
-               vfree(&v1);
-       }
-       
-The binit/vinit calls prepare a buffer or vector for use, initializing the 
-data structures, and the bfree/vfree calls free any memory they are still
-holding onto.  Use of this idiom gives us lexically scoped allocations.
+1. Build cmd/dist with Go 1.4.
+2. Using dist, build Go 1.x compiler toolchain with Go 1.4.
+3. Using dist, rebuild Go 1.x compiler toolchain with itself.
+4. Using dist, build Go 1.x cmd/go (as go_bootstrap) with Go 1.x compiler toolchain.
+5. Using go_bootstrap, build the remaining Go 1.x standard library and commands.
 
+NOTE: During the transition from the old C-based toolchain to the Go-based one,
+step 2 also builds the parts of the toolchain written in C, and step 3 does not
+recompile those.
+
+Because of backward compatibility, although the steps above say Go 1.4,
+in practice any release ≥ Go 1.4 but < Go 1.x will work as the bootstrap base.
+
+See golang.org/s/go15bootstrap for more details.
+
+Compared to Go 1.4 and earlier, dist will also take over much of what used to
+be done by make.bash/make.bat/make.rc and all of what used to be done by
+run.bash/run.bat/run.rc, because it is nicer to implement that logic in Go
+than in three different scripting languages simultaneously.
diff --git a/src/cmd/dist/a.h b/src/cmd/dist/a.h
deleted file mode 100644 (file)
index 288063b..0000000
+++ /dev/null
@@ -1,165 +0,0 @@
-// Copyright 2012 The Go Authors.  All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-typedef int bool;
-
-// The Time unit is unspecified; we just need to
-// be able to compare whether t1 is older than t2 with t1 < t2.
-typedef long long Time;
-
-#define nil ((void*)0)
-#define nelem(x) (sizeof(x)/sizeof((x)[0]))
-#ifndef PLAN9
-#define USED(x) ((void)(x))
-#endif
-
-// A Buf is a byte buffer, like Go's []byte.
-typedef struct Buf Buf;
-struct Buf
-{
-       char *p;
-       int len;
-       int cap;
-};
-
-// A Vec is a string vector, like Go's []string.
-typedef struct Vec Vec;
-struct Vec
-{
-       char **p;
-       int len;
-       int cap;
-};
-
-// Modes for run.
-enum {
-       CheckExit = 1,
-};
-
-// buf.c
-bool   bequal(Buf *s, Buf *t);
-void   bsubst(Buf *b, char *x, char *y);
-void   bfree(Buf *b);
-void   bgrow(Buf *b, int n);
-void   binit(Buf *b);
-char*  bpathf(Buf *b, char *fmt, ...);
-char*  bprintf(Buf *b, char *fmt, ...);
-void   bwritef(Buf *b, char *fmt, ...);
-void   breset(Buf *b);
-char*  bstr(Buf *b);
-char*  btake(Buf *b);
-void   bwrite(Buf *b, void *v, int n);
-void   bwriteb(Buf *dst, Buf *src);
-void   bwritestr(Buf *b, char *p);
-void   bswap(Buf *b, Buf *b1);
-void   vadd(Vec *v, char *p);
-void   vcopy(Vec *dst, char **src, int n);
-void   vfree(Vec *v);
-void   vgrow(Vec *v, int n);
-void   vinit(Vec *v);
-void   vreset(Vec *v);
-void   vuniq(Vec *v);
-void   splitlines(Vec*, char*);
-void   splitfields(Vec*, char*);
-
-// build.c
-extern char *goarch;
-extern char *gobin;
-extern char *gochar;
-extern char *gohostarch;
-extern char *gohostos;
-extern char *goos;
-extern char *goroot;
-extern char *goroot_final;
-extern char *goextlinkenabled;
-extern char *goversion;
-extern char *defaultcc;
-extern char *defaultcxxtarget;
-extern char *defaultcctarget;
-extern char *workdir;
-extern char *tooldir;
-extern char *slash;
-extern bool rebuildall;
-extern bool defaultclang;
-
-int    find(char*, char**, int);
-void   init(void);
-void   cmdbanner(int, char**);
-void   cmdbootstrap(int, char**);
-void   cmdclean(int, char**);
-void   cmdenv(int, char**);
-void   cmdinstall(int, char**);
-void   cmdversion(int, char**);
-
-// buildgc.c
-void   gcopnames(char*, char*);
-void   mkanames(char*, char*);
-
-// buildruntime.c
-void   mkzasm(char*, char*);
-void   mkzsys(char*, char*);
-void   mkzgoarch(char*, char*);
-void   mkzgoos(char*, char*);
-void   mkzruntimedefs(char*, char*);
-void   mkzversion(char*, char*);
-void   mkzexperiment(char*, char*);
-
-// buildgo.c
-void   mkzdefaultcc(char*, char*);
-
-// main.c
-extern int vflag;
-extern int sflag;
-void   usage(void);
-void   xmain(int argc, char **argv);
-
-// portability layer (plan9.c, unix.c, windows.c)
-bool   contains(char *p, char *sep);
-void   errprintf(char*, ...);
-void   fatal(char *msg, ...);
-bool   hasprefix(char *p, char *prefix);
-bool   hassuffix(char *p, char *suffix);
-bool   isabs(char*);
-bool   isdir(char *p);
-bool   isfile(char *p);
-char*  lastelem(char*);
-Time   mtime(char*);
-void   readfile(Buf*, char*);
-void   copyfile(char*, char*, int);
-void   run(Buf *b, char *dir, int mode, char *cmd, ...);
-void   runv(Buf *b, char *dir, int mode, Vec *argv);
-void   bgrunv(char *dir, int mode, Vec *argv);
-void   bgwait(void);
-bool   streq(char*, char*);
-bool   cansse2(void);
-void   writefile(Buf*, char*, int);
-void   xatexit(void (*f)(void));
-void   xexit(int);
-void   xfree(void*);
-void   xgetenv(Buf *b, char *name);
-void   xgetwd(Buf *b);
-void*  xmalloc(int n);
-void*  xmalloc(int);
-int    xmemcmp(void*, void*, int);
-void   xmemmove(void*, void*, int);
-void   xmkdir(char *p);
-void   xmkdirall(char*);
-Time   xmtime(char *p);
-void   xprintf(char*, ...);
-void   xqsort(void*, int, int, int(*)(const void*, const void*));
-void   xreaddir(Vec *dst, char *dir);
-void*  xrealloc(void*, int);
-void   xrealwd(Buf *b, char *path);
-void   xremove(char *p);
-void   xremoveall(char *p);
-void   xsetenv(char*, char*);
-int    xstrcmp(char*, char*);
-char*  xstrdup(char *p);
-int    xstrlen(char*);
-char*  xstrrchr(char*, int);
-char*  xstrstr(char*, char*);
-char*  xworkdir(void);
-int    xsamefile(char*, char*);
-char*  xgetgoarm(void);
-int    xtryexecfunc(void (*)(void));
diff --git a/src/cmd/dist/arg.h b/src/cmd/dist/arg.h
deleted file mode 100644 (file)
index 9819765..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
-Derived from Inferno include/kern.h.
-
-http://code.google.com/p/inferno-os/source/browse/include/kern.h
-
-       Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
-       Revisions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com).  All rights reserved.
-       Portions Copyright © 2009 The Go Authors.  All rights reserved.
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in
-all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-THE SOFTWARE.
-*/
-
-/* command line */
-extern char    *argv0;
-#define        ARGBEGIN        for((argv0=(argv0?argv0:*argv)),argv++,argc--;\
-                           argv[0] && argv[0][0]=='-' && argv[0][1];\
-                           argc--, argv++) {\
-                               char *_args, *_argt;\
-                               char _argc;\
-                               _args = &argv[0][1];\
-                               if(_args[0]=='-' && _args[1]==0){\
-                                       argc--; argv++; break;\
-                               }\
-                               while((_argc = *_args++) != 0)\
-                               switch(_argc)
-#define        ARGEND          _argt=0;USED(_argt);USED(_argc);USED(_args);}USED(argv);USED(argc);
-#define        ARGF()          (_argt=_args, _args="",\
-                               (*_argt? _argt: argv[1]? (argc--, *++argv): 0))
-#define        EARGF(x)        (_argt=_args, _args="",\
-                               (*_argt? _argt: argv[1]? (argc--, *++argv): ((x), fatal("usage"), (char*)0)))
-
-#define        ARGC()          _argc
-
diff --git a/src/cmd/dist/arm.c b/src/cmd/dist/arm.c
deleted file mode 100644 (file)
index 1ce7b77..0000000
+++ /dev/null
@@ -1,72 +0,0 @@
-// Copyright 2012 The Go Authors.  All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-#include "a.h"
-
-#ifndef __ARMEL__
-char *
-xgetgoarm(void)
-{
-       return "6";
-}
-#else
-static void useVFPv3(void);
-static void useVFPv1(void);
-
-char *
-xgetgoarm(void)
-{
-#if defined(__FreeBSD__)
-       // FreeBSD has broken VFP support
-       return "5";
-#endif
-       // NaCl always has VFP support.
-       if(streq(goos, "nacl") || xtryexecfunc(useVFPv3))
-               return "7";
-       else if(xtryexecfunc(useVFPv1))
-               return "6";
-       return "5";
-}
-
-static void
-useVFPv3(void)
-{
-       // try to run VFPv3-only "vmov.f64 d0, #112" instruction
-       // we can't use that instruction directly, because we
-       // might be compiling with a soft-float only toolchain.
-       //
-       // some newer toolchains are configured to use thumb
-       // by default, so we need to do some mode changing magic
-       // here.
-       // We can use "bx pc; nop" here, but GNU as(1) insists
-       // on warning us
-       // "use of r15 in bx in ARM mode is not really useful"
-       // so we workaround that by using "bx r0"
-       __asm__ __volatile__ ("mov r0, pc");
-       __asm__ __volatile__ ("bx r0");
-       __asm__ __volatile__ (".word 0xeeb70b00"); // vmov.f64 d0, #112
-       __asm__ __volatile__ (".word 0xe12fff1e"); // bx lr
-}
-
-static void
-useVFPv1(void)
-{
-       // try to run "vmov.f64 d0, d0" instruction
-       // we can't use that instruction directly, because we
-       // might be compiling with a soft-float only toolchain
-       //
-       // some newer toolchains are configured to use thumb
-       // by default, so we need to do some mode changing magic
-       // here.
-       // We can use "bx pc; nop" here, but GNU as(1) insists
-       // on warning us
-       // "use of r15 in bx in ARM mode is not really useful"
-       // so we workaround that by using "bx r0"
-       __asm__ __volatile__ ("mov r0, pc");
-       __asm__ __volatile__ ("bx r0");
-       __asm__ __volatile__ (".word 0xeeb00b40"); // vomv.f64 d0, d0
-       __asm__ __volatile__ (".word 0xe12fff1e"); // bx lr
-}
-
-#endif
diff --git a/src/cmd/dist/buf.c b/src/cmd/dist/buf.c
deleted file mode 100644 (file)
index fbecd56..0000000
+++ /dev/null
@@ -1,284 +0,0 @@
-// Copyright 2012 The Go Authors.  All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// Byte buffers and string vectors.
-
-#include "a.h"
-
-// binit prepares an uninitialized buffer for use.
-void
-binit(Buf *b)
-{
-       b->p = nil;
-       b->len = 0;
-       b->cap = 0;
-}
-
-// breset truncates the buffer back to zero length.
-void
-breset(Buf *b)
-{
-       b->len = 0;
-}
-
-// bfree frees the storage associated with a buffer.
-void
-bfree(Buf *b)
-{
-       xfree(b->p);
-       binit(b);
-}
-
-// bgrow ensures that the buffer has at least n more bytes
-// between its len and cap.
-void
-bgrow(Buf *b, int n)
-{
-       int want;
-       
-       want = b->len+n;
-       if(want > b->cap) {
-               b->cap = 2*want;
-               if(b->cap < 64)
-                       b->cap = 64;
-               b->p = xrealloc(b->p, b->cap);
-       }
-}
-
-// bwrite appends the n bytes at v to the buffer.
-void
-bwrite(Buf *b, void *v, int n)
-{
-       bgrow(b, n);
-       xmemmove(b->p+b->len, v, n);
-       b->len += n;
-}
-
-// bwritestr appends the string p to the buffer.
-void
-bwritestr(Buf *b, char *p)
-{
-       bwrite(b, p, xstrlen(p));
-}
-
-// bstr returns a pointer to a NUL-terminated string of the
-// buffer contents.  The pointer points into the buffer.
-char*
-bstr(Buf *b)
-{
-       bgrow(b, 1);
-       b->p[b->len] = '\0';
-       return b->p;
-}
-
-// btake takes ownership of the string form of the buffer.
-// After this call, the buffer has zero length and does not
-// refer to the memory that btake returned.
-char*
-btake(Buf *b)
-{
-       char *p;
-       
-       p = bstr(b);
-       binit(b);
-       return p;
-}
-
-// bwriteb appends the src buffer to the dst buffer.
-void
-bwriteb(Buf *dst, Buf *src)
-{
-       bwrite(dst, src->p, src->len);
-}
-
-// bequal reports whether the buffers have the same content.
-bool
-bequal(Buf *s, Buf *t)
-{
-       return s->len == t->len && xmemcmp(s->p, t->p, s->len) == 0;
-}
-
-// bsubst rewites b to replace all occurrences of x with y.
-void
-bsubst(Buf *b, char *x, char *y)
-{
-       char *p;
-       int nx, ny, pos;
-
-       nx = xstrlen(x);
-       ny = xstrlen(y);
-
-       pos = 0;
-       for(;;) {
-               p = xstrstr(bstr(b)+pos, x);
-               if(p == nil)
-                       break;
-               if(nx != ny) {
-                       if(nx < ny) {
-                               pos = p - b->p;
-                               bgrow(b, ny-nx);
-                               p = b->p + pos;
-                       }
-                       xmemmove(p+ny, p+nx, (b->p+b->len)-(p+nx));
-               }
-               xmemmove(p, y, ny);
-               pos = p+ny - b->p;
-               b->len += ny - nx;
-       }
-}
-
-// The invariant with the vectors is that v->p[0:v->len] is allocated
-// strings that are owned by the vector.  The data beyond v->len may
-// be garbage.
-
-// vinit prepares an uninitialized vector for use.
-void
-vinit(Vec *v)
-{
-       v->p = nil;
-       v->len = 0;
-       v->cap = 0;
-}
-
-// vreset truncates the vector back to zero length.
-void
-vreset(Vec *v)
-{
-       int i;
-       
-       for(i=0; i<v->len; i++) {
-               xfree(v->p[i]);
-               v->p[i] = nil;
-       }
-       v->len = 0;
-}
-
-// vfree frees the storage associated with the vector.
-void
-vfree(Vec *v)
-{
-       vreset(v);
-       xfree(v->p);
-       vinit(v);
-}
-
-
-// vgrow ensures that the vector has room for at least 
-// n more entries between len and cap.
-void
-vgrow(Vec *v, int n)
-{
-       int want;
-       
-       want = v->len+n;
-       if(want > v->cap) {
-               v->cap = 2*want;
-               if(v->cap < 64)
-                       v->cap = 64;
-               v->p = xrealloc(v->p, v->cap*sizeof v->p[0]);
-       }
-}
-
-// vcopy copies the srclen strings at src into the vector.
-void
-vcopy(Vec *dst, char **src, int srclen)
-{
-       int i;
-       
-       // use vadd, to make copies of strings
-       for(i=0; i<srclen; i++)
-               vadd(dst, src[i]);
-}
-
-// vadd adds a copy of the string p to the vector.
-void
-vadd(Vec *v, char *p)
-{
-       vgrow(v, 1);
-       if(p != nil)
-               p = xstrdup(p);
-       v->p[v->len++] = p;
-}
-
-// vaddn adds a string consisting of the n bytes at p to the vector.
-static void
-vaddn(Vec *v, char *p, int n)
-{
-       char *q;
-
-       vgrow(v, 1);
-       q = xmalloc(n+1);
-       xmemmove(q, p, n);
-       q[n] = '\0';
-       v->p[v->len++] = q;
-}
-
-static int
-strpcmp(const void *a, const void *b)
-{
-       return xstrcmp(*(char**)a, *(char**)b);
-}
-
-// vuniq sorts the vector and then discards duplicates,
-// in the manner of sort | uniq.
-void
-vuniq(Vec *v)
-{
-       int i, n;
-
-       xqsort(v->p, v->len, sizeof(v->p[0]), strpcmp);
-       n = 0;
-       for(i=0; i<v->len; i++) {
-               if(n>0 && streq(v->p[i], v->p[n-1]))
-                       xfree(v->p[i]);
-               else
-                       v->p[n++] = v->p[i];
-       }
-       v->len = n;
-}
-
-// splitlines replaces the vector v with the result of splitting
-// the input p after each \n. If there is a \r immediately before
-// each \n, it will be removed.
-void
-splitlines(Vec *v, char *p)
-{
-       int i;
-       char *start;
-       
-       vreset(v);
-       start = p;
-       for(i=0; p[i]; i++) {
-               if((p[i] == '\r' && p[i+1] == '\n') || p[i] == '\n') {
-                       vaddn(v, start, (p+i+1)-start);
-                       if(p[i] == '\r') {
-                               v->p[v->len-1][(p+i)-start] = '\n';
-                               i++;
-                       }
-                       start = p+i+1;
-               }
-       }
-       if(*start != '\0')
-               vadd(v, start);
-}
-
-// splitfields replaces the vector v with the result of splitting
-// the input p into non-empty fields containing no spaces.
-void
-splitfields(Vec *v, char *p)
-{
-       char *start;
-
-       vreset(v);
-       for(;;) {
-               while(*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n')
-                       p++;
-               if(*p == '\0')
-                       break;
-               start = p;
-               while(*p != ' ' && *p != '\t' && *p != '\r' && *p != '\n' && *p != '\0')
-                       p++;
-               vaddn(v, start, p-start);
-       }
-}
diff --git a/src/cmd/dist/build.c b/src/cmd/dist/build.c
deleted file mode 100644 (file)
index e4b8b58..0000000
+++ /dev/null
@@ -1,1785 +0,0 @@
-// Copyright 2012 The Go Authors.  All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-#include "a.h"
-#include "arg.h"
-
-/*
- * Initialization for any invocation.
- */
-
-// The usual variables.
-char *goarch;
-char *gobin;
-char *gohostarch;
-char *gohostchar;
-char *gohostos;
-char *goos;
-char *goarm;
-char *go386;
-char *goroot = GOROOT_FINAL;
-char *goroot_final = GOROOT_FINAL;
-char *goextlinkenabled = "";
-char *workdir;
-char *tooldir;
-char *gochar;
-char *goversion;
-char *slash;   // / for unix, \ for windows
-char *defaultcc;
-char *defaultcflags;
-char *defaultldflags;
-char *defaultcxxtarget;
-char *defaultcctarget;
-bool   rebuildall;
-bool defaultclang;
-
-static bool shouldbuild(char*, char*);
-static void dopack(char*, char*, char**, int);
-static char *findgoversion(void);
-
-// The known architecture letters.
-static char *gochars = "566899";
-
-// The known architectures.
-static char *okgoarch[] = {
-       // same order as gochars
-       "arm",
-       "amd64",
-       "amd64p32",
-       "386",
-       "ppc64",
-       "ppc64le",
-};
-
-// The known operating systems.
-static char *okgoos[] = {
-       "darwin",
-       "dragonfly",
-       "linux",
-       "android",
-       "solaris",
-       "freebsd",
-       "nacl",
-       "netbsd",
-       "openbsd",
-       "plan9",
-       "windows",
-};
-
-static void rmworkdir(void);
-
-// find reports the first index of p in l[0:n], or else -1.
-int
-find(char *p, char **l, int n)
-{
-       int i;
-
-       for(i=0; i<n; i++)
-               if(streq(p, l[i]))
-                       return i;
-       return -1;
-}
-
-// init handles initialization of the various global state, like goroot and goarch.
-void
-init(void)
-{
-       char *p;
-       int i;
-       Buf b;
-
-       binit(&b);
-
-       xgetenv(&b, "GOROOT");
-       if(b.len > 0) {
-               // if not "/", then strip trailing path separator
-               if(b.len >= 2 && b.p[b.len - 1] == slash[0])
-                       b.len--;
-               goroot = btake(&b);
-       }
-
-       xgetenv(&b, "GOBIN");
-       if(b.len == 0)
-               bprintf(&b, "%s%sbin", goroot, slash);
-       gobin = btake(&b);
-
-       xgetenv(&b, "GOOS");
-       if(b.len == 0)
-               bwritestr(&b, gohostos);
-       goos = btake(&b);
-       if(find(goos, okgoos, nelem(okgoos)) < 0)
-               fatal("unknown $GOOS %s", goos);
-
-       xgetenv(&b, "GOARM");
-       if(b.len == 0)
-               bwritestr(&b, xgetgoarm());
-       goarm = btake(&b);
-
-       xgetenv(&b, "GO386");
-       if(b.len == 0) {
-               if(cansse2())
-                       bwritestr(&b, "sse2");
-               else
-                       bwritestr(&b, "387");
-       }
-       go386 = btake(&b);
-
-       p = bpathf(&b, "%s/include/u.h", goroot);
-       if(!isfile(p)) {
-               fatal("$GOROOT is not set correctly or not exported\n"
-                       "\tGOROOT=%s\n"
-                       "\t%s does not exist", goroot, p);
-       }
-
-       xgetenv(&b, "GOHOSTARCH");
-       if(b.len > 0)
-               gohostarch = btake(&b);
-
-       i = find(gohostarch, okgoarch, nelem(okgoarch));
-       if(i < 0)
-               fatal("unknown $GOHOSTARCH %s", gohostarch);
-       bprintf(&b, "%c", gochars[i]);
-       gohostchar = btake(&b);
-
-       xgetenv(&b, "GOARCH");
-       if(b.len == 0)
-               bwritestr(&b, gohostarch);
-       goarch = btake(&b);
-       i = find(goarch, okgoarch, nelem(okgoarch));
-       if(i < 0)
-               fatal("unknown $GOARCH %s", goarch);
-       bprintf(&b, "%c", gochars[i]);
-       gochar = btake(&b);
-
-       xgetenv(&b, "GO_EXTLINK_ENABLED");
-       if(b.len > 0) {
-               goextlinkenabled = btake(&b);
-               if(!streq(goextlinkenabled, "0") && !streq(goextlinkenabled, "1"))
-                       fatal("unknown $GO_EXTLINK_ENABLED %s", goextlinkenabled);
-       }
-       
-       xgetenv(&b, "CC");
-       if(b.len == 0) {
-               // Use clang on OS X, because gcc is deprecated there.
-               // Xcode for OS X 10.9 Mavericks will ship a fake "gcc" binary that
-               // actually runs clang. We prepare different command
-               // lines for the two binaries, so it matters what we call it.
-               // See golang.org/issue/5822.
-               if(defaultclang)
-                       bprintf(&b, "clang");
-               else
-                       bprintf(&b, "gcc");
-       }
-       defaultcc = btake(&b);
-
-       xgetenv(&b, "CFLAGS");
-       defaultcflags = btake(&b);
-
-       xgetenv(&b, "LDFLAGS");
-       defaultldflags = btake(&b);
-
-       xgetenv(&b, "CC_FOR_TARGET");
-       if(b.len == 0) {
-               bprintf(&b, defaultcc);
-       }
-       defaultcctarget = btake(&b);
-
-       xgetenv(&b, "CXX_FOR_TARGET");
-       if(b.len == 0) {
-               xgetenv(&b, "CXX");
-               if(b.len == 0) {
-                       if(defaultclang)
-                               bprintf(&b, "clang++");
-                       else
-                               bprintf(&b, "g++");
-               }
-       }
-       defaultcxxtarget = btake(&b);
-
-       xsetenv("GOROOT", goroot);
-       xsetenv("GOARCH", goarch);
-       xsetenv("GOOS", goos);
-       xsetenv("GOARM", goarm);
-       xsetenv("GO386", go386);
-
-       // Make the environment more predictable.
-       xsetenv("LANG", "C");
-       xsetenv("LANGUAGE", "en_US.UTF8");
-
-       goversion = findgoversion();
-
-       workdir = xworkdir();
-       xatexit(rmworkdir);
-
-       bpathf(&b, "%s/pkg/tool/%s_%s", goroot, gohostos, gohostarch);
-       tooldir = btake(&b);
-
-       bfree(&b);
-}
-
-// rmworkdir deletes the work directory.
-static void
-rmworkdir(void)
-{
-       if(vflag > 1)
-               errprintf("rm -rf %s\n", workdir);
-       xremoveall(workdir);
-}
-
-// Remove trailing spaces.
-static void
-chomp(Buf *b)
-{
-       int c;
-
-       while(b->len > 0 && ((c=b->p[b->len-1]) == ' ' || c == '\t' || c == '\r' || c == '\n'))
-               b->len--;
-}
-
-static char*
-branchtag(char *branch, bool *precise)
-{
-       char *tag, *p, *q;
-       int i;
-       Buf b, arg;
-       Vec tags;
-
-       binit(&b);
-       binit(&arg);
-       vinit(&tags);
-
-       bprintf(&arg, "master..%s", branch);
-       run(&b, goroot, CheckExit, "git", "log", "--decorate=full", "--format=format:%d", bstr(&arg), nil);
-
-       splitlines(&tags, bstr(&b));
-       tag = branch;
-       for(i=0; i < tags.len; i++) {
-               // Each line is either blank, or looks like
-               //        (tag: refs/tags/go1.4rc2, refs/remotes/origin/release-branch.go1.4, refs/heads/release-branch.go1.4)
-               // We need to find an element starting with refs/tags/.
-               p = xstrstr(tags.p[i], " refs/tags/");
-               if(p == nil)
-                       continue;
-               p += xstrlen(" refs/tags/");
-               // The tag name ends at a comma or paren (prefer the first).
-               q = xstrstr(p, ",");
-               if(q == nil)
-                       q = xstrstr(p, ")");
-               if(q == nil)
-                       continue;  // malformed line; ignore it
-               *q = '\0';
-               tag = xstrdup(p);
-               if(i == 0)
-                       *precise = 1;  // tag denotes HEAD
-               break;
-       }
-
-       bfree(&b);
-       bfree(&arg);
-       vfree(&tags);
-       return tag;
-}
-
-// findgoversion determines the Go version to use in the version string.
-static char*
-findgoversion(void)
-{
-       char *tag, *p;
-       bool precise;
-       Buf b, path, bmore, branch;
-
-       binit(&b);
-       binit(&path);
-       binit(&bmore);
-       binit(&branch);
-
-       // The $GOROOT/VERSION file takes priority, for distributions
-       // without the source repo.
-       bpathf(&path, "%s/VERSION", goroot);
-       if(isfile(bstr(&path))) {
-               readfile(&b, bstr(&path));
-               chomp(&b);
-               // Commands such as "dist version > VERSION" will cause
-               // the shell to create an empty VERSION file and set dist's
-               // stdout to its fd. dist in turn looks at VERSION and uses
-               // its content if available, which is empty at this point.
-               if(b.len > 0)
-                       goto done;
-       }
-
-       // The $GOROOT/VERSION.cache file is a cache to avoid invoking
-       // git every time we run this command.  Unlike VERSION, it gets
-       // deleted by the clean command.
-       bpathf(&path, "%s/VERSION.cache", goroot);
-       if(isfile(bstr(&path))) {
-               readfile(&b, bstr(&path));
-               chomp(&b);
-               goto done;
-       }
-
-       // Otherwise, use Git.
-       // What is the current branch?
-       run(&branch, goroot, CheckExit, "git", "rev-parse", "--abbrev-ref", "HEAD", nil);
-       chomp(&branch);
-
-       // What are the tags along the current branch?
-       tag = "devel";
-       precise = 0;
-
-       // If we're on a release branch, use the closest matching tag
-       // that is on the release branch (and not on the master branch).
-       if(hasprefix(bstr(&branch), "release-branch."))
-               tag = branchtag(bstr(&branch), &precise);
-
-       bprintf(&b, "%s", tag);
-       if(!precise) {
-               // Tag does not point at HEAD; add hash and date to version.
-               run(&bmore, goroot, CheckExit, "git", "log", "-n", "1", "--format=format: +%h %cd", "HEAD", nil);
-               chomp(&bmore);
-               bwriteb(&b, &bmore);
-       }
-
-       // Cache version.
-       writefile(&b, bstr(&path), 0);
-
-done:
-       p = btake(&b);
-
-
-       bfree(&b);
-       bfree(&path);
-       bfree(&bmore);
-       bfree(&branch);
-
-       return p;
-}
-
-/*
- * Initial tree setup.
- */
-
-// The old tools that no longer live in $GOBIN or $GOROOT/bin.
-static char *oldtool[] = {
-       "5a", "5c", "5g", "5l",
-       "6a", "6c", "6g", "6l",
-       "8a", "8c", "8g", "8l",
-       "9a", "9c", "9g", "9l",
-       "6cov",
-       "6nm",
-       "6prof",
-       "cgo",
-       "ebnflint",
-       "goapi",
-       "gofix",
-       "goinstall",
-       "gomake",
-       "gopack",
-       "gopprof",
-       "gotest",
-       "gotype",
-       "govet",
-       "goyacc",
-       "quietgcc",
-};
-
-// Unreleased directories (relative to $GOROOT) that should
-// not be in release branches.
-static char *unreleased[] = {
-       "src/cmd/link",
-       "src/debug/goobj",
-       "src/old",
-};
-
-// setup sets up the tree for the initial build.
-static void
-setup(void)
-{
-       int i;
-       Buf b;
-       char *p;
-
-       binit(&b);
-
-       // Create bin directory.
-       p = bpathf(&b, "%s/bin", goroot);
-       if(!isdir(p))
-               xmkdir(p);
-
-       // Create package directory.
-       p = bpathf(&b, "%s/pkg", goroot);
-       if(!isdir(p))
-               xmkdir(p);
-       p = bpathf(&b, "%s/pkg/%s_%s", goroot, gohostos, gohostarch);
-       if(rebuildall)
-               xremoveall(p);
-       xmkdirall(p);
-       if(!streq(goos, gohostos) || !streq(goarch, gohostarch)) {
-               p = bpathf(&b, "%s/pkg/%s_%s", goroot, goos, goarch);
-               if(rebuildall)
-                       xremoveall(p);
-               xmkdirall(p);
-       }
-
-       // Create object directory.
-       // We keep it in pkg/ so that all the generated binaries
-       // are in one tree.  If pkg/obj/libgc.a exists, it is a dreg from
-       // before we used subdirectories of obj.  Delete all of obj
-       // to clean up.
-       bpathf(&b, "%s/pkg/obj/libgc.a", goroot);
-       if(isfile(bstr(&b)))
-               xremoveall(bpathf(&b, "%s/pkg/obj", goroot));
-       p = bpathf(&b, "%s/pkg/obj/%s_%s", goroot, gohostos, gohostarch);
-       if(rebuildall)
-               xremoveall(p);
-       xmkdirall(p);
-
-       // Create tool directory.
-       // We keep it in pkg/, just like the object directory above.
-       if(rebuildall)
-               xremoveall(tooldir);
-       xmkdirall(tooldir);
-
-       // Remove tool binaries from before the tool/gohostos_gohostarch
-       xremoveall(bpathf(&b, "%s/bin/tool", goroot));
-
-       // Remove old pre-tool binaries.
-       for(i=0; i<nelem(oldtool); i++)
-               xremove(bpathf(&b, "%s/bin/%s", goroot, oldtool[i]));
-
-       // If $GOBIN is set and has a Go compiler, it must be cleaned.
-       for(i=0; gochars[i]; i++) {
-               if(isfile(bprintf(&b, "%s%s%c%s", gobin, slash, gochars[i], "g"))) {
-                       for(i=0; i<nelem(oldtool); i++)
-                               xremove(bprintf(&b, "%s%s%s", gobin, slash, oldtool[i]));
-                       break;
-               }
-       }
-
-       // For release, make sure excluded things are excluded.
-       if(hasprefix(goversion, "release.") || (hasprefix(goversion, "go") && !contains(goversion, "beta"))) {
-               for(i=0; i<nelem(unreleased); i++)
-                       if(isdir(bpathf(&b, "%s/%s", goroot, unreleased[i])))
-                               fatal("%s should not exist in release build", bstr(&b));
-       }
-
-       bfree(&b);
-}
-
-/*
- * C library and tool building
- */
-
-// gccargs is the gcc command line to use for compiling a single C file.
-static char *proto_gccargs[] = {
-       "-Wall",
-       // native Plan 9 compilers don't like non-standard prototypes
-       // so let gcc catch them.
-       "-Wstrict-prototypes",
-       "-Wextra",
-       "-Wunused",
-       "-Wno-sign-compare",
-       "-Wno-missing-braces",
-       "-Wno-parentheses",
-       "-Wno-unknown-pragmas",
-       "-Wno-switch",
-       "-Wno-comment",
-       "-Wno-missing-field-initializers",
-       "-Werror",
-       "-fno-common",
-       "-ggdb",
-       "-pipe",
-};
-
-// gccargs2 is the second part of gccargs.
-// it is used if the environment isn't defining CFLAGS.
-static char *proto_gccargs2[] = {
-       // on older versions of GCC, -Wuninitialized is not supported
-       // without -O, so put it here together with -O settings in case
-       // the user's $CFLAGS doesn't include -O.
-       "-Wuninitialized",
-#if defined(__NetBSD__) && defined(__arm__)
-       // GCC 4.5.4 (NetBSD nb1 20120916) on ARM is known to mis-optimize gc/mparith3.c
-       // Fix available at http://patchwork.ozlabs.org/patch/64562/.
-       "-O1",
-#else
-       "-O2",
-#endif
-};
-
-static Vec gccargs, ldargs;
-
-// deptab lists changes to the default dependencies for a given prefix.
-// deps ending in /* read the whole directory; deps beginning with -
-// exclude files with that prefix.
-static struct {
-       char *prefix;  // prefix of target
-       char *dep[20];  // dependency tweaks for targets with that prefix
-} deptab[] = {
-       {"lib9", {
-               "$GOROOT/include/u.h",
-               "$GOROOT/include/utf.h",
-               "$GOROOT/include/fmt.h",
-               "$GOROOT/include/libc.h",
-               "fmt/*",
-               "utf/*",
-       }},
-       {"libbio", {
-               "$GOROOT/include/u.h",
-               "$GOROOT/include/utf.h",
-               "$GOROOT/include/fmt.h",
-               "$GOROOT/include/libc.h",
-               "$GOROOT/include/bio.h",
-       }},
-       {"liblink", {
-               "$GOROOT/include/u.h",
-               "$GOROOT/include/utf.h",
-               "$GOROOT/include/fmt.h",
-               "$GOROOT/include/libc.h",
-               "$GOROOT/include/bio.h",
-               "$GOROOT/include/ar.h",
-               "$GOROOT/include/link.h",
-               "anames5.c",
-               "anames6.c",
-               "anames8.c",
-               "anames9.c",
-       }},
-       {"cmd/gc", {
-               "-cplx.c",
-               "-pgen.c",
-               "-plive.c",
-               "-popt.c",
-               "-y1.tab.c",  // makefile dreg
-               "opnames.h",
-       }},
-       {"cmd/5g", {
-               "../gc/cplx.c",
-               "../gc/pgen.c",
-               "../gc/plive.c",
-               "../gc/popt.c",
-               "../gc/popt.h",
-               "$GOROOT/pkg/obj/$GOHOSTOS_$GOHOSTARCH/libgc.a",
-       }},
-       {"cmd/6g", {
-               "../gc/cplx.c",
-               "../gc/pgen.c",
-               "../gc/plive.c",
-               "../gc/popt.c",
-               "../gc/popt.h",
-               "$GOROOT/pkg/obj/$GOHOSTOS_$GOHOSTARCH/libgc.a",
-       }},
-       {"cmd/8g", {
-               "../gc/cplx.c",
-               "../gc/pgen.c",
-               "../gc/plive.c",
-               "../gc/popt.c",
-               "../gc/popt.h",
-               "$GOROOT/pkg/obj/$GOHOSTOS_$GOHOSTARCH/libgc.a",
-       }},
-       {"cmd/9g", {
-               "../gc/cplx.c",
-               "../gc/pgen.c",
-               "../gc/plive.c",
-               "../gc/popt.c",
-               "../gc/popt.h",
-               "$GOROOT/pkg/obj/$GOHOSTOS_$GOHOSTARCH/libgc.a",
-       }},
-       {"cmd/5l", {
-               "../ld/*",
-       }},
-       {"cmd/6l", {
-               "../ld/*",
-       }},
-       {"cmd/8l", {
-               "../ld/*",
-       }},
-       {"cmd/9l", {
-               "../ld/*",
-       }},
-       {"cmd/go", {
-               "zdefaultcc.go",
-       }},
-       {"cmd/", {
-               "$GOROOT/pkg/obj/$GOHOSTOS_$GOHOSTARCH/liblink.a",
-               "$GOROOT/pkg/obj/$GOHOSTOS_$GOHOSTARCH/libbio.a",
-               "$GOROOT/pkg/obj/$GOHOSTOS_$GOHOSTARCH/lib9.a",
-       }},
-       {"runtime", {
-               "zaexperiment.h",
-               "zversion.go",
-       }},
-};
-
-// depsuffix records the allowed suffixes for source files.
-char *depsuffix[] = {
-       ".c",
-       ".h",
-       ".s",
-       ".go",
-};
-
-// gentab records how to generate some trivial files.
-static struct {
-       char *nameprefix;
-       void (*gen)(char*, char*);
-} gentab[] = {
-       {"opnames.h", gcopnames},
-       {"anames5.c", mkanames},
-       {"anames6.c", mkanames},
-       {"anames8.c", mkanames},
-       {"anames9.c", mkanames},
-       {"zdefaultcc.go", mkzdefaultcc},
-       {"zversion.go", mkzversion},
-       {"zaexperiment.h", mkzexperiment},
-
-       // not generated anymore, but delete the file if we see it
-       {"enam.c", nil},
-};
-
-// install installs the library, package, or binary associated with dir,
-// which is relative to $GOROOT/src.
-static void
-install(char *dir)
-{
-       char *name, *p, *elem, *prefix, *exe;
-       bool islib, ispkg, isgo, stale, ispackcmd;
-       Buf b, b1, path, final_path, final_name, archive;
-       Vec compile, files, link, go, missing, clean, lib, extra;
-       Time ttarg, t;
-       int i, j, k, n, doclean, targ;
-
-       if(vflag) {
-               if(!streq(goos, gohostos) || !streq(goarch, gohostarch))
-                       errprintf("%s (%s/%s)\n", dir, goos, goarch);
-               else
-                       errprintf("%s\n", dir);
-       }
-
-       binit(&b);
-       binit(&b1);
-       binit(&path);
-       binit(&final_path);
-       binit(&final_name);
-       binit(&archive);
-       vinit(&compile);
-       vinit(&files);
-       vinit(&link);
-       vinit(&go);
-       vinit(&missing);
-       vinit(&clean);
-       vinit(&lib);
-       vinit(&extra);
-
-
-       // path = full path to dir.
-       bpathf(&path, "%s/src/%s", goroot, dir);
-       bpathf(&final_path, "%s/src/%s", goroot_final, dir);
-       name = lastelem(dir);
-
-       // set up gcc command line on first run.
-       if(gccargs.len == 0) {
-               bprintf(&b, "%s %s", defaultcc, defaultcflags);
-               splitfields(&gccargs, bstr(&b));
-               for(i=0; i<nelem(proto_gccargs); i++)
-                       vadd(&gccargs, proto_gccargs[i]);
-               if(defaultcflags[0] == '\0') {
-                       for(i=0; i<nelem(proto_gccargs2); i++)
-                               vadd(&gccargs, proto_gccargs2[i]);
-               }
-               if(contains(gccargs.p[0], "clang")) {
-                       // disable ASCII art in clang errors, if possible
-                       vadd(&gccargs, "-fno-caret-diagnostics");
-                       // clang is too smart about unused command-line arguments
-                       vadd(&gccargs, "-Qunused-arguments");
-               }
-               // disable word wrapping in error messages
-               vadd(&gccargs, "-fmessage-length=0");
-               if(streq(gohostos, "darwin")) {
-                       // golang.org/issue/5261
-                       vadd(&gccargs, "-mmacosx-version-min=10.6");
-               }
-       }
-       if(ldargs.len == 0 && defaultldflags[0] != '\0') {
-               bprintf(&b, "%s", defaultldflags);
-               splitfields(&ldargs, bstr(&b));
-       }
-
-       islib = hasprefix(dir, "lib") || streq(dir, "cmd/gc");
-       ispkg = !islib && !hasprefix(dir, "cmd/");
-       isgo = ispkg || streq(dir, "cmd/go") || streq(dir, "cmd/cgo");
-
-       exe = "";
-       if(streq(gohostos, "windows"))
-               exe = ".exe";
-
-       // Start final link command line.
-       // Note: code below knows that link.p[targ] is the target.
-       ispackcmd = 0;
-       if(islib) {
-               // C library.
-               vadd(&link, "ar");
-               if(streq(gohostos, "plan9"))
-                       vadd(&link, "rc");
-               else
-                       vadd(&link, "rsc");
-               prefix = "";
-               if(!hasprefix(name, "lib"))
-                       prefix = "lib";
-               targ = link.len;
-               vadd(&link, bpathf(&b, "%s/pkg/obj/%s_%s/%s%s.a", goroot, gohostos, gohostarch, prefix, name));
-       } else if(ispkg) {
-               // Go library (package).
-               ispackcmd = 1;
-               vadd(&link, "pack"); // program name - unused here, but all the other cases record one
-               p = bprintf(&b, "%s/pkg/%s_%s/%s", goroot, goos, goarch, dir);
-               *xstrrchr(p, '/') = '\0';
-               xmkdirall(p);
-               targ = link.len;
-               vadd(&link, bpathf(&b, "%s/pkg/%s_%s/%s.a", goroot, goos, goarch, dir));
-       } else if(streq(dir, "cmd/go") || streq(dir, "cmd/cgo")) {
-               // Go command.
-               vadd(&link, bpathf(&b, "%s/%sl", tooldir, gochar));
-               vadd(&link, "-o");
-               elem = name;
-               if(streq(elem, "go"))
-                       elem = "go_bootstrap";
-               targ = link.len;
-               vadd(&link, bpathf(&b, "%s/%s%s", tooldir, elem, exe));
-       } else {
-               // C command. Use gccargs and ldargs.
-               if(streq(gohostos, "plan9")) {
-                       vadd(&link, bprintf(&b, "%sl", gohostchar));
-                       vadd(&link, "-o");
-                       targ = link.len;
-                       vadd(&link, bpathf(&b, "%s/%s", tooldir, name));
-               } else {
-                       vcopy(&link, gccargs.p, gccargs.len);
-                       vcopy(&link, ldargs.p, ldargs.len);
-                       if(sflag)
-                               vadd(&link, "-static");
-                       vadd(&link, "-o");
-                       targ = link.len;
-                       vadd(&link, bpathf(&b, "%s/%s%s", tooldir, name, exe));
-                       if(streq(gohostarch, "amd64"))
-                               vadd(&link, "-m64");
-                       else if(streq(gohostarch, "386"))
-                               vadd(&link, "-m32");
-               }
-       }
-       ttarg = mtime(link.p[targ]);
-
-       // Gather files that are sources for this target.
-       // Everything in that directory, and any target-specific
-       // additions.
-       xreaddir(&files, bstr(&path));
-
-       // Remove files beginning with . or _,
-       // which are likely to be editor temporary files.
-       // This is the same heuristic build.ScanDir uses.
-       // There do exist real C files beginning with _,
-       // so limit that check to just Go files.
-       n = 0;
-       for(i=0; i<files.len; i++) {
-               p = files.p[i];
-               if(hasprefix(p, ".") || (hasprefix(p, "_") && hassuffix(p, ".go")))
-                       xfree(p);
-               else
-                       files.p[n++] = p;
-       }
-       files.len = n;
-
-       for(i=0; i<nelem(deptab); i++) {
-               if(streq(dir, deptab[i].prefix) ||
-                  (hassuffix(deptab[i].prefix, "/") && hasprefix(dir, deptab[i].prefix))) {
-                       for(j=0; (p=deptab[i].dep[j])!=nil; j++) {
-                               breset(&b1);
-                               bwritestr(&b1, p);
-                               bsubst(&b1, "$GOROOT", goroot);
-                               bsubst(&b1, "$GOOS", goos);
-                               bsubst(&b1, "$GOARCH", goarch);
-                               bsubst(&b1, "$GOHOSTOS", gohostos);
-                               bsubst(&b1, "$GOHOSTARCH", gohostarch);
-                               p = bstr(&b1);
-                               if(hassuffix(p, ".a")) {
-                                       vadd(&lib, bpathf(&b, "%s", p));
-                                       continue;
-                               }
-                               if(hassuffix(p, "/*")) {
-                                       bpathf(&b, "%s/%s", bstr(&path), p);
-                                       b.len -= 2;
-                                       xreaddir(&extra, bstr(&b));
-                                       bprintf(&b, "%s", p);
-                                       b.len -= 2;
-                                       for(k=0; k<extra.len; k++)
-                                               vadd(&files, bpathf(&b1, "%s/%s", bstr(&b), extra.p[k]));
-                                       continue;
-                               }
-                               if(hasprefix(p, "-")) {
-                                       p++;
-                                       n = 0;
-                                       for(k=0; k<files.len; k++) {
-                                               if(hasprefix(files.p[k], p))
-                                                       xfree(files.p[k]);
-                                               else
-                                                       files.p[n++] = files.p[k];
-                                       }
-                                       files.len = n;
-                                       continue;
-                               }
-                               vadd(&files, p);
-                       }
-               }
-       }
-       vuniq(&files);
-
-       // Convert to absolute paths.
-       for(i=0; i<files.len; i++) {
-               if(!isabs(files.p[i])) {
-                       bpathf(&b, "%s/%s", bstr(&path), files.p[i]);
-                       xfree(files.p[i]);
-                       files.p[i] = btake(&b);
-               }
-       }
-
-       // Is the target up-to-date?
-       stale = rebuildall;
-       n = 0;
-       for(i=0; i<files.len; i++) {
-               p = files.p[i];
-               for(j=0; j<nelem(depsuffix); j++)
-                       if(hassuffix(p, depsuffix[j]))
-                               goto ok;
-               xfree(files.p[i]);
-               continue;
-       ok:
-               t = mtime(p);
-               if(t != 0 && !hassuffix(p, ".a") && !shouldbuild(p, dir)) {
-                       xfree(files.p[i]);
-                       continue;
-               }
-               if(hassuffix(p, ".go"))
-                       vadd(&go, p);
-               if(t > ttarg)
-                       stale = 1;
-               if(t == 0) {
-                       vadd(&missing, p);
-                       files.p[n++] = files.p[i];
-                       continue;
-               }
-               files.p[n++] = files.p[i];
-       }
-       files.len = n;
-
-       // If there are no files to compile, we're done.
-       if(files.len == 0)
-               goto out;
-       
-       for(i=0; i<lib.len && !stale; i++)
-               if(mtime(lib.p[i]) > ttarg)
-                       stale = 1;
-
-       if(!stale)
-               goto out;
-
-       // For package runtime, copy some files into the work space.
-       if(streq(dir, "runtime")) {
-               copyfile(bpathf(&b, "%s/pkg/%s_%s/textflag.h", goroot, goos, goarch),
-                       bpathf(&b1, "%s/src/cmd/ld/textflag.h", goroot), 0);
-               copyfile(bpathf(&b, "%s/pkg/%s_%s/funcdata.h", goroot, goos, goarch),
-                       bpathf(&b1, "%s/src/runtime/funcdata.h", goroot), 0);
-       }
-
-       // Generate any missing files; regenerate existing ones.
-       for(i=0; i<files.len; i++) {
-               p = files.p[i];
-               elem = lastelem(p);
-               for(j=0; j<nelem(gentab); j++) {
-                       if(gentab[j].gen == nil)
-                               continue;
-                       if(hasprefix(elem, gentab[j].nameprefix)) {
-                               if(vflag > 1)
-                                       errprintf("generate %s\n", p);
-                               gentab[j].gen(bstr(&path), p);
-                               // Do not add generated file to clean list.
-                               // In runtime, we want to be able to
-                               // build the package with the go tool,
-                               // and it assumes these generated files already
-                               // exist (it does not know how to build them).
-                               // The 'clean' command can remove
-                               // the generated files.
-                               goto built;
-                       }
-               }
-               // Did not rebuild p.
-               if(find(p, missing.p, missing.len) >= 0)
-                       fatal("missing file %s", p);
-       built:;
-       }
-
-       if((!streq(goos, gohostos) || !streq(goarch, gohostarch)) && isgo) {
-               // We've generated the right files; the go command can do the build.
-               if(vflag > 1)
-                       errprintf("skip build for cross-compile %s\n", dir);
-               goto nobuild;
-       }
-
-       if(isgo) {
-               // The next loop will compile individual non-Go files.
-               // Hand the Go files to the compiler en masse.
-               // For package runtime, this writes go_asm.h, which
-               // the assembly files will need.
-               vreset(&compile);
-               vadd(&compile, bpathf(&b, "%s/%sg", tooldir, gochar));
-
-               bpathf(&b, "%s/_go_.a", workdir);
-               vadd(&compile, "-pack");
-               vadd(&compile, "-o");
-               vadd(&compile, bstr(&b));
-               vadd(&clean, bstr(&b));
-               if(!ispackcmd)
-                       vadd(&link, bstr(&b));
-               else
-                       bwriteb(&archive, &b);
-
-               vadd(&compile, "-p");
-               if(hasprefix(dir, "cmd/"))
-                       vadd(&compile, "main");
-               else
-                       vadd(&compile, dir);
-
-               if(streq(dir, "runtime")) {
-                       vadd(&compile, "-+");
-                       vadd(&compile, "-asmhdr");
-                       bpathf(&b1, "%s/go_asm.h", workdir);
-                       vadd(&compile, bstr(&b1));
-               }
-
-               vcopy(&compile, go.p, go.len);
-
-               runv(nil, bstr(&path), CheckExit, &compile);
-       }
-
-       // Compile the files.
-       for(i=0; i<files.len; i++) {
-               if(!hassuffix(files.p[i], ".c") && !hassuffix(files.p[i], ".s"))
-                       continue;
-               name = lastelem(files.p[i]);
-
-               vreset(&compile);
-               if(!isgo) {
-                       // C library or tool.
-                       if(streq(gohostos, "plan9")) {
-                               vadd(&compile, bprintf(&b, "%sc", gohostchar));
-                               vadd(&compile, "-FTVwp");
-                               vadd(&compile, "-DPLAN9");
-                               vadd(&compile, "-D__STDC__=1");
-                               vadd(&compile, "-D__SIZE_TYPE__=ulong"); // for GNU Bison
-                               vadd(&compile, bpathf(&b, "-I%s/include/plan9", goroot));
-                               vadd(&compile, bpathf(&b, "-I%s/include/plan9/%s", goroot, gohostarch));
-                       } else {
-                               vcopy(&compile, gccargs.p, gccargs.len);
-                               vadd(&compile, "-c");
-                               if(streq(gohostarch, "amd64"))
-                                       vadd(&compile, "-m64");
-                               else if(streq(gohostarch, "386"))
-                                       vadd(&compile, "-m32");
-       
-                               vadd(&compile, "-I");
-                               vadd(&compile, bpathf(&b, "%s/include", goroot));
-                       }
-
-                       if(streq(dir, "lib9"))
-                               vadd(&compile, "-DPLAN9PORT");
-
-
-                       vadd(&compile, "-I");
-                       vadd(&compile, bstr(&path));
-
-                       // lib9/goos.c gets the default constants hard-coded.
-                       if(streq(name, "goos.c")) {
-                               vadd(&compile, "-D");
-                               vadd(&compile, bprintf(&b, "GOOS=\"%s\"", goos));
-                               vadd(&compile, "-D");
-                               vadd(&compile, bprintf(&b, "GOARCH=\"%s\"", goarch));
-                               bprintf(&b1, "%s", goroot_final);
-                               bsubst(&b1, "\\", "\\\\");  // turn into C string
-                               vadd(&compile, "-D");
-                               vadd(&compile, bprintf(&b, "GOROOT=\"%s\"", bstr(&b1)));
-                               vadd(&compile, "-D");
-                               vadd(&compile, bprintf(&b, "GOVERSION=\"%s\"", goversion));
-                               vadd(&compile, "-D");
-                               vadd(&compile, bprintf(&b, "GOARM=\"%s\"", goarm));
-                               vadd(&compile, "-D");
-                               vadd(&compile, bprintf(&b, "GO386=\"%s\"", go386));
-                               vadd(&compile, "-D");
-                               vadd(&compile, bprintf(&b, "GO_EXTLINK_ENABLED=\"%s\"", goextlinkenabled));
-                       }
-
-                       // gc/lex.c records the GOEXPERIMENT setting used during the build.
-                       if(streq(name, "lex.c")) {
-                               xgetenv(&b, "GOEXPERIMENT");
-                               vadd(&compile, "-D");
-                               vadd(&compile, bprintf(&b1, "GOEXPERIMENT=\"%s\"", bstr(&b)));
-                       }
-               } else {
-                       // Supporting files for a Go package.
-                       if(hassuffix(files.p[i], ".s"))
-                               vadd(&compile, bpathf(&b, "%s/%sa", tooldir, gochar));
-                       else {
-                               vadd(&compile, bpathf(&b, "%s/%sc", tooldir, gochar));
-                               vadd(&compile, "-F");
-                               vadd(&compile, "-V");
-                               vadd(&compile, "-w");
-                       }
-                       vadd(&compile, "-I");
-                       vadd(&compile, workdir);
-                       vadd(&compile, "-I");
-                       vadd(&compile, bprintf(&b, "%s/pkg/%s_%s", goroot, goos, goarch));
-                       vadd(&compile, "-D");
-                       vadd(&compile, bprintf(&b, "GOOS_%s", goos));
-                       vadd(&compile, "-D");
-                       vadd(&compile, bprintf(&b, "GOARCH_%s", goarch));
-                       vadd(&compile, "-D");
-                       vadd(&compile, bprintf(&b, "GOOS_GOARCH_%s_%s", goos, goarch));
-               }
-
-               bpathf(&b, "%s/%s", workdir, lastelem(files.p[i]));
-               doclean = 1;
-               if(!isgo && streq(gohostos, "darwin")) {
-                       // To debug C programs on OS X, it is not enough to say -ggdb
-                       // on the command line.  You have to leave the object files
-                       // lying around too.  Leave them in pkg/obj/, which does not
-                       // get removed when this tool exits.
-                       bpathf(&b1, "%s/pkg/obj/%s", goroot, dir);
-                       xmkdirall(bstr(&b1));
-                       bpathf(&b, "%s/%s", bstr(&b1), lastelem(files.p[i]));
-                       doclean = 0;
-               }
-
-               // Change the last character of the output file (which was c or s).
-               if(streq(gohostos, "plan9"))
-                       b.p[b.len-1] = gohostchar[0];
-               else
-                       b.p[b.len-1] = 'o';
-               vadd(&compile, "-o");
-               vadd(&compile, bstr(&b));
-               vadd(&compile, files.p[i]);
-               bgrunv(bstr(&path), CheckExit, &compile);
-
-               vadd(&link, bstr(&b));
-               if(doclean)
-                       vadd(&clean, bstr(&b));
-       }
-       bgwait();
-
-       if(isgo && ispackcmd) {
-               xremove(link.p[targ]);
-               dopack(link.p[targ], bstr(&archive), &link.p[targ+1], link.len - (targ+1));
-               goto nobuild;
-       }
-
-       if(!islib && !isgo) {
-               // C binaries need the libraries explicitly, and -lm.
-               vcopy(&link, lib.p, lib.len);
-               if(!streq(gohostos, "plan9"))
-                       vadd(&link, "-lm");
-       }
-
-       // Remove target before writing it.
-       xremove(link.p[targ]);
-
-       runv(nil, nil, CheckExit, &link);
-nobuild:
-
-out:
-       for(i=0; i<clean.len; i++)
-               xremove(clean.p[i]);
-
-       bfree(&b);
-       bfree(&b1);
-       bfree(&path);
-       bfree(&archive);
-       vfree(&compile);
-       vfree(&files);
-       vfree(&link);
-       vfree(&go);
-       vfree(&missing);
-       vfree(&clean);
-       vfree(&lib);
-       vfree(&extra);
-}
-
-// matchfield reports whether the field matches this build.
-static bool
-matchfield(char *f)
-{
-       char *p;
-       bool res;
-
-       p = xstrrchr(f, ',');
-       if(p == nil)
-               return streq(f, goos) || streq(f, goarch) || streq(f, "cmd_go_bootstrap") || streq(f, "go1.1") || (streq(goos, "android") && streq(f, "linux"));
-       *p = 0;
-       res = matchfield(f) && matchfield(p+1);
-       *p = ',';
-       return res;
-}
-
-// shouldbuild reports whether we should build this file.
-// It applies the same rules that are used with context tags
-// in package go/build, except that the GOOS and GOARCH
-// can appear anywhere in the file name, not just after _.
-// In particular, they can be the entire file name (like windows.c).
-// We also allow the special tag cmd_go_bootstrap.
-// See ../go/bootstrap.go and package go/build.
-static bool
-shouldbuild(char *file, char *dir)
-{
-       char *name, *p;
-       int i, j, ret;
-       Buf b;
-       Vec lines, fields;
-       
-       // Check file name for GOOS or GOARCH.
-       name = lastelem(file);
-       for(i=0; i<nelem(okgoos); i++) {
-               if(streq(okgoos[i], goos))
-                       continue;
-               p = xstrstr(name, okgoos[i]);
-               if(p == nil)
-                       continue;
-               p += xstrlen(okgoos[i]);
-               if(*p == '.' || *p == '_' || *p == '\0')
-                       return 0;
-       }
-       for(i=0; i<nelem(okgoarch); i++) {
-               if(streq(okgoarch[i], goarch))
-                       continue;
-               p = xstrstr(name, okgoarch[i]);
-               if(p == nil)
-                       continue;
-               p += xstrlen(okgoarch[i]);
-               if(*p == '.' || *p == '_' || *p == '\0')
-                       return 0;
-       }
-
-       // Omit test files.
-       if(contains(name, "_test"))
-               return 0;
-
-       // cmd/go/doc.go has a giant /* */ comment before
-       // it gets to the important detail that it is not part of
-       // package main.  We don't parse those comments,
-       // so special case that file.
-       if(hassuffix(file, "cmd/go/doc.go") || hassuffix(file, "cmd\\go\\doc.go"))
-               return 0;
-       if(hassuffix(file, "cmd/cgo/doc.go") || hassuffix(file, "cmd\\cgo\\doc.go"))
-               return 0;
-
-       // Check file contents for // +build lines.
-       binit(&b);
-       vinit(&lines);
-       vinit(&fields);
-
-       ret = 1;
-       readfile(&b, file);
-       splitlines(&lines, bstr(&b));
-       for(i=0; i<lines.len; i++) {
-               p = lines.p[i];
-               while(*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n')
-                       p++;
-               if(*p == '\0')
-                       continue;
-               if(contains(p, "package documentation")) {
-                       ret = 0;
-                       goto out;
-               }
-               if(contains(p, "package main") && !streq(dir, "cmd/go") && !streq(dir, "cmd/cgo")) {
-                       ret = 0;
-                       goto out;
-               }
-               if(!hasprefix(p, "//"))
-                       break;
-               if(!contains(p, "+build"))
-                       continue;
-               splitfields(&fields, lines.p[i]);
-               if(fields.len < 2 || !streq(fields.p[1], "+build"))
-                       continue;
-               for(j=2; j<fields.len; j++) {
-                       p = fields.p[j];
-                       if((*p == '!' && !matchfield(p+1)) || matchfield(p))
-                               goto fieldmatch;
-               }
-               ret = 0;
-               goto out;
-       fieldmatch:;
-       }
-
-out:
-       bfree(&b);
-       vfree(&lines);
-       vfree(&fields);
-
-       return ret;
-}
-
-// copy copies the file src to dst, via memory (so only good for small files).
-void
-copyfile(char *dst, char *src, int exec)
-{
-       Buf b;
-
-       if(vflag > 1)
-               errprintf("cp %s %s\n", src, dst);
-
-       binit(&b);
-       readfile(&b, src);
-       writefile(&b, dst, exec);
-       bfree(&b);
-}
-
-// dopack copies the package src to dst,
-// appending the files listed in extra.
-// The archive format is the traditional Unix ar format.
-static void
-dopack(char *dst, char *src, char **extra, int nextra)
-{
-       int i;
-       char c, *p, *q;
-       Buf b, bdst;
-       
-       binit(&b);
-       binit(&bdst);
-
-       readfile(&bdst, src);
-       for(i=0; i<nextra; i++) {
-               readfile(&b, extra[i]);
-               // find last path element for archive member name
-               p = xstrrchr(extra[i], '/');
-               if(p)
-                       p++;
-               q = xstrrchr(extra[i], '\\');
-               if(q) {
-                       q++;
-                       if(p == nil || q > p)
-                               p = q;
-               }
-               if(p == nil)
-                       p = extra[i];
-               bwritef(&bdst, "%-16.16s%-12d%-6d%-6d%-8o%-10d`\n", p, 0, 0, 0, 0644, b.len);
-               bwriteb(&bdst, &b);
-               if(b.len&1) {
-                       c = 0;
-                       bwrite(&bdst, &c, 1);
-               }
-       }
-
-       writefile(&bdst, dst, 0);
-
-       bfree(&b);
-       bfree(&bdst);
-}
-
-// buildorder records the order of builds for the 'go bootstrap' command.
-static char *buildorder[] = {
-       "lib9",
-       "libbio",
-       "liblink",
-
-       "cmd/gc",  // must be before g
-       "cmd/%sl",  // must be before a, g
-       "cmd/%sa",
-       "cmd/%sg",
-
-       // The dependency order here was copied from a buildscript
-       // back when there were build scripts.  Will have to
-       // be maintained by hand, but shouldn't change very
-       // often.
-       "runtime",
-       "errors",
-       "sync/atomic",
-       "sync",
-       "io",
-       "unicode",
-       "unicode/utf8",
-       "unicode/utf16",
-       "bytes",
-       "math",
-       "strings",
-       "strconv",
-       "bufio",
-       "sort",
-       "container/heap",
-       "encoding/base64",
-       "syscall",
-       "time",
-       "os",
-       "reflect",
-       "fmt",
-       "encoding",
-       "encoding/json",
-       "flag",
-       "path/filepath",
-       "path",
-       "io/ioutil",
-       "log",
-       "regexp/syntax",
-       "regexp",
-       "go/token",
-       "go/scanner",
-       "go/ast",
-       "go/parser",
-       "os/exec",
-       "os/signal",
-       "net/url",
-       "text/template/parse",
-       "text/template",
-       "go/doc",
-       "go/build",
-       "cmd/go",
-};
-
-// cleantab records the directories to clean in 'go clean'.
-// It is bigger than the buildorder because we clean all the
-// compilers but build only the $GOARCH ones.
-static char *cleantab[] = {
-       // Commands and C libraries.
-       "cmd/5a",
-       "cmd/5g",
-       "cmd/5l",
-       "cmd/6a",
-       "cmd/6g",
-       "cmd/6l",
-       "cmd/8a",
-       "cmd/8g",
-       "cmd/8l",
-       "cmd/9a",
-       "cmd/9g",
-       "cmd/9l",
-       "cmd/gc",
-       "cmd/go",       
-       "lib9",
-       "libbio",
-       "liblink",
-
-       // Go packages.
-       "bufio",
-       "bytes",
-       "container/heap",
-       "encoding",
-       "encoding/base64",
-       "encoding/json",
-       "errors",
-       "flag",
-       "fmt",
-       "go/ast",
-       "go/build",
-       "go/doc",
-       "go/parser",
-       "go/scanner",
-       "go/token",
-       "io",
-       "io/ioutil",
-       "log",
-       "math",
-       "net/url",
-       "os",
-       "os/exec",
-       "path",
-       "path/filepath",
-       "reflect",
-       "regexp",
-       "regexp/syntax",
-       "runtime",
-       "sort",
-       "strconv",
-       "strings",
-       "sync",
-       "sync/atomic",
-       "syscall",
-       "text/template",
-       "text/template/parse",
-       "time",
-       "unicode",
-       "unicode/utf16",
-       "unicode/utf8",
-};
-
-static char *runtimegen[] = {
-       "zaexperiment.h",
-       "zversion.go",
-};
-
-static void
-clean(void)
-{
-       int i, j, k;
-       Buf b, path;
-       Vec dir;
-
-       binit(&b);
-       binit(&path);
-       vinit(&dir);
-
-       for(i=0; i<nelem(cleantab); i++) {
-               bpathf(&path, "%s/src/%s", goroot, cleantab[i]);
-               xreaddir(&dir, bstr(&path));
-               // Remove generated files.
-               for(j=0; j<dir.len; j++) {
-                       for(k=0; k<nelem(gentab); k++) {
-                               if(hasprefix(dir.p[j], gentab[k].nameprefix))
-                                       xremove(bpathf(&b, "%s/%s", bstr(&path), dir.p[j]));
-                       }
-               }
-               // Remove generated binary named for directory.
-               if(hasprefix(cleantab[i], "cmd/"))
-                       xremove(bpathf(&b, "%s/%s", bstr(&path), cleantab[i]+4));
-       }
-
-       // remove src/runtime/zaexperiment.h and 
-       // except leave zgoos and zgoarch, now maintained with go generate.
-       bpathf(&path, "%s/src/runtime", goroot);
-       for(j=0; j<nelem(runtimegen); j++)
-               xremove(bpathf(&b, "%s/%s", bstr(&path), runtimegen[j]));
-
-       if(rebuildall) {
-               // Remove object tree.
-               xremoveall(bpathf(&b, "%s/pkg/obj/%s_%s", goroot, gohostos, gohostarch));
-
-               // Remove installed packages and tools.
-               xremoveall(bpathf(&b, "%s/pkg/%s_%s", goroot, gohostos, gohostarch));
-               xremoveall(bpathf(&b, "%s/pkg/%s_%s", goroot, goos, goarch));
-               xremoveall(tooldir);
-
-               // Remove cached version info.
-               xremove(bpathf(&b, "%s/VERSION.cache", goroot));
-       }
-
-       bfree(&b);
-       bfree(&path);
-       vfree(&dir);
-}
-
-/*
- * command implementations
- */
-
-void
-usage(void)
-{
-       xprintf("usage: go tool dist [command]\n"
-               "Commands are:\n"
-               "\n"
-               "banner         print installation banner\n"
-               "bootstrap      rebuild everything\n"
-               "clean          deletes all built files\n"
-               "env [-p]       print environment (-p: include $PATH)\n"
-               "install [dir]  install individual directory\n"
-               "version        print Go version\n"
-               "\n"
-               "All commands take -v flags to emit extra information.\n"
-       );
-       xexit(2);
-}
-
-// The env command prints the default environment.
-void
-cmdenv(int argc, char **argv)
-{
-       bool pflag;
-       char *sep;
-       Buf b, b1;
-       char *format;
-
-       binit(&b);
-       binit(&b1);
-
-       format = "%s=\"%s\"\n";
-       pflag = 0;
-       ARGBEGIN{
-       case '9':
-               format = "%s='%s'\n";
-               break;
-       case 'p':
-               pflag = 1;
-               break;
-       case 'v':
-               vflag++;
-               break;
-       case 'w':
-               format = "set %s=%s\r\n";
-               break;
-       default:
-               usage();
-       }ARGEND
-
-       if(argc > 0)
-               usage();
-
-       xprintf(format, "CC", defaultcc);
-       xprintf(format, "CC_FOR_TARGET", defaultcctarget);
-       xprintf(format, "GOROOT", goroot);
-       xprintf(format, "GOBIN", gobin);
-       xprintf(format, "GOARCH", goarch);
-       xprintf(format, "GOOS", goos);
-       xprintf(format, "GOHOSTARCH", gohostarch);
-       xprintf(format, "GOHOSTOS", gohostos);
-       xprintf(format, "GOTOOLDIR", tooldir);
-       xprintf(format, "GOCHAR", gochar);
-       if(streq(goarch, "arm"))
-               xprintf(format, "GOARM", goarm);
-       if(streq(goarch, "386"))
-               xprintf(format, "GO386", go386);
-
-       if(pflag) {
-               sep = ":";
-               if(streq(gohostos, "windows"))
-                       sep = ";";
-               xgetenv(&b, "PATH");
-               bprintf(&b1, "%s%s%s", gobin, sep, bstr(&b));
-               xprintf(format, "PATH", bstr(&b1));
-       }
-
-       bfree(&b);
-       bfree(&b1);
-}
-
-// The bootstrap command runs a build from scratch,
-// stopping at having installed the go_bootstrap command.
-void
-cmdbootstrap(int argc, char **argv)
-{
-       int i;
-       Buf b;
-       char *oldgoos, *oldgoarch, *oldgochar;
-
-       binit(&b);
-
-       ARGBEGIN{
-       case 'a':
-               rebuildall = 1;
-               break;
-       case 's':
-               sflag++;
-               break;
-       case 'v':
-               vflag++;
-               break;
-       default:
-               usage();
-       }ARGEND
-
-       if(argc > 0)
-               usage();
-
-       if(isdir(bpathf(&b, "%s/src/pkg", goroot))) {
-               fatal("\n\n"
-                       "The Go package sources have moved to $GOROOT/src.\n"
-                       "*** %s still exists. ***\n"
-                       "It probably contains stale files that may confuse the build.\n"
-                       "Please (check what's there and) remove it and try again.\n"
-                       "See http://golang.org/s/go14nopkg\n", bpathf(&b, "%s/src/pkg", goroot));
-       }
-       
-       if(rebuildall)
-               clean();
-       goversion = findgoversion();
-       setup();
-
-       xsetenv("GOROOT", goroot);
-       xsetenv("GOROOT_FINAL", goroot_final);
-
-       // For the main bootstrap, building for host os/arch.
-       oldgoos = goos;
-       oldgoarch = goarch;
-       oldgochar = gochar;
-       goos = gohostos;
-       goarch = gohostarch;
-       gochar = gohostchar;
-       xsetenv("GOARCH", goarch);
-       xsetenv("GOOS", goos);
-
-       for(i=0; i<nelem(buildorder); i++) {
-               install(bprintf(&b, buildorder[i], gohostchar));
-               if(!streq(oldgochar, gohostchar) && xstrstr(buildorder[i], "%s"))
-                       install(bprintf(&b, buildorder[i], oldgochar));
-       }
-
-       goos = oldgoos;
-       goarch = oldgoarch;
-       gochar = oldgochar;
-       xsetenv("GOARCH", goarch);
-       xsetenv("GOOS", goos);
-
-       // Build runtime for actual goos/goarch too.
-       if(!streq(goos, gohostos) || !streq(goarch, gohostarch))
-               install("runtime");
-
-       bfree(&b);
-}
-
-static char*
-defaulttarg(void)
-{
-       char *p;
-       Buf pwd, src, real_src;
-
-       binit(&pwd);
-       binit(&src);
-       binit(&real_src);
-
-       // xgetwd might return a path with symlinks fully resolved, and if
-       // there happens to be symlinks in goroot, then the hasprefix test
-       // will never succeed. Instead, we use xrealwd to get a canonical
-       // goroot/src before the comparison to avoid this problem.
-       xgetwd(&pwd);
-       p = btake(&pwd);
-       bpathf(&src, "%s/src/", goroot);
-       xrealwd(&real_src, bstr(&src));
-       if(!hasprefix(p, bstr(&real_src)))
-               fatal("current directory %s is not under %s", p, bstr(&real_src));
-       p += real_src.len;
-       // guard againt xrealwd return the directory without the trailing /
-       if(*p == slash[0])
-               p++;
-
-       bfree(&pwd);
-       bfree(&src);
-       bfree(&real_src);
-
-       return p;
-}
-
-// Install installs the list of packages named on the command line.
-void
-cmdinstall(int argc, char **argv)
-{
-       int i;
-
-       ARGBEGIN{
-       case 's':
-               sflag++;
-               break;
-       case 'v':
-               vflag++;
-               break;
-       default:
-               usage();
-       }ARGEND
-
-       if(argc == 0)
-               install(defaulttarg());
-
-       for(i=0; i<argc; i++)
-               install(argv[i]);
-}
-
-// Clean deletes temporary objects.
-// Clean -i deletes the installed objects too.
-void
-cmdclean(int argc, char **argv)
-{
-       ARGBEGIN{
-       case 'v':
-               vflag++;
-               break;
-       default:
-               usage();
-       }ARGEND
-
-       if(argc > 0)
-               usage();
-
-       clean();
-}
-
-// Banner prints the 'now you've installed Go' banner.
-void
-cmdbanner(int argc, char **argv)
-{
-       char *pathsep, *pid, *ns;
-       Buf b, b1, search, path;
-
-       ARGBEGIN{
-       case 'v':
-               vflag++;
-               break;
-       default:
-               usage();
-       }ARGEND
-
-       if(argc > 0)
-               usage();
-
-       binit(&b);
-       binit(&b1);
-       binit(&search);
-       binit(&path);
-
-       xprintf("\n");
-       xprintf("---\n");
-       xprintf("Installed Go for %s/%s in %s\n", goos, goarch, goroot);
-       xprintf("Installed commands in %s\n", gobin);
-
-       if(!xsamefile(goroot_final, goroot)) {
-               // If the files are to be moved, don't check that gobin
-               // is on PATH; assume they know what they are doing.
-       } else if(streq(gohostos, "plan9")) {
-               // Check that gobin is bound before /bin.
-               readfile(&b, "#c/pid");
-               bsubst(&b, " ", "");
-               pid = btake(&b);
-               bprintf(&b, "/proc/%s/ns", pid);
-               ns = btake(&b);
-               readfile(&b, ns);
-               bprintf(&search, "bind -b %s /bin\n", gobin);
-               if(xstrstr(bstr(&b), bstr(&search)) == nil)
-                       xprintf("*** You need to bind %s before /bin.\n", gobin);
-       } else {
-               // Check that gobin appears in $PATH.
-               xgetenv(&b, "PATH");
-               pathsep = ":";
-               if(streq(gohostos, "windows"))
-                       pathsep = ";";
-               bprintf(&b1, "%s%s%s", pathsep, bstr(&b), pathsep);
-               bprintf(&search, "%s%s%s", pathsep, gobin, pathsep);
-               if(xstrstr(bstr(&b1), bstr(&search)) == nil)
-                       xprintf("*** You need to add %s to your PATH.\n", gobin);
-       }
-
-       if(streq(gohostos, "darwin")) {
-               if(isfile(bpathf(&path, "%s/cov", tooldir)))
-                       xprintf("\n"
-                               "On OS X the debuggers must be installed setgid procmod.\n"
-                               "Read and run ./sudo.bash to install the debuggers.\n");
-       }
-
-       if(!xsamefile(goroot_final, goroot)) {
-               xprintf("\n"
-                       "The binaries expect %s to be copied or moved to %s\n",
-                       goroot, goroot_final);
-       }
-
-       bfree(&b);
-       bfree(&b1);
-       bfree(&search);
-       bfree(&path);
-}
-
-// Version prints the Go version.
-void
-cmdversion(int argc, char **argv)
-{
-       ARGBEGIN{
-       case 'v':
-               vflag++;
-               break;
-       default:
-               usage();
-       }ARGEND
-
-       if(argc > 0)
-               usage();
-
-       xprintf("%s\n", goversion);
-}
diff --git a/src/cmd/dist/build.go b/src/cmd/dist/build.go
new file mode 100644 (file)
index 0000000..9e4d1e3
--- /dev/null
@@ -0,0 +1,1491 @@
+// Copyright 2012 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+       "bytes"
+       "flag"
+       "fmt"
+       "os"
+       "path/filepath"
+       "runtime"
+       "strings"
+)
+
+// Initialization for any invocation.
+
+// The usual variables.
+var (
+       goarch           string
+       gobin            string
+       gohostarch       string
+       gohostchar       string
+       gohostos         string
+       goos             string
+       goarm            string
+       go386            string
+       goroot           string
+       goroot_final     string
+       goextlinkenabled string
+       workdir          string
+       tooldir          string
+       gochar           string
+       goversion        string
+       oldgoos          string
+       oldgoarch        string
+       oldgochar        string
+       slash            string
+       defaultcc        string
+       defaultcflags    string
+       defaultldflags   string
+       defaultcxxtarget string
+       defaultcctarget  string
+       rebuildall       bool
+       defaultclang     bool
+
+       sflag bool // build static binaries
+       vflag int  // verbosity
+)
+
+// The known architecture letters.
+var gochars = "566899"
+
+// The known architectures.
+var okgoarch = []string{
+       // same order as gochars
+       "arm",
+       "amd64",
+       "amd64p32",
+       "386",
+       "ppc64",
+       "ppc64le",
+}
+
+// The known operating systems.
+var okgoos = []string{
+       "darwin",
+       "dragonfly",
+       "linux",
+       "android",
+       "solaris",
+       "freebsd",
+       "nacl",
+       "netbsd",
+       "openbsd",
+       "plan9",
+       "windows",
+}
+
+// find reports the first index of p in l[0:n], or else -1.
+func find(p string, l []string) int {
+       for i, s := range l {
+               if p == s {
+                       return i
+               }
+       }
+       return -1
+}
+
+// xinit handles initialization of the various global state, like goroot and goarch.
+func xinit() {
+       goroot = os.Getenv("GOROOT")
+       if slash == "/" && len(goroot) > 1 || slash == `\` && len(goroot) > 3 {
+               // if not "/" or "c:\", then strip trailing path separator
+               goroot = strings.TrimSuffix(goroot, slash)
+       }
+       if goroot == "" {
+               fatal("$GOROOT must be set")
+       }
+
+       goroot_final = os.Getenv("GOROOT_FINAL")
+       if goroot_final == "" {
+               goroot_final = goroot
+       }
+
+       b := os.Getenv("GOBIN")
+       if b == "" {
+               b = goroot + slash + "bin"
+       }
+       gobin = b
+
+       b = os.Getenv("GOOS")
+       if b == "" {
+               b = gohostos
+       }
+       goos = b
+       if find(goos, okgoos) < 0 {
+               fatal("unknown $GOOS %s", goos)
+       }
+
+       b = os.Getenv("GOARM")
+       if b == "" {
+               b = xgetgoarm()
+       }
+       goarm = b
+
+       b = os.Getenv("GO386")
+       if b == "" {
+               if cansse2() {
+                       b = "sse2"
+               } else {
+                       b = "387"
+               }
+       }
+       go386 = b
+
+       p := pathf("%s/include/u.h", goroot)
+       if !isfile(p) {
+               fatal("$GOROOT is not set correctly or not exported\n"+
+                       "\tGOROOT=%s\n"+
+                       "\t%s does not exist", goroot, p)
+       }
+
+       b = os.Getenv("GOHOSTARCH")
+       if b != "" {
+               gohostarch = b
+       }
+
+       i := find(gohostarch, okgoarch)
+       if i < 0 {
+               fatal("unknown $GOHOSTARCH %s", gohostarch)
+       }
+       gohostchar = gochars[i : i+1]
+
+       b = os.Getenv("GOARCH")
+       if b == "" {
+               b = gohostarch
+       }
+       goarch = b
+       i = find(goarch, okgoarch)
+       if i < 0 {
+               fatal("unknown $GOARCH %s", goarch)
+       }
+       gochar = gochars[i : i+1]
+
+       b = os.Getenv("GO_EXTLINK_ENABLED")
+       if b != "" {
+               if b != "0" && b != "1" {
+                       fatal("unknown $GO_EXTLINK_ENABLED %s", b)
+               }
+               goextlinkenabled = b
+       }
+
+       b = os.Getenv("CC")
+       if b == "" {
+               // Use clang on OS X, because gcc is deprecated there.
+               // Xcode for OS X 10.9 Mavericks will ship a fake "gcc" binary that
+               // actually runs clang. We prepare different command
+               // lines for the two binaries, so it matters what we call it.
+               // See golang.org/issue/5822.
+               if defaultclang {
+                       b = "clang"
+               } else {
+                       b = "gcc"
+               }
+       }
+       defaultcc = b
+
+       defaultcflags = os.Getenv("CFLAGS")
+
+       defaultldflags = os.Getenv("LDFLAGS")
+
+       b = os.Getenv("CC_FOR_TARGET")
+       if b == "" {
+               b = defaultcc
+       }
+       defaultcctarget = b
+
+       b = os.Getenv("CXX_FOR_TARGET")
+       if b == "" {
+               b = os.Getenv("CXX")
+               if b == "" {
+                       if defaultclang {
+                               b = "clang++"
+                       } else {
+                               b = "g++"
+                       }
+               }
+       }
+       defaultcxxtarget = b
+
+       // For tools being invoked but also for os.ExpandEnv.
+       os.Setenv("GO386", go386)
+       os.Setenv("GOARCH", goarch)
+       os.Setenv("GOARM", goarm)
+       os.Setenv("GOHOSTARCH", gohostarch)
+       os.Setenv("GOHOSTOS", gohostos)
+       os.Setenv("GOOS", goos)
+       os.Setenv("GOROOT", goroot)
+       os.Setenv("GOROOT_FINAL", goroot_final)
+
+       // Make the environment more predictable.
+       os.Setenv("LANG", "C")
+       os.Setenv("LANGUAGE", "en_US.UTF8")
+
+       goversion = findgoversion()
+
+       workdir = xworkdir()
+       xatexit(rmworkdir)
+
+       tooldir = pathf("%s/pkg/tool/%s_%s", goroot, gohostos, gohostarch)
+}
+
+// rmworkdir deletes the work directory.
+func rmworkdir() {
+       if vflag > 1 {
+               errprintf("rm -rf %s\n", workdir)
+       }
+       xremoveall(workdir)
+}
+
+// Remove trailing spaces.
+func chomp(s string) string {
+       return strings.TrimRight(s, " \t\r\n")
+}
+
+func branchtag(branch string) (tag string, precise bool) {
+       b := run(goroot, CheckExit, "git", "log", "--decorate=full", "--format=format:%d", "master.."+branch)
+       tag = branch
+       for _, line := range splitlines(b) {
+               // Each line is either blank, or looks like
+               //        (tag: refs/tags/go1.4rc2, refs/remotes/origin/release-branch.go1.4, refs/heads/release-branch.go1.4)
+               // We need to find an element starting with refs/tags/.
+               i := strings.Index(line, " refs/tags/")
+               if i < 0 {
+                       continue
+               }
+               i += len(" refs/tags/")
+               // The tag name ends at a comma or paren (prefer the first).
+               j := strings.Index(line[i:], ",")
+               if j < 0 {
+                       j = strings.Index(line[i:], ")")
+               }
+               if j < 0 {
+                       continue // malformed line; ignore it
+               }
+               tag = line[i : i+j]
+               if i == 0 {
+                       precise = true // tag denotes HEAD
+               }
+               break
+       }
+       return
+}
+
+// findgoversion determines the Go version to use in the version string.
+func findgoversion() string {
+       // The $GOROOT/VERSION file takes priority, for distributions
+       // without the source repo.
+       path := pathf("%s/VERSION", goroot)
+       if isfile(path) {
+               b := chomp(readfile(path))
+               // Commands such as "dist version > VERSION" will cause
+               // the shell to create an empty VERSION file and set dist's
+               // stdout to its fd. dist in turn looks at VERSION and uses
+               // its content if available, which is empty at this point.
+               // Only use the VERSION file if it is non-empty.
+               if b != "" {
+                       return b
+               }
+       }
+
+       // The $GOROOT/VERSION.cache file is a cache to avoid invoking
+       // git every time we run this command.  Unlike VERSION, it gets
+       // deleted by the clean command.
+       path = pathf("%s/VERSION.cache", goroot)
+       if isfile(path) {
+               return chomp(readfile(path))
+       }
+
+       // Otherwise, use Git.
+       // What is the current branch?
+       branch := chomp(run(goroot, CheckExit, "git", "rev-parse", "--abbrev-ref", "HEAD"))
+
+       // What are the tags along the current branch?
+       tag := "devel"
+       precise := false
+
+       // If we're on a release branch, use the closest matching tag
+       // that is on the release branch (and not on the master branch).
+       if strings.HasPrefix(branch, "release-branch.") {
+               tag, precise = branchtag(branch)
+       }
+
+       if !precise {
+               // Tag does not point at HEAD; add hash and date to version.
+               tag += chomp(run(goroot, CheckExit, "git", "log", "-n", "1", "--format=format: +%h %cd", "HEAD"))
+       }
+
+       // Cache version.
+       writefile(tag, path, 0)
+
+       return tag
+}
+
+/*
+ * Initial tree setup.
+ */
+
+// The old tools that no longer live in $GOBIN or $GOROOT/bin.
+var oldtool = []string{
+       "5a", "5c", "5g", "5l",
+       "6a", "6c", "6g", "6l",
+       "8a", "8c", "8g", "8l",
+       "9a", "9c", "9g", "9l",
+       "6cov",
+       "6nm",
+       "6prof",
+       "cgo",
+       "ebnflint",
+       "goapi",
+       "gofix",
+       "goinstall",
+       "gomake",
+       "gopack",
+       "gopprof",
+       "gotest",
+       "gotype",
+       "govet",
+       "goyacc",
+       "quietgcc",
+}
+
+// Unreleased directories (relative to $GOROOT) that should
+// not be in release branches.
+var unreleased = []string{
+       "src/cmd/link",
+       "src/debug/goobj",
+       "src/old",
+}
+
+// setup sets up the tree for the initial build.
+func setup() {
+       // Create bin directory.
+       if p := pathf("%s/bin", goroot); !isdir(p) {
+               xmkdir(p)
+       }
+
+       // Create package directory.
+       if p := pathf("%s/pkg", goroot); !isdir(p) {
+               xmkdir(p)
+       }
+
+       p := pathf("%s/pkg/%s_%s", goroot, gohostos, gohostarch)
+       if rebuildall {
+               xremoveall(p)
+       }
+       xmkdirall(p)
+
+       if goos != gohostos || goarch != gohostarch {
+               p := pathf("%s/pkg/%s_%s", goroot, goos, goarch)
+               if rebuildall {
+                       xremoveall(p)
+               }
+               xmkdirall(p)
+       }
+
+       // Create object directory.
+       // We keep it in pkg/ so that all the generated binaries
+       // are in one tree.  If pkg/obj/libgc.a exists, it is a dreg from
+       // before we used subdirectories of obj.  Delete all of obj
+       // to clean up.
+       if p := pathf("%s/pkg/obj/libgc.a", goroot); isfile(p) {
+               xremoveall(pathf("%s/pkg/obj", goroot))
+       }
+       p = pathf("%s/pkg/obj/%s_%s", goroot, gohostos, gohostarch)
+       if rebuildall {
+               xremoveall(p)
+       }
+       xmkdirall(p)
+
+       // Create tool directory.
+       // We keep it in pkg/, just like the object directory above.
+       if rebuildall {
+               xremoveall(tooldir)
+       }
+       xmkdirall(tooldir)
+
+       // Remove tool binaries from before the tool/gohostos_gohostarch
+       xremoveall(pathf("%s/bin/tool", goroot))
+
+       // Remove old pre-tool binaries.
+       for _, old := range oldtool {
+               xremove(pathf("%s/bin/%s", goroot, old))
+       }
+
+       // If $GOBIN is set and has a Go compiler, it must be cleaned.
+       for _, char := range gochars {
+               if isfile(pathf("%s%s%c%s", gobin, slash, char, "g")) {
+                       for _, old := range oldtool {
+                               xremove(pathf("%s/%s", gobin, old))
+                       }
+                       break
+               }
+       }
+
+       // For release, make sure excluded things are excluded.
+       if strings.HasPrefix(goversion, "release.") || (strings.HasPrefix(goversion, "go") && !strings.Contains(goversion, "beta")) {
+               for _, dir := range unreleased {
+                       if p := pathf("%s/%s", goroot, dir); isdir(p) {
+                               fatal("%s should not exist in release build", p)
+                       }
+               }
+       }
+}
+
+/*
+ * C library and tool building
+ */
+
+// gccargs is the gcc command line to use for compiling a single C file.
+var proto_gccargs = []string{
+       "-Wall",
+       // native Plan 9 compilers don't like non-standard prototypes
+       // so let gcc catch them.
+       "-Wstrict-prototypes",
+       "-Wextra",
+       "-Wunused",
+       "-Wno-sign-compare",
+       "-Wno-missing-braces",
+       "-Wno-parentheses",
+       "-Wno-unknown-pragmas",
+       "-Wno-switch",
+       "-Wno-comment",
+       "-Wno-missing-field-initializers",
+       "-Werror",
+       "-fno-common",
+       "-ggdb",
+       "-pipe",
+}
+
+// gccargs2 is the second part of gccargs.
+// it is used if the environment isn't defining CFLAGS.
+var proto_gccargs2 = []string{
+       // on older versions of GCC, -Wuninitialized is not supported
+       // without -O, so put it here together with -O settings in case
+       // the user's $CFLAGS doesn't include -O.
+       "-Wuninitialized",
+       "-O2",
+}
+
+func init() {
+       if runtime.GOOS == "netbsd" && runtime.GOARCH == "arm" {
+               // GCC 4.5.4 (NetBSD nb1 20120916) on ARM is known to mis-optimize gc/mparith3.c
+               // Fix available at http://patchwork.ozlabs.org/patch/64562/.
+               proto_gccargs2[1] = "-O1"
+       }
+}
+
+var gccargs, ldargs []string
+
+// deptab lists changes to the default dependencies for a given prefix.
+// deps ending in /* read the whole directory; deps beginning with -
+// exclude files with that prefix.
+var deptab = []struct {
+       prefix string   // prefix of target
+       dep    []string // dependency tweaks for targets with that prefix
+}{
+       {"lib9", []string{
+               "$GOROOT/include/u.h",
+               "$GOROOT/include/utf.h",
+               "$GOROOT/include/fmt.h",
+               "$GOROOT/include/libc.h",
+               "fmt/*",
+               "utf/*",
+       }},
+       {"libbio", []string{
+               "$GOROOT/include/u.h",
+               "$GOROOT/include/utf.h",
+               "$GOROOT/include/fmt.h",
+               "$GOROOT/include/libc.h",
+               "$GOROOT/include/bio.h",
+       }},
+       {"liblink", []string{
+               "$GOROOT/include/u.h",
+               "$GOROOT/include/utf.h",
+               "$GOROOT/include/fmt.h",
+               "$GOROOT/include/libc.h",
+               "$GOROOT/include/bio.h",
+               "$GOROOT/include/ar.h",
+               "$GOROOT/include/link.h",
+               "anames5.c",
+               "anames6.c",
+               "anames8.c",
+               "anames9.c",
+       }},
+       {"cmd/gc", []string{
+               "-cplx.c",
+               "-pgen.c",
+               "-plive.c",
+               "-popt.c",
+               "-y1.tab.c", // makefile dreg
+               "opnames.h",
+       }},
+       {"cmd/5g", []string{
+               "../gc/cplx.c",
+               "../gc/pgen.c",
+               "../gc/plive.c",
+               "../gc/popt.c",
+               "../gc/popt.h",
+               "$GOROOT/pkg/obj/${GOHOSTOS}_$GOHOSTARCH/libgc.a",
+       }},
+       {"cmd/6g", []string{
+               "../gc/cplx.c",
+               "../gc/pgen.c",
+               "../gc/plive.c",
+               "../gc/popt.c",
+               "../gc/popt.h",
+               "$GOROOT/pkg/obj/${GOHOSTOS}_$GOHOSTARCH/libgc.a",
+       }},
+       {"cmd/8g", []string{
+               "../gc/cplx.c",
+               "../gc/pgen.c",
+               "../gc/plive.c",
+               "../gc/popt.c",
+               "../gc/popt.h",
+               "$GOROOT/pkg/obj/${GOHOSTOS}_$GOHOSTARCH/libgc.a",
+       }},
+       {"cmd/9g", []string{
+               "../gc/cplx.c",
+               "../gc/pgen.c",
+               "../gc/plive.c",
+               "../gc/popt.c",
+               "../gc/popt.h",
+               "$GOROOT/pkg/obj/${GOHOSTOS}_$GOHOSTARCH/libgc.a",
+       }},
+       {"cmd/5l", []string{
+               "../ld/*",
+       }},
+       {"cmd/6l", []string{
+               "../ld/*",
+       }},
+       {"cmd/8l", []string{
+               "../ld/*",
+       }},
+       {"cmd/9l", []string{
+               "../ld/*",
+       }},
+       {"cmd/go", []string{
+               "zdefaultcc.go",
+       }},
+       {"cmd/", []string{
+               "$GOROOT/pkg/obj/${GOHOSTOS}_$GOHOSTARCH/liblink.a",
+               "$GOROOT/pkg/obj/${GOHOSTOS}_$GOHOSTARCH/libbio.a",
+               "$GOROOT/pkg/obj/${GOHOSTOS}_$GOHOSTARCH/lib9.a",
+       }},
+       {"runtime", []string{
+               "zaexperiment.h",
+               "zversion.go",
+       }},
+}
+
+// depsuffix records the allowed suffixes for source files.
+var depsuffix = []string{
+       ".c",
+       ".h",
+       ".s",
+       ".go",
+}
+
+// gentab records how to generate some trivial files.
+var gentab = []struct {
+       nameprefix string
+       gen        func(string, string)
+}{
+       {"opnames.h", gcopnames},
+       {"anames5.c", mkanames},
+       {"anames6.c", mkanames},
+       {"anames8.c", mkanames},
+       {"anames9.c", mkanames},
+       {"zdefaultcc.go", mkzdefaultcc},
+       {"zversion.go", mkzversion},
+       {"zaexperiment.h", mkzexperiment},
+
+       // not generated anymore, but delete the file if we see it
+       {"enam.c", nil},
+}
+
+// install installs the library, package, or binary associated with dir,
+// which is relative to $GOROOT/src.
+func install(dir string) {
+       if vflag > 0 {
+               if goos != gohostos || goarch != gohostarch {
+                       errprintf("%s (%s/%s)\n", dir, goos, goarch)
+               } else {
+                       errprintf("%s\n", dir)
+               }
+       }
+
+       var clean []string
+       defer func() {
+               for _, name := range clean {
+                       xremove(name)
+               }
+       }()
+
+       // path = full path to dir.
+       path := pathf("%s/src/%s", goroot, dir)
+       name := filepath.Base(dir)
+
+       // set up gcc command line on first run.
+       if gccargs == nil {
+               gccargs = splitfields(defaultcc + " " + defaultcflags)
+               gccargs = append(gccargs, proto_gccargs...)
+               if defaultcflags == "" {
+                       gccargs = append(gccargs, proto_gccargs2...)
+               }
+               if strings.Contains(gccargs[0], "clang") {
+                       // disable ASCII art in clang errors, if possible
+                       gccargs = append(gccargs, "-fno-caret-diagnostics")
+                       // clang is too smart about unused command-line arguments
+                       gccargs = append(gccargs, "-Qunused-arguments")
+               }
+               // disable word wrapping in error messages
+               gccargs = append(gccargs, "-fmessage-length=0")
+               if gohostos == "darwin" {
+                       // golang.org/issue/5261
+                       gccargs = append(gccargs, "-mmacosx-version-min=10.6")
+               }
+       }
+       if ldargs == nil && defaultldflags != "" {
+               ldargs = splitfields(defaultldflags)
+       }
+
+       islib := strings.HasPrefix(dir, "lib") || dir == "cmd/gc"
+       ispkg := !islib && !strings.HasPrefix(dir, "cmd/")
+       isgo := ispkg || dir == "cmd/go" || dir == "cmd/cgo"
+
+       exe := ""
+       if gohostos == "windows" {
+               exe = ".exe"
+       }
+
+       // Start final link command line.
+       // Note: code below knows that link.p[targ] is the target.
+       var (
+               link      []string
+               targ      int
+               ispackcmd bool
+       )
+       switch {
+       case islib:
+               // C library.
+               prefix := ""
+               if !strings.HasPrefix(name, "lib") {
+                       prefix = "lib"
+               }
+               link = []string{"ar", "rsc", pathf("%s/pkg/obj/%s_%s/%s%s.a", goroot, gohostos, gohostarch, prefix, name)}
+               if gohostos == "plan9" {
+                       link[1] = "rc"
+               }
+               targ = len(link) - 1
+
+       case ispkg:
+               // Go library (package).
+               ispackcmd = true
+               link = []string{"pack", pathf("%s/pkg/%s_%s/%s.a", goroot, goos, goarch, dir)}
+               targ = len(link) - 1
+               xmkdirall(filepath.Dir(link[targ]))
+
+       case dir == "cmd/go" || dir == "cmd/cgo":
+               // Go command.
+               elem := name
+               if elem == "go" {
+                       elem = "go_bootstrap"
+               }
+               link = []string{fmt.Sprintf("%s/%sl", tooldir, gochar), "-o", pathf("%s/%s%s", tooldir, elem, exe)}
+               targ = len(link) - 1
+
+       default:
+               // C command. Use gccargs and ldargs.
+               if gohostos == "plan9" {
+                       link = []string{fmt.Sprintf("%sl", gohostchar), "-o", pathf("%s/%s", tooldir, name)}
+                       targ = len(link) - 1
+               } else {
+                       link = append(link, gccargs...)
+                       link = append(link, ldargs...)
+                       if sflag {
+                               link = append(link, "-static")
+                       }
+                       link = append(link, "-o", pathf("%s/%s%s", tooldir, name, exe))
+                       targ = len(link) - 1
+                       switch gohostarch {
+                       case "amd64":
+                               link = append(link, "-m64")
+                       case "386":
+                               link = append(link, "-m32")
+                       }
+               }
+       }
+       ttarg := mtime(link[targ])
+
+       // Gather files that are sources for this target.
+       // Everything in that directory, and any target-specific
+       // additions.
+       files := xreaddir(path)
+
+       // Remove files beginning with . or _,
+       // which are likely to be editor temporary files.
+       // This is the same heuristic build.ScanDir uses.
+       // There do exist real C files beginning with _,
+       // so limit that check to just Go files.
+       files = filter(files, func(p string) bool {
+               return !strings.HasPrefix(p, ".") && (!strings.HasPrefix(p, "_") || !strings.HasSuffix(p, ".go"))
+       })
+
+       var libs []string
+
+       for _, dt := range deptab {
+               if dir == dt.prefix || strings.HasSuffix(dt.prefix, "/") && strings.HasPrefix(dir, dt.prefix) {
+                       for _, p := range dt.dep {
+                               p = os.ExpandEnv(p)
+                               switch {
+                               case strings.HasSuffix(p, ".a"):
+                                       libs = append(libs, p)
+
+                               case strings.HasSuffix(p, "/*"):
+                                       dir := strings.TrimSuffix(p, "/*")
+                                       for _, name := range xreaddir(pathf("%s/%s", path, dir)) {
+                                               files = append(files, pathf("%s/%s", dir, name))
+                                       }
+
+                               case strings.HasPrefix(p, "-"):
+                                       files = filter(files, func(s string) bool {
+                                               return !strings.HasPrefix(s, p[1:])
+                                       })
+
+                               default:
+                                       files = append(files, p)
+                               }
+                       }
+               }
+       }
+       files = uniq(files)
+
+       // Convert to absolute paths.
+       for i, p := range files {
+               if !isabs(p) {
+                       files[i] = pathf("%s/%s", path, p)
+               }
+       }
+
+       // Is the target up-to-date?
+       var gofiles, missing []string
+       stale := rebuildall
+       files = filter(files, func(p string) bool {
+               for _, suf := range depsuffix {
+                       if strings.HasSuffix(p, suf) {
+                               goto ok
+                       }
+               }
+               return false
+       ok:
+               t := mtime(p)
+               if !t.IsZero() && !strings.HasSuffix(p, ".a") && !shouldbuild(p, dir) {
+                       return false
+               }
+               if strings.HasSuffix(p, ".go") {
+                       gofiles = append(gofiles, p)
+               }
+               if t.After(ttarg) {
+                       stale = true
+               }
+               if t.IsZero() {
+                       missing = append(missing, p)
+               }
+               return true
+       })
+
+       // If there are no files to compile, we're done.
+       if len(files) == 0 {
+               return
+       }
+
+       if !stale {
+               for _, p := range libs {
+                       if mtime(p).After(ttarg) {
+                               stale = true
+                               break
+                       }
+               }
+       }
+
+       if !stale {
+               return
+       }
+
+       // For package runtime, copy some files into the work space.
+       if dir == "runtime" {
+               // For use by assembly and C files.
+               copyfile(pathf("%s/pkg/%s_%s/textflag.h", goroot, goos, goarch),
+                       pathf("%s/src/cmd/ld/textflag.h", goroot), 0)
+               copyfile(pathf("%s/pkg/%s_%s/funcdata.h", goroot, goos, goarch),
+                       pathf("%s/src/runtime/funcdata.h", goroot), 0)
+       }
+
+       // Generate any missing files; regenerate existing ones.
+       for _, p := range files {
+               elem := filepath.Base(p)
+               for _, gt := range gentab {
+                       if gt.gen == nil {
+                               continue
+                       }
+                       if strings.HasPrefix(elem, gt.nameprefix) {
+                               if vflag > 1 {
+                                       errprintf("generate %s\n", p)
+                               }
+                               gt.gen(path, p)
+                               // Do not add generated file to clean list.
+                               // In runtime, we want to be able to
+                               // build the package with the go tool,
+                               // and it assumes these generated files already
+                               // exist (it does not know how to build them).
+                               // The 'clean' command can remove
+                               // the generated files.
+                               goto built
+                       }
+               }
+               // Did not rebuild p.
+               if find(p, missing) >= 0 {
+                       fatal("missing file %s", p)
+               }
+       built:
+       }
+
+       if (goos != gohostos || goarch != gohostarch) && isgo {
+               // We've generated the right files; the go command can do the build.
+               if vflag > 1 {
+                       errprintf("skip build for cross-compile %s\n", dir)
+               }
+               return
+       }
+
+       var archive string
+       if isgo {
+               // The next loop will compile individual non-Go files.
+               // Hand the Go files to the compiler en masse.
+               // For package runtime, this writes go_asm.h, which
+               // the assembly files will need.
+               pkg := dir
+               if strings.HasPrefix(dir, "cmd/") {
+                       pkg = "main"
+               }
+               b := pathf("%s/_go_.a", workdir)
+               clean = append(clean, b)
+               if !ispackcmd {
+                       link = append(link, b)
+               } else {
+                       archive = b
+               }
+               compile := []string{pathf("%s/%sg", tooldir, gochar), "-pack", "-o", b, "-p", pkg}
+               if dir == "runtime" {
+                       compile = append(compile, "-+", "-asmhdr", pathf("%s/go_asm.h", workdir))
+               }
+               compile = append(compile, gofiles...)
+               run(path, CheckExit|ShowOutput, compile...)
+       }
+
+       // Compile the files.
+       for _, p := range files {
+               if !strings.HasSuffix(p, ".c") && !strings.HasSuffix(p, ".s") {
+                       continue
+               }
+               name := filepath.Base(p)
+
+               var compile []string
+               if !isgo {
+                       // C library or tool.
+                       if gohostos == "plan9" {
+                               compile = []string{
+                                       gohostchar + "c", "-FTVwp",
+                                       "-DPLAN9",
+                                       "-D__STDC__=1",
+                                       "-D__SIZE_TYPE__=ulong", // for GNU bison
+                                       pathf("-I%s/include/plan9", goroot),
+                                       pathf("-I%s/include/plan9/%s", goroot, gohostarch),
+                               }
+                       } else {
+                               compile = gccargs[0:len(gccargs):len(gccargs)]
+                               compile = append(compile, "-c")
+                               switch gohostarch {
+                               case "amd64":
+                                       compile = append(compile, "-m64")
+                               case "386":
+                                       compile = append(compile, "-m32")
+                               }
+                               compile = append(compile, "-I", pathf("%s/include", goroot))
+                       }
+
+                       if dir == "lib9" {
+                               compile = append(compile, "-DPLAN9PORT")
+                       }
+
+                       compile = append(compile, "-I", path)
+
+                       // lib9/goos.c gets the default constants hard-coded.
+                       if name == "goos.c" {
+                               compile = append(compile,
+                                       "-D", fmt.Sprintf("GOOS=%q", goos),
+                                       "-D", fmt.Sprintf("GOARCH=%q", goarch),
+                                       "-D", fmt.Sprintf("GOROOT=%q", goroot_final),
+                                       "-D", fmt.Sprintf("GOVERSION=%q", goversion),
+                                       "-D", fmt.Sprintf("GOARM=%q", goarm),
+                                       "-D", fmt.Sprintf("GO386=%q", go386),
+                                       "-D", fmt.Sprintf("GO_EXTLINK_ENABLED=%q", goextlinkenabled),
+                               )
+                       }
+
+                       // gc/lex.c records the GOEXPERIMENT setting used during the build.
+                       if name == "lex.c" {
+                               compile = append(compile,
+                                       "-D", fmt.Sprintf("GOEXPERIMENT=%q", os.Getenv("GOEXPERIMENT")))
+                       }
+               } else {
+                       // Assembly file for a Go package.
+                       compile = []string{
+                               pathf("%s/%sa", tooldir, gochar),
+                               "-I", workdir,
+                               "-I", pathf("%s/pkg/%s_%s", goroot, goos, goarch),
+                               "-D", "GOOS_" + goos,
+                               "-D", "GOARCH_" + goarch,
+                               "-D", "GOOS_GOARCH_" + goos + "_" + goarch,
+                       }
+               }
+
+               doclean := true
+               b := pathf("%s/%s", workdir, filepath.Base(p))
+               if !isgo && gohostos == "darwin" {
+                       // To debug C programs on OS X, it is not enough to say -ggdb
+                       // on the command line.  You have to leave the object files
+                       // lying around too.  Leave them in pkg/obj/, which does not
+                       // get removed when this tool exits.
+                       obj := pathf("%s/pkg/obj/%s", goroot, dir)
+                       xmkdirall(obj)
+                       b = pathf("%s/%s", obj, filepath.Base(p))
+                       doclean = false
+               }
+
+               // Change the last character of the output file (which was c or s).
+               if gohostos == "plan9" {
+                       b = b[:len(b)-1] + gohostchar
+               } else {
+                       b = b[:len(b)-1] + "o"
+               }
+               compile = append(compile, "-o", b, p)
+               bgrun(path, compile...)
+
+               link = append(link, b)
+               if doclean {
+                       clean = append(clean, b)
+               }
+       }
+       bgwait()
+
+       if isgo && ispackcmd {
+               xremove(link[targ])
+               dopack(link[targ], archive, link[targ+1:])
+               return
+       }
+
+       if !islib && !isgo {
+               // C binaries need the libraries explicitly, and -lm.
+               link = append(link, libs...)
+               if gohostos != "plan9" {
+                       link = append(link, "-lm")
+               }
+       }
+
+       // Remove target before writing it.
+       xremove(link[targ])
+       run("", CheckExit|ShowOutput, link...)
+}
+
+// matchfield reports whether the field matches this build.
+func matchfield(f string) bool {
+       for _, tag := range strings.Split(f, ",") {
+               if tag == goos || tag == goarch || tag == "cmd_go_bootstrap" || tag == "go1.1" || (goos == "android" && tag == "linux") {
+                       continue
+               }
+               return false
+       }
+       return true
+}
+
+// shouldbuild reports whether we should build this file.
+// It applies the same rules that are used with context tags
+// in package go/build, except that the GOOS and GOARCH
+// can appear anywhere in the file name, not just after _.
+// In particular, they can be the entire file name (like windows.c).
+// We also allow the special tag cmd_go_bootstrap.
+// See ../go/bootstrap.go and package go/build.
+func shouldbuild(file, dir string) bool {
+       // Check file name for GOOS or GOARCH.
+       name := filepath.Base(file)
+       excluded := func(list []string, ok string) bool {
+               for _, x := range list {
+                       if x == ok {
+                               continue
+                       }
+                       i := strings.Index(name, x)
+                       if i < 0 {
+                               continue
+                       }
+                       i += len(x)
+                       if i == len(name) || name[i] == '.' || name[i] == '_' {
+                               return true
+                       }
+               }
+               return false
+       }
+       if excluded(okgoos, goos) || excluded(okgoarch, goarch) {
+               return false
+       }
+
+       // Omit test files.
+       if strings.Contains(name, "_test") {
+               return false
+       }
+
+       // cmd/go/doc.go has a giant /* */ comment before
+       // it gets to the important detail that it is not part of
+       // package main.  We don't parse those comments,
+       // so special case that file.
+       if strings.HasSuffix(file, "cmd/go/doc.go") || strings.HasSuffix(file, "cmd\\go\\doc.go") {
+               return false
+       }
+       if strings.HasSuffix(file, "cmd/cgo/doc.go") || strings.HasSuffix(file, "cmd\\cgo\\doc.go") {
+               return false
+       }
+
+       // Check file contents for // +build lines.
+       for _, p := range splitlines(readfile(file)) {
+               p = strings.TrimSpace(p)
+               if p == "" {
+                       continue
+               }
+               if strings.Contains(p, "package documentation") {
+                       return false
+               }
+               if strings.Contains(p, "package main") && dir != "cmd/go" && dir != "cmd/cgo" {
+                       return false
+               }
+               if !strings.HasPrefix(p, "//") {
+                       break
+               }
+               if !strings.Contains(p, "+build") {
+                       continue
+               }
+               fields := splitfields(p)
+               if len(fields) < 2 || fields[1] != "+build" {
+                       continue
+               }
+               for _, p := range fields[2:] {
+                       if (p[0] == '!' && !matchfield(p[1:])) || matchfield(p) {
+                               goto fieldmatch
+                       }
+               }
+               return false
+       fieldmatch:
+       }
+
+       return true
+}
+
+// copy copies the file src to dst, via memory (so only good for small files).
+func copyfile(dst, src string, exec int) {
+       if vflag > 1 {
+               errprintf("cp %s %s\n", src, dst)
+       }
+       writefile(readfile(src), dst, exec)
+}
+
+// dopack copies the package src to dst,
+// appending the files listed in extra.
+// The archive format is the traditional Unix ar format.
+func dopack(dst, src string, extra []string) {
+       bdst := bytes.NewBufferString(readfile(src))
+       for _, file := range extra {
+               b := readfile(file)
+               // find last path element for archive member name
+               i := strings.LastIndex(file, "/") + 1
+               j := strings.LastIndex(file, `\`) + 1
+               if i < j {
+                       i = j
+               }
+               fmt.Fprintf(bdst, "%-16.16s%-12d%-6d%-6d%-8o%-10d`\n", file[i:], 0, 0, 0, 0644, len(b))
+               bdst.WriteString(b)
+               if len(b)&1 != 0 {
+                       bdst.WriteByte(0)
+               }
+       }
+       writefile(bdst.String(), dst, 0)
+}
+
+// buildorder records the order of builds for the 'go bootstrap' command.
+var buildorder = []string{
+       "lib9",
+       "libbio",
+       "liblink",
+
+       "cmd/gc",  // must be before g
+       "cmd/%sl", // must be before a, g
+       "cmd/%sa",
+       "cmd/%sg",
+
+       // The dependency order here was copied from a buildscript
+       // back when there were build scripts.  Will have to
+       // be maintained by hand, but shouldn't change very
+       // often.
+       "runtime",
+       "errors",
+       "sync/atomic",
+       "sync",
+       "io",
+       "unicode",
+       "unicode/utf8",
+       "unicode/utf16",
+       "bytes",
+       "math",
+       "strings",
+       "strconv",
+       "bufio",
+       "sort",
+       "container/heap",
+       "encoding/base64",
+       "syscall",
+       "time",
+       "os",
+       "reflect",
+       "fmt",
+       "encoding",
+       "encoding/json",
+       "flag",
+       "path/filepath",
+       "path",
+       "io/ioutil",
+       "log",
+       "regexp/syntax",
+       "regexp",
+       "go/token",
+       "go/scanner",
+       "go/ast",
+       "go/parser",
+       "os/exec",
+       "os/signal",
+       "net/url",
+       "text/template/parse",
+       "text/template",
+       "go/doc",
+       "go/build",
+       "cmd/go",
+}
+
+// cleantab records the directories to clean in 'go clean'.
+// It is bigger than the buildorder because we clean all the
+// compilers but build only the $GOARCH ones.
+var cleantab = []string{
+       // Commands and C libraries.
+       "cmd/5a",
+       "cmd/5g",
+       "cmd/5l",
+       "cmd/6a",
+       "cmd/6g",
+       "cmd/6l",
+       "cmd/8a",
+       "cmd/8g",
+       "cmd/8l",
+       "cmd/9a",
+       "cmd/9g",
+       "cmd/9l",
+       "cmd/gc",
+       "cmd/go",
+       "lib9",
+       "libbio",
+       "liblink",
+
+       // Go packages.
+       "bufio",
+       "bytes",
+       "container/heap",
+       "encoding",
+       "encoding/base64",
+       "encoding/json",
+       "errors",
+       "flag",
+       "fmt",
+       "go/ast",
+       "go/build",
+       "go/doc",
+       "go/parser",
+       "go/scanner",
+       "go/token",
+       "io",
+       "io/ioutil",
+       "log",
+       "math",
+       "net/url",
+       "os",
+       "os/exec",
+       "path",
+       "path/filepath",
+       "reflect",
+       "regexp",
+       "regexp/syntax",
+       "runtime",
+       "sort",
+       "strconv",
+       "strings",
+       "sync",
+       "sync/atomic",
+       "syscall",
+       "text/template",
+       "text/template/parse",
+       "time",
+       "unicode",
+       "unicode/utf16",
+       "unicode/utf8",
+}
+
+var runtimegen = []string{
+       "zaexperiment.h",
+       "zversion.go",
+}
+
+func clean() {
+       for _, name := range cleantab {
+               path := pathf("%s/src/%s", goroot, name)
+               // Remove generated files.
+               for _, elem := range xreaddir(path) {
+                       for _, gt := range gentab {
+                               if strings.HasPrefix(elem, gt.nameprefix) {
+                                       xremove(pathf("%s/%s", path, elem))
+                               }
+                       }
+               }
+               // Remove generated binary named for directory.
+               if strings.HasPrefix(name, "cmd/") {
+                       xremove(pathf("%s/%s", path, name[4:]))
+               }
+       }
+
+       // remove runtimegen files.
+       path := pathf("%s/src/runtime", goroot)
+       for _, elem := range runtimegen {
+               xremove(pathf("%s/%s", path, elem))
+       }
+
+       if rebuildall {
+               // Remove object tree.
+               xremoveall(pathf("%s/pkg/obj/%s_%s", goroot, gohostos, gohostarch))
+
+               // Remove installed packages and tools.
+               xremoveall(pathf("%s/pkg/%s_%s", goroot, gohostos, gohostarch))
+               xremoveall(pathf("%s/pkg/%s_%s", goroot, goos, goarch))
+               xremoveall(tooldir)
+
+               // Remove cached version info.
+               xremove(pathf("%s/VERSION.cache", goroot))
+       }
+}
+
+/*
+ * command implementations
+ */
+
+func usage() {
+       xprintf("usage: go tool dist [command]\n" +
+               "Commands are:\n" +
+               "\n" +
+               "banner         print installation banner\n" +
+               "bootstrap      rebuild everything\n" +
+               "clean          deletes all built files\n" +
+               "env [-p]       print environment (-p: include $PATH)\n" +
+               "install [dir]  install individual directory\n" +
+               "version        print Go version\n" +
+               "\n" +
+               "All commands take -v flags to emit extra information.\n",
+       )
+       xexit(2)
+}
+
+// The env command prints the default environment.
+func cmdenv() {
+       path := flag.Bool("p", false, "emit updated PATH")
+       plan9 := flag.Bool("9", false, "emit plan 9 syntax")
+       windows := flag.Bool("w", false, "emit windows syntax")
+       xflagparse(0)
+
+       format := "%s=\"%s\"\n"
+       switch {
+       case *plan9:
+               format = "%s='%s'\n"
+       case *windows:
+               format = "set %s=%s\r\n"
+       }
+
+       xprintf(format, "CC", defaultcc)
+       xprintf(format, "CC_FOR_TARGET", defaultcctarget)
+       xprintf(format, "GOROOT", goroot)
+       xprintf(format, "GOBIN", gobin)
+       xprintf(format, "GOARCH", goarch)
+       xprintf(format, "GOOS", goos)
+       xprintf(format, "GOHOSTARCH", gohostarch)
+       xprintf(format, "GOHOSTOS", gohostos)
+       xprintf(format, "GOTOOLDIR", tooldir)
+       xprintf(format, "GOCHAR", gochar)
+       if goarch == "arm" {
+               xprintf(format, "GOARM", goarm)
+       }
+       if goarch == "386" {
+               xprintf(format, "GO386", go386)
+       }
+
+       if *path {
+               sep := ":"
+               if gohostos == "windows" {
+                       sep = ";"
+               }
+               xprintf(format, "PATH", fmt.Sprintf("%s%s%s", gobin, sep, os.Getenv("PATH")))
+       }
+}
+
+// The bootstrap command runs a build from scratch,
+// stopping at having installed the go_bootstrap command.
+func cmdbootstrap() {
+       flag.BoolVar(&rebuildall, "a", rebuildall, "rebuild all")
+       flag.BoolVar(&sflag, "s", sflag, "build static binaries")
+       xflagparse(0)
+
+       if isdir(pathf("%s/src/pkg", goroot)) {
+               fatal("\n\n"+
+                       "The Go package sources have moved to $GOROOT/src.\n"+
+                       "*** %s still exists. ***\n"+
+                       "It probably contains stale files that may confuse the build.\n"+
+                       "Please (check what's there and) remove it and try again.\n"+
+                       "See http://golang.org/s/go14nopkg\n",
+                       pathf("%s/src/pkg", goroot))
+       }
+
+       if rebuildall {
+               clean()
+       }
+
+       setup()
+
+       // For the main bootstrap, building for host os/arch.
+       oldgoos = goos
+       oldgoarch = goarch
+       oldgochar = gochar
+       goos = gohostos
+       goarch = gohostarch
+       gochar = gohostchar
+       os.Setenv("GOHOSTARCH", gohostarch)
+       os.Setenv("GOHOSTOS", gohostos)
+       os.Setenv("GOARCH", goarch)
+       os.Setenv("GOOS", goos)
+
+       for _, pattern := range buildorder {
+               dir := pattern
+               if strings.Contains(pattern, "%s") {
+                       dir = fmt.Sprintf(pattern, gohostchar)
+               }
+               install(dir)
+               if oldgochar != gohostchar && strings.Contains(pattern, "%s") {
+                       install(fmt.Sprintf(pattern, oldgochar))
+               }
+       }
+
+       goos = oldgoos
+       goarch = oldgoarch
+       gochar = oldgochar
+       os.Setenv("GOARCH", goarch)
+       os.Setenv("GOOS", goos)
+
+       // Build runtime for actual goos/goarch too.
+       if goos != gohostos || goarch != gohostarch {
+               install("runtime")
+       }
+}
+
+func defaulttarg() string {
+       // xgetwd might return a path with symlinks fully resolved, and if
+       // there happens to be symlinks in goroot, then the hasprefix test
+       // will never succeed. Instead, we use xrealwd to get a canonical
+       // goroot/src before the comparison to avoid this problem.
+       pwd := xgetwd()
+       src := pathf("%s/src/", goroot)
+       real_src := xrealwd(src)
+       if !strings.HasPrefix(pwd, real_src) {
+               fatal("current directory %s is not under %s", pwd, real_src)
+       }
+       pwd = pwd[len(real_src):]
+       // guard againt xrealwd return the directory without the trailing /
+       pwd = strings.TrimPrefix(pwd, "/")
+
+       return pwd
+}
+
+// Install installs the list of packages named on the command line.
+func cmdinstall() {
+       flag.BoolVar(&sflag, "s", sflag, "build static binaries")
+       xflagparse(-1)
+
+       if flag.NArg() == 0 {
+               install(defaulttarg())
+       }
+
+       for _, arg := range flag.Args() {
+               install(arg)
+       }
+}
+
+// Clean deletes temporary objects.
+func cmdclean() {
+       xflagparse(0)
+       clean()
+}
+
+// Banner prints the 'now you've installed Go' banner.
+func cmdbanner() {
+       xflagparse(0)
+
+       xprintf("\n")
+       xprintf("---\n")
+       xprintf("Installed Go for %s/%s in %s\n", goos, goarch, goroot)
+       xprintf("Installed commands in %s\n", gobin)
+
+       if !xsamefile(goroot_final, goroot) {
+               // If the files are to be moved, don't check that gobin
+               // is on PATH; assume they know what they are doing.
+       } else if gohostos == "plan9" {
+               // Check that gobin is bound before /bin.
+               pid := strings.Replace(readfile("#c/pid"), " ", "", -1)
+               ns := fmt.Sprintf("/proc/%s/ns", pid)
+               if !strings.Contains(readfile(ns), fmt.Sprintf("bind -b %s /bin", gobin)) {
+                       xprintf("*** You need to bind %s before /bin.\n", gobin)
+               }
+       } else {
+               // Check that gobin appears in $PATH.
+               pathsep := ":"
+               if gohostos == "windows" {
+                       pathsep = ";"
+               }
+               if !strings.Contains(pathsep+os.Getenv("PATH")+pathsep, pathsep+gobin+pathsep) {
+                       xprintf("*** You need to add %s to your PATH.\n", gobin)
+               }
+       }
+
+       if !xsamefile(goroot_final, goroot) {
+               xprintf("\n"+
+                       "The binaries expect %s to be copied or moved to %s\n",
+                       goroot, goroot_final)
+       }
+}
+
+// Version prints the Go version.
+func cmdversion() {
+       xflagparse(0)
+       xprintf("%s\n", goversion)
+}
diff --git a/src/cmd/dist/buildgc.c b/src/cmd/dist/buildgc.c
deleted file mode 100644 (file)
index 64434d5..0000000
+++ /dev/null
@@ -1,218 +0,0 @@
-// Copyright 2012 The Go Authors.  All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-#include "a.h"
-
-/*
- * Helpers for building cmd/gc.
- */
-
-// gcopnames creates opnames.h from go.h.
-// It finds the OXXX enum, pulls out all the constants
-// from OXXX to OEND, and writes a table mapping
-// op to string.
-void
-gcopnames(char *dir, char *file)
-{
-       char *p, *q;
-       int i, j, end;
-       Buf in, b, out;
-       Vec lines, fields;
-       
-       binit(&in);
-       binit(&b);
-       binit(&out);
-       vinit(&lines);
-       vinit(&fields);
-       
-       bwritestr(&out, bprintf(&b, "// auto generated by go tool dist\n"));
-       bwritestr(&out, bprintf(&b, "static char *opnames[] = {\n"));
-
-       readfile(&in, bprintf(&b, "%s/go.h", dir));
-       splitlines(&lines, bstr(&in));
-       i = 0;
-       while(i<lines.len && !contains(lines.p[i], "OXXX"))
-               i++;
-       end = 0;
-       for(; i<lines.len && !end; i++) {
-               p = xstrstr(lines.p[i], "//");
-               if(p != nil)
-                       *p = '\0';
-               end = contains(lines.p[i], "OEND");
-               splitfields(&fields, lines.p[i]);
-               for(j=0; j<fields.len; j++) {
-                       q = fields.p[j];
-                       if(*q == 'O')
-                               q++;
-                       p = q+xstrlen(q)-1;
-                       if(*p == ',')
-                               *p = '\0';
-                       bwritestr(&out, bprintf(&b, "   [O%s] = \"%s\",\n", q, q));
-               }
-       }
-       
-       bwritestr(&out, bprintf(&b, "};\n"));
-
-       writefile(&out, file, 0);
-
-       bfree(&in);
-       bfree(&b);
-       bfree(&out);
-       vfree(&lines);
-       vfree(&fields);
-}
-
-static int
-xatoi(char *s, char **end)
-{
-       int val = 0;
-       for(; *s && *s >= '0' && *s <= '9'; ++s)
-               val = val * 10 + (*s - '0');
-       *end = s;
-       return val;
-}
-
-// mkanames reads [5689].out.h and writes anames[5689].c
-// The format is much the same as the Go opcodes above.
-// It also writes out cnames array for C_* constants and the dnames
-// array for D_* constants.
-void
-mkanames(char *dir, char *file)
-{
-       int i, j, ch, n, unknown;
-       Buf in, b, out, out2;
-       Vec lines;
-       char *p, *p2;
-       Vec dnames[128];
-
-       binit(&b);
-       binit(&in);
-       binit(&out);
-       binit(&out2);
-       vinit(&lines);
-       for(i=0; i<nelem(dnames); i++)
-               vinit(&dnames[i]);
-
-       ch = file[xstrlen(file)-3];
-       bprintf(&b, "%s/../cmd/%cl/%c.out.h", dir, ch, ch);
-       readfile(&in, bstr(&b));
-       splitlines(&lines, bstr(&in));
-       
-       // Include link.h so that the extern declaration there is
-       // checked against the non-extern declaration we are generating.
-       bwritestr(&out, bprintf(&b, "// auto generated by go tool dist\n"));
-       bwritestr(&out, bprintf(&b, "#include <u.h>\n"));
-       bwritestr(&out, bprintf(&b, "#include <libc.h>\n"));
-       bwritestr(&out, bprintf(&b, "#include <bio.h>\n"));
-       bwritestr(&out, bprintf(&b, "#include <link.h>\n"));
-       bwritestr(&out, bprintf(&b, "#include \"../cmd/%cl/%c.out.h\"\n", ch, ch));
-       bwritestr(&out, bprintf(&b, "\n"));
-
-       bwritestr(&out, bprintf(&b, "char*      anames%c[] = {\n", ch));
-       for(i=0; i<lines.len; i++) {
-               if(hasprefix(lines.p[i], "\tA")) {
-                       p = xstrstr(lines.p[i], ",");
-                       if(p)
-                               *p = '\0';
-                       p = xstrstr(lines.p[i], "\n");
-                       if(p)
-                               *p = '\0';
-                       p = lines.p[i] + 2;
-                       bwritestr(&out, bprintf(&b, "\t\"%s\",\n", p));
-               }
-       }
-       bwritestr(&out, "};\n");
-
-       j=0;
-       bprintf(&out2, "char*   cnames%c[] = {\n", ch);
-       for(i=0; i<lines.len; i++) {
-               if(hasprefix(lines.p[i], "\tC_")) {
-                       p = xstrstr(lines.p[i], ",");
-                       if(p)
-                               *p = '\0';
-                       p = xstrstr(lines.p[i], "\n");
-                       if(p)
-                               *p = '\0';
-                       p = lines.p[i] + 3;
-                       bwritestr(&out2, bprintf(&b, "\t\"%s\",\n", p));
-                       j++;
-               }
-       }
-       bwritestr(&out2, "};\n");
-       if(j>0)
-               bwriteb(&out, &out2);
-
-       j=unknown=0;
-       n=-1;
-       for(i=0; i<lines.len; i++) {
-               if(hasprefix(lines.p[i], "\tD_")) {
-                       p = xstrstr(lines.p[i], ",");
-                       if(p)
-                               *p = '\0';
-                       p = xstrstr(lines.p[i], "\n");
-                       if(p)
-                               *p = '\0';
-
-                       // Parse explicit value, if any
-                       p = xstrstr(lines.p[i], "=");
-                       if(p) {
-                               // Skip space after '='
-                               p2 = p + 1;
-                               while(*p2 == ' ' || *p2 == '\t')
-                                       p2++;
-                               n = xatoi(p2, &p2);
-                               // We can't do anything about
-                               // non-numeric values or anything that
-                               // follows
-                               while(*p2 == ' ' || *p2 == '\t')
-                                       p2++;
-                               if(*p2 != 0) {
-                                       unknown = 1;
-                                       continue;
-                               }
-                               // Truncate space before '='
-                               while(*(p-1) == ' ' || *(p-1) == '\t')
-                                       p--;
-                               *p = '\0';
-                               unknown = 0;
-                       } else {
-                               n++;
-                       }
-
-                       if(unknown || n >= nelem(dnames))
-                               continue;
-
-                       p = lines.p[i] + 3;
-                       if(xstrcmp(p, "LAST") == 0)
-                               continue;
-                       vadd(&dnames[n], p);
-                       j++;
-               }
-       }
-       if(j>0){
-               bwritestr(&out, bprintf(&b, "char*      dnames%c[D_LAST] = {\n", ch));
-               for(i=0; i<nelem(dnames); i++) {
-                       if(dnames[i].len == 0)
-                               continue;
-                       bwritestr(&out, bprintf(&b, "\t[D_%s] = \"", dnames[i].p[0]));
-                       for(j=0; j<dnames[i].len; j++) {
-                               if(j != 0)
-                                       bwritestr(&out, "/");
-                               bwritestr(&out, dnames[i].p[j]);
-                       }
-                       bwritestr(&out, "\",\n");
-               }
-               bwritestr(&out, "};\n");
-       }
-
-       writefile(&out, file, 0);
-
-       bfree(&b);
-       bfree(&in);
-       bfree(&out);
-       bfree(&out2);
-       vfree(&lines);
-       for(i=0; i<nelem(dnames); i++)
-               vfree(&dnames[i]);
-}
diff --git a/src/cmd/dist/buildgc.go b/src/cmd/dist/buildgc.go
new file mode 100644 (file)
index 0000000..b1b5d5e
--- /dev/null
@@ -0,0 +1,170 @@
+// Copyright 2012 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+       "bytes"
+       "fmt"
+       "strconv"
+       "strings"
+)
+
+/*
+ * Helpers for building cmd/gc.
+ */
+
+// gcopnames creates opnames.h from go.h.
+// It finds the OXXX enum, pulls out all the constants
+// from OXXX to OEND, and writes a table mapping
+// op to string.
+func gcopnames(dir, file string) {
+       var out bytes.Buffer
+       fmt.Fprintf(&out, "// auto generated by go tool dist\n")
+       fmt.Fprintf(&out, "static char *opnames[] = {\n")
+
+       in := readfile(pathf("%s/go.h", dir))
+       lines := splitlines(in)
+       i := 0
+       for i < len(lines) && !strings.Contains(lines[i], "OXXX") {
+               i++
+       }
+       for _, line := range lines[i:] {
+               if i := strings.Index(line, "//"); i >= 0 {
+                       line = line[:i]
+               }
+               for _, field := range splitfields(line) {
+                       field = strings.TrimPrefix(field, "O")
+                       field = strings.TrimSuffix(field, ",")
+                       fmt.Fprintf(&out, "\t[O%s] = \"%s\",\n", field, field)
+               }
+               if strings.Contains(line, "OEND") {
+                       break
+               }
+       }
+       fmt.Fprintf(&out, "};\n")
+
+       writefile(out.String(), file, 0)
+}
+
+// mkanames reads [5689].out.h and writes anames[5689].c
+// The format is much the same as the Go opcodes above.
+// It also writes out cnames array for C_* constants and the dnames
+// array for D_* constants.
+func mkanames(dir, file string) {
+       ch := file[len(file)-3]
+       targ := pathf("%s/../cmd/%cl/%c.out.h", dir, ch, ch)
+       in := readfile(targ)
+       lines := splitlines(in)
+
+       // Include link.h so that the extern declaration there is
+       // checked against the non-extern declaration we are generating.
+       var out bytes.Buffer
+       fmt.Fprintf(&out, "// auto generated by go tool dist\n")
+       fmt.Fprintf(&out, "#include <u.h>\n")
+       fmt.Fprintf(&out, "#include <libc.h>\n")
+       fmt.Fprintf(&out, "#include <bio.h>\n")
+       fmt.Fprintf(&out, "#include <link.h>\n")
+       fmt.Fprintf(&out, "#include \"../cmd/%cl/%c.out.h\"\n", ch, ch)
+       fmt.Fprintf(&out, "\n")
+
+       fmt.Fprintf(&out, "char*        anames%c[] = {\n", ch)
+       for _, line := range lines {
+               if strings.HasPrefix(line, "\tA") {
+                       if i := strings.Index(line, ","); i >= 0 {
+                               line = line[:i]
+                       }
+                       if i := strings.Index(line, "\n"); i >= 0 {
+                               line = line[:i]
+                       }
+                       line = line[2:]
+                       fmt.Fprintf(&out, "\t\"%s\",\n", line)
+               }
+       }
+       fmt.Fprintf(&out, "};\n")
+
+       j := 0
+       var out2 bytes.Buffer
+       fmt.Fprintf(&out2, "char*       cnames%c[] = {\n", ch)
+       for _, line := range lines {
+               if strings.HasPrefix(line, "\tC_") {
+                       if i := strings.Index(line, ","); i >= 0 {
+                               line = line[:i]
+                       }
+                       if i := strings.Index(line, "\n"); i >= 0 {
+                               line = line[:i]
+                       }
+                       line = line[3:]
+                       fmt.Fprintf(&out2, "\t\"%s\",\n", line)
+                       j++
+               }
+       }
+       fmt.Fprintf(&out2, "};\n")
+       if j > 0 {
+               out.Write(out2.Bytes())
+       }
+
+       var dnames [128][]string
+       j = 0
+       unknown := false
+       n := -1
+       for _, line := range lines {
+               if strings.HasPrefix(line, "\tD_") {
+                       if i := strings.Index(line, ","); i >= 0 {
+                               line = line[:i]
+                       }
+
+                       // Parse explicit value, if any
+                       if i := strings.Index(line, "="); i >= 0 {
+                               value := strings.TrimSpace(line[i+1:])
+                               line = strings.TrimSpace(line[:i])
+                               var err error
+                               n, err = strconv.Atoi(value)
+                               if err != nil {
+                                       // We can't do anything about
+                                       // non-numeric values or anything that
+                                       // follows.
+                                       unknown = true
+                                       continue
+                               }
+                               unknown = false
+                       } else {
+                               n++
+                       }
+
+                       if unknown || n < 0 || n >= len(dnames) {
+                               continue
+                       }
+
+                       line = strings.TrimSpace(line)
+                       line = line[len("D_"):]
+
+                       if strings.Contains(line, "LAST") {
+                               continue
+                       }
+                       dnames[n] = append(dnames[n], line)
+                       j++
+               }
+       }
+
+       if j > 0 {
+               fmt.Fprintf(&out, "char*        dnames%c[D_LAST] = {\n", ch)
+               for _, d := range dnames {
+                       if len(d) == 0 {
+                               continue
+                       }
+                       fmt.Fprintf(&out, "\t[D_%s] = \"", d[0])
+                       for k, name := range d {
+                               if k > 0 {
+                                       fmt.Fprintf(&out, "/")
+                               }
+                               fmt.Fprintf(&out, "%s", name)
+                       }
+                       fmt.Fprintf(&out, "\",\n")
+               }
+               fmt.Fprintf(&out, "};\n")
+       }
+
+       writefile(out.String(), file, 0)
+}
diff --git a/src/cmd/dist/buildgo.c b/src/cmd/dist/buildgo.c
deleted file mode 100644 (file)
index 41208fa..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-// Copyright 2012 The Go Authors.  All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-#include "a.h"
-
-/*
- * Helpers for building cmd/go and cmd/cgo.
- */
-
-// mkzdefaultcc writes zdefaultcc.go:
-//
-//     package main
-//     const defaultCC = <defaultcc>
-//     const defaultCXX = <defaultcxx>
-//
-// It is invoked to write cmd/go/zdefaultcc.go
-// but we also write cmd/cgo/zdefaultcc.go.
-void
-mkzdefaultcc(char *dir, char *file)
-{
-       Buf b, out;
-       
-       USED(dir);
-
-       binit(&out);
-       bprintf(&out,
-               "// auto generated by go tool dist\n"
-               "\n"
-               "package main\n"
-               "\n"
-               "const defaultCC = `%s`\n"
-               "const defaultCXX = `%s`\n",
-               defaultcctarget, defaultcxxtarget);
-
-       writefile(&out, file, 0);
-
-       // Convert file name to replace.
-       binit(&b);      
-       bwritestr(&b, file);
-       if(slash[0] == '/')
-               bsubst(&b, "/go/zdefaultcc.go", "/cgo/zdefaultcc.go");
-       else
-               bsubst(&b, "\\go\\zdefaultcc.go", "\\cgo\\zdefaultcc.go");
-       writefile(&out, bstr(&b), 0);
-
-       bfree(&b);
-       bfree(&out);
-}
diff --git a/src/cmd/dist/buildgo.go b/src/cmd/dist/buildgo.go
new file mode 100644 (file)
index 0000000..9cc6508
--- /dev/null
@@ -0,0 +1,39 @@
+// Copyright 2012 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "fmt"
+
+/*
+ * Helpers for building cmd/go and cmd/cgo.
+ */
+
+// mkzdefaultcc writes zdefaultcc.go:
+//
+//     package main
+//     const defaultCC = <defaultcc>
+//     const defaultCXX = <defaultcxx>
+//
+// It is invoked to write cmd/go/zdefaultcc.go
+// but we also write cmd/cgo/zdefaultcc.go
+func mkzdefaultcc(dir, file string) {
+       var out string
+
+       out = fmt.Sprintf(
+               "// auto generated by go tool dist\n"+
+                       "\n"+
+                       "package main\n"+
+                       "\n"+
+                       "const defaultCC = `%s`\n"+
+                       "const defaultCXX = `%s`\n",
+               defaultcctarget, defaultcxxtarget)
+
+       writefile(out, file, 0)
+
+       // Convert file name to replace: turn go into cgo.
+       i := len(file) - len("go/zdefaultcc.go")
+       file = file[:i] + "c" + file[i:]
+       writefile(out, file, 0)
+}
diff --git a/src/cmd/dist/buildruntime.c b/src/cmd/dist/buildruntime.c
deleted file mode 100644 (file)
index add6897..0000000
+++ /dev/null
@@ -1,68 +0,0 @@
-// Copyright 2012 The Go Authors.  All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-#include "a.h"
-
-/*
- * Helpers for building runtime.
- */
-
-// mkzversion writes zversion.go:
-//
-//     package runtime
-//     const defaultGoroot = <goroot>
-//     const theVersion = <version>
-//
-void
-mkzversion(char *dir, char *file)
-{
-       Buf b, out;
-       
-       USED(dir);
-
-       binit(&b);
-       binit(&out);
-       
-       bwritestr(&out, bprintf(&b,
-               "// auto generated by go tool dist\n"
-               "\n"
-               "package runtime\n"
-               "\n"
-               "const defaultGoroot = `%s`\n"
-               "const theVersion = `%s`\n"
-               "var buildVersion = theVersion\n", goroot_final, goversion));
-
-       writefile(&out, file, 0);
-       
-       bfree(&b);
-       bfree(&out);
-}
-
-// mkzexperiment writes zaexperiment.h (sic):
-//
-//     #define GOEXPERIMENT "experiment string"
-//
-void
-mkzexperiment(char *dir, char *file)
-{
-       Buf b, out, exp;
-       
-       USED(dir);
-
-       binit(&b);
-       binit(&out);
-       binit(&exp);
-       
-       xgetenv(&exp, "GOEXPERIMENT");
-       bwritestr(&out, bprintf(&b,
-               "// auto generated by go tool dist\n"
-               "\n"
-               "#define GOEXPERIMENT \"%s\"\n", bstr(&exp)));
-
-       writefile(&out, file, 0);
-       
-       bfree(&b);
-       bfree(&out);
-       bfree(&exp);
-}
diff --git a/src/cmd/dist/buildruntime.go b/src/cmd/dist/buildruntime.go
new file mode 100644 (file)
index 0000000..c0ec2ef
--- /dev/null
@@ -0,0 +1,46 @@
+// Copyright 2012 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+       "fmt"
+       "os"
+)
+
+/*
+ * Helpers for building runtime.
+ */
+
+// mkzversion writes zversion.go:
+//
+//     package runtime
+//     const defaultGoroot = <goroot>
+//     const theVersion = <version>
+//
+func mkzversion(dir, file string) {
+       out := fmt.Sprintf(
+               "// auto generated by go tool dist\n"+
+                       "\n"+
+                       "package runtime\n"+
+                       "\n"+
+                       "const defaultGoroot = `%s`\n"+
+                       "const theVersion = `%s`\n"+
+                       "var buildVersion = theVersion\n", goroot_final, goversion)
+
+       writefile(out, file, 0)
+}
+
+// mkzexperiment writes zaexperiment.h (sic):
+//
+//     #define GOEXPERIMENT "experiment string"
+//
+func mkzexperiment(dir, file string) {
+       out := fmt.Sprintf(
+               "// auto generated by go tool dist\n"+
+                       "\n"+
+                       "#define GOEXPERIMENT \"%s\"\n", os.Getenv("GOEXPERIMENT"))
+
+       writefile(out, file, 0)
+}
diff --git a/src/cmd/dist/cpuid_386.s b/src/cmd/dist/cpuid_386.s
new file mode 100644 (file)
index 0000000..853824a
--- /dev/null
@@ -0,0 +1,14 @@
+// Copyright 2015 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+TEXT ·cpuid(SB),$0-8
+       MOVL ax+4(FP), AX
+       CPUID
+       MOVL info+0(FP), DI
+       MOVL AX, 0(DI)
+       MOVL BX, 4(DI)
+       MOVL CX, 8(DI)
+       MOVL DX, 12(DI)
+       RET
+
diff --git a/src/cmd/dist/cpuid_amd64.s b/src/cmd/dist/cpuid_amd64.s
new file mode 100644 (file)
index 0000000..dbb1085
--- /dev/null
@@ -0,0 +1,14 @@
+// Copyright 2015 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+TEXT ·cpuid(SB),$0-12
+       MOVL ax+8(FP), AX
+       CPUID
+       MOVQ info+0(FP), DI
+       MOVL AX, 0(DI)
+       MOVL BX, 4(DI)
+       MOVL CX, 8(DI)
+       MOVL DX, 12(DI)
+       RET
+
diff --git a/src/cmd/dist/cpuid_default.s b/src/cmd/dist/cpuid_default.s
new file mode 100644 (file)
index 0000000..e5bfd18
--- /dev/null
@@ -0,0 +1,10 @@
+// Copyright 2015 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build !386,!amd64
+
+#include "textflag.h"
+
+TEXT ·cpuid(SB),NOSPLIT,$0-0
+       RET
diff --git a/src/cmd/dist/main.c b/src/cmd/dist/main.c
deleted file mode 100644 (file)
index fad0180..0000000
+++ /dev/null
@@ -1,42 +0,0 @@
-// Copyright 2012 The Go Authors.  All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-#include "a.h"
-
-int vflag;
-int sflag;
-char *argv0;
-
-// cmdtab records the available commands.
-static struct {
-       char *name;
-       void (*f)(int, char**);
-} cmdtab[] = {
-       {"banner", cmdbanner},
-       {"bootstrap", cmdbootstrap},
-       {"clean", cmdclean},
-       {"env", cmdenv},
-       {"install", cmdinstall},
-       {"version", cmdversion},
-};
-
-// The OS-specific main calls into the portable code here.
-void
-xmain(int argc, char **argv)
-{
-       int i;
-
-       if(argc <= 1)
-               usage();
-       
-       for(i=0; i<nelem(cmdtab); i++) {
-               if(streq(cmdtab[i].name, argv[1])) {
-                       cmdtab[i].f(argc-1, argv+1);
-                       return;
-               }
-       }
-
-       xprintf("unknown command %s\n", argv[1]);
-       usage();
-}
diff --git a/src/cmd/dist/main.go b/src/cmd/dist/main.go
new file mode 100644 (file)
index 0000000..a2ac65e
--- /dev/null
@@ -0,0 +1,85 @@
+// Copyright 2012 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+       "flag"
+       "fmt"
+       "os"
+       "strconv"
+)
+
+// cmdtab records the available commands.
+var cmdtab = []struct {
+       name string
+       f    func()
+}{
+       {"banner", cmdbanner},
+       {"bootstrap", cmdbootstrap},
+       {"clean", cmdclean},
+       {"env", cmdenv},
+       {"install", cmdinstall},
+       {"version", cmdversion},
+}
+
+// The OS-specific main calls into the portable code here.
+func xmain() {
+       if len(os.Args) < 2 {
+               usage()
+       }
+       cmd := os.Args[1]
+       os.Args = os.Args[1:] // for flag parsing during cmd
+       for _, ct := range cmdtab {
+               if ct.name == cmd {
+                       flag.Usage = func() {
+                               fmt.Fprintf(os.Stderr, "usage: go tool dist %s [options]\n", cmd)
+                               flag.PrintDefaults()
+                               os.Exit(2)
+                       }
+                       ct.f()
+                       return
+               }
+       }
+
+       xprintf("unknown command %s\n", cmd)
+       usage()
+}
+
+func xflagparse(maxargs int) {
+       flag.Var((*count)(&vflag), "v", "verbosity")
+       flag.Parse()
+       if maxargs >= 0 && flag.NArg() > maxargs {
+               flag.Usage()
+       }
+}
+
+// count is a flag.Value that is like a flag.Bool and a flag.Int.
+// If used as -name, it increments the count, but -name=x sets the count.
+// Used for verbose flag -v.
+type count int
+
+func (c *count) String() string {
+       return fmt.Sprint(int(*c))
+}
+
+func (c *count) Set(s string) error {
+       switch s {
+       case "true":
+               *c++
+       case "false":
+               *c = 0
+       default:
+               n, err := strconv.Atoi(s)
+               if err != nil {
+                       return fmt.Errorf("invalid count %q", s)
+               }
+               *c = count(n)
+       }
+       return nil
+}
+
+func (c *count) IsBoolFlag() bool {
+       return true
+}
diff --git a/src/cmd/dist/plan9.c b/src/cmd/dist/plan9.c
deleted file mode 100644 (file)
index 13bee4a..0000000
+++ /dev/null
@@ -1,758 +0,0 @@
-// Copyright 2012 The Go Authors.  All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// These #ifdefs are being used as a substitute for
-// build configuration, so that on any system, this
-// tool can be built with the local equivalent of
-//     cc *.c
-//
-#ifdef PLAN9
-
-#include <u.h>
-#include <libc.h>
-#include <stdio.h>
-#undef nil
-#undef nelem
-#include "a.h"
-
-// bprintf replaces the buffer with the result of the printf formatting
-// and returns a pointer to the NUL-terminated buffer contents.
-char*
-bprintf(Buf *b, char *fmt, ...)
-{
-       va_list arg;
-       char buf[4096];
-
-       breset(b);
-       va_start(arg, fmt);
-       vsnprintf(buf, sizeof buf, fmt, arg);
-       va_end(arg);
-       bwritestr(b, buf);
-       return bstr(b);
-}
-
-// bpathf is the same as bprintf (on windows it turns / into \ after the printf).
-// It returns a pointer to the NUL-terminated buffer contents.
-char*
-bpathf(Buf *b, char *fmt, ...)
-{
-       va_list arg;
-       char buf[4096];
-       
-       breset(b);
-       va_start(arg, fmt);
-       vsnprintf(buf, sizeof buf, fmt, arg);
-       va_end(arg);
-       bwritestr(b, buf);
-       return bstr(b);
-}
-
-// bwritef is like bprintf but does not reset the buffer
-// and does not return the NUL-terminated string.
-void
-bwritef(Buf *b, char *fmt, ...)
-{
-       va_list arg;
-       char buf[4096];
-       
-       va_start(arg, fmt);
-       vsnprintf(buf, sizeof buf, fmt, arg);
-       va_end(arg);
-       bwritestr(b, buf);
-}
-
-// breadfrom appends to b all the data that can be read from fd.
-static void
-breadfrom(Buf *b, int fd)
-{
-       int n;
-
-       for(;;) {
-               bgrow(b, 4096);
-               n = read(fd, b->p+b->len, 4096);
-               if(n < 0)
-                       fatal("read");
-               if(n == 0)
-                       break;
-               b->len += n;
-       }
-}
-
-// xgetenv replaces b with the value of the named environment variable.
-void
-xgetenv(Buf *b, char *name)
-{
-       char *p;
-       
-       breset(b);
-       p = getenv(name);
-       if(p != nil)
-               bwritestr(b, p);
-}
-
-static void genrun(Buf *b, char *dir, int mode, Vec *argv, int bg);
-
-// run runs the command named by cmd.
-// If b is not nil, run replaces b with the output of the command.
-// If dir is not nil, run runs the command in that directory.
-// If mode is CheckExit, run calls fatal if the command is not successful.
-void
-run(Buf *b, char *dir, int mode, char *cmd, ...)
-{
-       va_list arg;
-       Vec argv;
-       char *p;
-       
-       vinit(&argv);
-       vadd(&argv, cmd);
-       va_start(arg, cmd);
-       while((p = va_arg(arg, char*)) != nil)
-               vadd(&argv, p);
-       va_end(arg);
-       
-       runv(b, dir, mode, &argv);
-       
-       vfree(&argv);
-}
-
-// runv is like run but takes a vector.
-void
-runv(Buf *b, char *dir, int mode, Vec *argv)
-{
-       genrun(b, dir, mode, argv, 1);
-}
-
-// bgrunv is like run but runs the command in the background.
-// bgwait waits for pending bgrunv to finish.
-void
-bgrunv(char *dir, int mode, Vec *argv)
-{
-       genrun(nil, dir, mode, argv, 0);
-}
-
-#define MAXBG 4 /* maximum number of jobs to run at once */
-
-static struct {
-       int pid;
-       int mode;
-       char *cmd;
-       Buf *b;
-} bg[MAXBG];
-static int nbg;
-static int maxnbg = nelem(bg);
-
-static void bgwait1(void);
-
-// genrun is the generic run implementation.
-static void
-genrun(Buf *b, char *dir, int mode, Vec *argv, int wait)
-{
-       int i, p[2], pid;
-       Buf b1, cmd;
-       char *q;
-
-       while(nbg >= maxnbg)
-               bgwait1();
-
-       binit(&b1);
-       binit(&cmd);
-
-       if(!isabs(argv->p[0])) {
-               bpathf(&b1, "/bin/%s", argv->p[0]);
-               free(argv->p[0]);
-               argv->p[0] = xstrdup(bstr(&b1));
-       }
-
-       // Generate a copy of the command to show in a log.
-       // Substitute $WORK for the work directory.
-       for(i=0; i<argv->len; i++) {
-               if(i > 0)
-                       bwritestr(&cmd, " ");
-               q = argv->p[i];
-               if(workdir != nil && hasprefix(q, workdir)) {
-                       bwritestr(&cmd, "$WORK");
-                       q += strlen(workdir);
-               }
-               bwritestr(&cmd, q);
-       }
-       if(vflag > 1)
-               errprintf("%s\n", bstr(&cmd));
-
-       if(b != nil) {
-               breset(b);
-               if(pipe(p) < 0)
-                       fatal("pipe");
-       }
-
-       switch(pid = fork()) {
-       case -1:
-               fatal("fork");
-       case 0:
-               if(b != nil) {
-                       close(0);
-                       close(p[0]);
-                       dup(p[1], 1);
-                       dup(p[1], 2);
-                       if(p[1] > 2)
-                               close(p[1]);
-               }
-               if(dir != nil) {
-                       if(chdir(dir) < 0) {
-                               fprint(2, "chdir: %r\n");
-                               _exits("chdir");
-                       }
-               }
-               vadd(argv, nil);
-               exec(argv->p[0], argv->p);
-               fprint(2, "%s\n", bstr(&cmd));
-               fprint(2, "exec: %r\n");
-               _exits("exec");
-       }
-       if(b != nil) {
-               close(p[1]);
-               breadfrom(b, p[0]);
-               close(p[0]);
-       }
-
-       if(nbg < 0)
-               fatal("bad bookkeeping");
-       bg[nbg].pid = pid;
-       bg[nbg].mode = mode;
-       bg[nbg].cmd = btake(&cmd);
-       bg[nbg].b = b;
-       nbg++;
-       
-       if(wait)
-               bgwait();
-
-       bfree(&cmd);
-       bfree(&b1);
-}
-
-// bgwait1 waits for a single background job.
-static void
-bgwait1(void)
-{
-       Waitmsg *w;
-       int i, mode;
-       char *cmd;
-       Buf *b;
-
-       w = wait();
-       if(w == nil)
-               fatal("wait");
-               
-       for(i=0; i<nbg; i++)
-               if(bg[i].pid == w->pid)
-                       goto ok;
-       fatal("wait: unexpected pid");
-
-ok:
-       cmd = bg[i].cmd;
-       mode = bg[i].mode;
-       bg[i].pid = 0;
-       b = bg[i].b;
-       bg[i].b = nil;
-       bg[i] = bg[--nbg];
-       
-       if(mode == CheckExit && w->msg[0]) {
-               if(b != nil)
-                       xprintf("%s\n", bstr(b));
-               fatal("FAILED: %s", cmd);
-       }
-       xfree(cmd);
-}
-
-// bgwait waits for all the background jobs.
-void
-bgwait(void)
-{
-       while(nbg > 0)
-               bgwait1();
-}
-
-// xgetwd replaces b with the current directory.
-void
-xgetwd(Buf *b)
-{
-       char buf[4096];
-       
-       breset(b);
-       if(getwd(buf, sizeof buf) == nil)
-               fatal("getwd");
-       bwritestr(b, buf);
-}
-
-// xrealwd replaces b with the 'real' name for the given path.
-// real is defined as what getcwd returns in that directory.
-void
-xrealwd(Buf *b, char *path)
-{
-       char buf[4096];
-       int fd;
-
-       fd = open(path, OREAD);
-       if(fd2path(fd, buf, sizeof buf) < 0)
-               fatal("fd2path");
-       close(fd);
-       breset(b);
-       bwritestr(b, buf);
-}
-
-// isdir reports whether p names an existing directory.
-bool
-isdir(char *p)
-{
-       Dir *d;
-       ulong mode;
-
-       d = dirstat(p);
-       if(d == nil)
-               return 0;
-       mode = d->mode;
-       free(d);
-       return (mode & DMDIR) == DMDIR;
-}
-
-// isfile reports whether p names an existing file.
-bool
-isfile(char *p)
-{
-       Dir *d;
-       ulong mode;
-
-       d = dirstat(p);
-       if(d == nil)
-               return 0;
-       mode = d->mode;
-       free(d);
-       return (mode & DMDIR) == 0;
-}
-
-// mtime returns the modification time of the file p.
-Time
-mtime(char *p)
-{
-       Dir *d;
-       ulong t;
-
-       d = dirstat(p);
-       if(d == nil)
-               return 0;
-       t = d->mtime;
-       free(d);
-       return (Time)t;
-}
-
-// isabs reports whether p is an absolute path.
-bool
-isabs(char *p)
-{
-       return hasprefix(p, "/");
-}
-
-// readfile replaces b with the content of the named file.
-void
-readfile(Buf *b, char *file)
-{
-       int fd;
-
-       breset(b);
-       fd = open(file, OREAD);
-       if(fd < 0)
-               fatal("open %s", file);
-       breadfrom(b, fd);
-       close(fd);
-}
-
-// writefile writes b to the named file, creating it if needed.
-void
-writefile(Buf *b, char *file, int exec)
-{
-       int fd;
-       Dir d;
-       
-       fd = create(file, ORDWR, 0666);
-       if(fd < 0)
-               fatal("create %s", file);
-       if(write(fd, b->p, b->len) != b->len)
-               fatal("short write");
-       if(exec) {
-               nulldir(&d);
-               d.mode = 0755;
-               dirfwstat(fd, &d);
-       }
-       close(fd);
-}
-
-// xmkdir creates the directory p.
-void
-xmkdir(char *p)
-{
-       int fd;
-
-       if(isdir(p))
-               return;
-       fd = create(p, OREAD, 0777|DMDIR);
-       close(fd);
-       if(fd < 0)
-               fatal("mkdir %s", p);
-}
-
-// xmkdirall creates the directory p and its parents, as needed.
-void
-xmkdirall(char *p)
-{
-       char *q;
-
-       if(isdir(p))
-               return;
-       q = strrchr(p, '/');
-       if(q != nil) {
-               *q = '\0';
-               xmkdirall(p);
-               *q = '/';
-       }
-       xmkdir(p);
-}
-
-// xremove removes the file p.
-void
-xremove(char *p)
-{
-       if(vflag > 2)
-               errprintf("rm %s\n", p);
-       remove(p);
-}
-
-// xremoveall removes the file or directory tree rooted at p.
-void
-xremoveall(char *p)
-{
-       int i;
-       Buf b;
-       Vec dir;
-
-       binit(&b);
-       vinit(&dir);
-
-       if(isdir(p)) {
-               xreaddir(&dir, p);
-               for(i=0; i<dir.len; i++) {
-                       bprintf(&b, "%s/%s", p, dir.p[i]);
-                       xremoveall(bstr(&b));
-               }
-       }
-       if(vflag > 2)
-               errprintf("rm %s\n", p);
-       remove(p);
-       
-       bfree(&b);
-       vfree(&dir);    
-}
-
-// xreaddir replaces dst with a list of the names of the files in dir.
-// The names are relative to dir; they are not full paths.
-void
-xreaddir(Vec *dst, char *dir)
-{
-       Dir *d;
-       int fd, i, n;
-
-       vreset(dst);
-
-       fd = open(dir, OREAD);
-       if(fd < 0)
-               fatal("open %s", dir);
-       n = dirreadall(fd, &d);
-       for(i=0; i<n; i++)
-               vadd(dst, d[i].name);
-       free(d);
-       close(fd);
-}
-
-// xworkdir creates a new temporary directory to hold object files
-// and returns the name of that directory.
-char*
-xworkdir(void)
-{
-       Buf b;
-       char *p;
-       int fd, tries;
-
-       binit(&b);
-
-       fd = 0;
-       for(tries=0; tries<1000; tries++) {
-               bprintf(&b, "/tmp/go-cbuild-%06x", nrand((1<<24)-1));
-               fd = create(bstr(&b), OREAD|OEXCL, 0700|DMDIR);
-               if(fd >= 0)
-                       goto done;
-       }
-       fatal("xworkdir create");
-
-done:
-       close(fd);
-       p = btake(&b);
-
-       bfree(&b);
-       return p;
-}
-
-// fatal prints an error message to standard error and exits.
-void
-fatal(char *msg, ...)
-{
-       va_list arg;
-       
-       fflush(stdout);
-       fprintf(stderr, "go tool dist: ");
-       va_start(arg, msg);
-       vfprintf(stderr, msg, arg);
-       va_end(arg);
-       fprintf(stderr, "\n");
-
-       bgwait();
-       exits(msg);
-}
-
-// xmalloc returns a newly allocated zeroed block of n bytes of memory.
-// It calls fatal if it runs out of memory.
-void*
-xmalloc(int n)
-{
-       void *p;
-       
-       p = malloc(n);
-       if(p == nil)
-               fatal("out of memory");
-       memset(p, 0, n);
-       return p;
-}
-
-// xstrdup returns a newly allocated copy of p.
-// It calls fatal if it runs out of memory.
-char*
-xstrdup(char *p)
-{
-       p = strdup(p);
-       if(p == nil)
-               fatal("out of memory");
-       return p;
-}
-
-// xrealloc grows the allocation p to n bytes and
-// returns the new (possibly moved) pointer.
-// It calls fatal if it runs out of memory.
-void*
-xrealloc(void *p, int n)
-{
-       p = realloc(p, n);
-       if(p == nil)
-               fatal("out of memory");
-       return p;
-}
-
-// xfree frees the result returned by xmalloc, xstrdup, or xrealloc.
-void
-xfree(void *p)
-{
-       free(p);
-}
-
-// hassuffix reports whether p ends with suffix.
-bool
-hassuffix(char *p, char *suffix)
-{
-       int np, ns;
-
-       np = strlen(p);
-       ns = strlen(suffix);
-       return np >= ns && streq(p+np-ns, suffix);
-}
-
-// hasprefix reports whether p begins with prefix.
-bool
-hasprefix(char *p, char *prefix)
-{
-       return strncmp(p, prefix, strlen(prefix)) == 0;
-}
-
-// contains reports whether sep appears in p.
-bool
-contains(char *p, char *sep)
-{
-       return strstr(p, sep) != nil;
-}
-
-// streq reports whether p and q are the same string.
-bool
-streq(char *p, char *q)
-{
-       return strcmp(p, q) == 0;
-}
-
-// lastelem returns the final path element in p.
-char*
-lastelem(char *p)
-{
-       char *out;
-
-       out = p;
-       for(; *p; p++)
-               if(*p == '/')
-                       out = p+1;
-       return out;
-}
-
-// xmemmove copies n bytes from src to dst.
-void
-xmemmove(void *dst, void *src, int n)
-{
-       memmove(dst, src, n);
-}
-
-// xmemcmp compares the n-byte regions starting at a and at b.
-int
-xmemcmp(void *a, void *b, int n)
-{
-       return memcmp(a, b, n);
-}
-
-// xstrlen returns the length of the NUL-terminated string at p.
-int
-xstrlen(char *p)
-{
-       return strlen(p);
-}
-
-// xexit exits the process with return code n.
-void
-xexit(int n)
-{
-       char buf[32];
-
-       snprintf(buf, sizeof buf, "%d", n);
-       exits(buf);
-}
-
-// xatexit schedules the exit-handler f to be run when the program exits.
-void
-xatexit(void (*f)(void))
-{
-       atexit(f);
-}
-
-// xprintf prints a message to standard output.
-void
-xprintf(char *fmt, ...)
-{
-       va_list arg;
-       
-       va_start(arg, fmt);
-       vprintf(fmt, arg);
-       va_end(arg);
-}
-
-// errprintf prints a message to standard output.
-void
-errprintf(char *fmt, ...)
-{
-       va_list arg;
-       
-       va_start(arg, fmt);
-       vfprintf(stderr, fmt, arg);
-       va_end(arg);
-}
-
-// xsetenv sets the environment variable $name to the given value.
-void
-xsetenv(char *name, char *value)
-{
-       putenv(name, value);
-}
-
-// main takes care of OS-specific startup and dispatches to xmain.
-void
-main(int argc, char **argv)
-{
-       Buf b;
-
-       setvbuf(stdout, nil, _IOLBF, BUFSIZ);
-       setvbuf(stderr, nil, _IOLBF, BUFSIZ);
-
-       binit(&b);
-
-       rfork(RFENVG);
-
-       slash = "/";
-       gohostos = "plan9";
-
-       xgetenv(&b, "objtype");
-       if(b.len == 0)
-               fatal("$objtype is unset");
-       gohostarch = btake(&b);
-
-       srand(time(0)+getpid());
-       init();
-       xmain(argc, argv);
-
-       bfree(&b);
-       exits(nil);
-}
-
-// xqsort is a wrapper for the C standard qsort.
-void
-xqsort(void *data, int n, int elemsize, int (*cmp)(const void*, const void*))
-{
-       qsort(data, n, elemsize, cmp);
-}
-
-// xstrcmp compares the NUL-terminated strings a and b.
-int
-xstrcmp(char *a, char *b)
-{
-       return strcmp(a, b);
-}
-
-// xstrstr returns a pointer to the first occurrence of b in a.
-char*
-xstrstr(char *a, char *b)
-{
-       return strstr(a, b);
-}
-
-// xstrrchr returns a pointer to the final occurrence of c in p.
-char*
-xstrrchr(char *p, int c)
-{
-       return strrchr(p, c);
-}
-
-// xsamefile reports whether f1 and f2 are the same file (or dir)
-int
-xsamefile(char *f1, char *f2)
-{
-       return streq(f1, f2); // suffice for now
-}
-
-// xtryexecfunc tries to execute function f, if any illegal instruction
-// signal received in the course of executing that function, it will
-// return 0, otherwise it will return 1.
-int
-xtryexecfunc(void (*f)(void))
-{
-       USED(f);
-       return 0; // suffice for now
-}
-
-bool
-cansse2(void)
-{
-       // if we had access to cpuid, could answer this question
-       // less conservatively.
-       return 0;
-}
-
-#endif // PLAN9
diff --git a/src/cmd/dist/sys_default.go b/src/cmd/dist/sys_default.go
new file mode 100644 (file)
index 0000000..d7bc464
--- /dev/null
@@ -0,0 +1,10 @@
+// Copyright 2015 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build !windows
+
+package main
+
+func sysinit() {
+}
diff --git a/src/cmd/dist/sys_windows.go b/src/cmd/dist/sys_windows.go
new file mode 100644 (file)
index 0000000..e9bfe9e
--- /dev/null
@@ -0,0 +1,49 @@
+// Copyright 2015 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+       "syscall"
+       "unsafe"
+)
+
+var (
+       modkernel32       = syscall.NewLazyDLL("kernel32.dll")
+       procGetSystemInfo = modkernel32.NewProc("GetSystemInfo")
+)
+
+// see http://msdn.microsoft.com/en-us/library/windows/desktop/ms724958(v=vs.85).aspx
+type systeminfo struct {
+       wProcessorArchitecture      uint16
+       wReserved                   uint16
+       dwPageSize                  uint32
+       lpMinimumApplicationAddress uintptr
+       lpMaximumApplicationAddress uintptr
+       dwActiveProcessorMask       uintptr
+       dwNumberOfProcessors        uint32
+       dwProcessorType             uint32
+       dwAllocationGranularity     uint32
+       wProcessorLevel             uint16
+       wProcessorRevision          uint16
+}
+
+const (
+       PROCESSOR_ARCHITECTURE_AMD64 = 9
+       PROCESSOR_ARCHITECTURE_INTEL = 0
+)
+
+var sysinfo systeminfo
+
+func sysinit() {
+       syscall.Syscall(procGetSystemInfo.Addr(), 1, uintptr(unsafe.Pointer(&sysinfo)), 0, 0)
+       switch sysinfo.wProcessorArchitecture {
+       case PROCESSOR_ARCHITECTURE_AMD64:
+               gohostarch = "amd64"
+       case PROCESSOR_ARCHITECTURE_INTEL:
+               gohostarch = "386"
+       default:
+               fatal("unknown processor architecture")
+       }
+}
diff --git a/src/cmd/dist/unix.c b/src/cmd/dist/unix.c
deleted file mode 100644 (file)
index 0fd17c1..0000000
+++ /dev/null
@@ -1,847 +0,0 @@
-// Copyright 2012 The Go Authors.  All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// These #ifdefs are being used as a substitute for
-// build configuration, so that on any system, this
-// tool can be built with the local equivalent of
-//     cc *.c
-//
-#ifndef WIN32
-#ifndef PLAN9
-
-#include "a.h"
-#include <unistd.h>
-#include <dirent.h>
-#include <sys/stat.h>
-#include <sys/wait.h>
-#include <sys/param.h>
-#include <sys/utsname.h>
-#include <fcntl.h>
-#include <string.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <errno.h>
-#include <stdarg.h>
-#include <setjmp.h>
-#include <signal.h>
-
-// bprintf replaces the buffer with the result of the printf formatting
-// and returns a pointer to the NUL-terminated buffer contents.
-char*
-bprintf(Buf *b, char *fmt, ...)
-{
-       va_list arg;
-       char buf[4096];
-       
-       breset(b);
-       va_start(arg, fmt);
-       vsnprintf(buf, sizeof buf, fmt, arg);
-       va_end(arg);
-       bwritestr(b, buf);
-       return bstr(b);
-}
-
-// bpathf is the same as bprintf (on windows it turns / into \ after the printf).
-// It returns a pointer to the NUL-terminated buffer contents.
-char*
-bpathf(Buf *b, char *fmt, ...)
-{
-       va_list arg;
-       char buf[4096];
-       
-       breset(b);
-       va_start(arg, fmt);
-       vsnprintf(buf, sizeof buf, fmt, arg);
-       va_end(arg);
-       bwritestr(b, buf);
-       return bstr(b);
-}
-
-// bwritef is like bprintf but does not reset the buffer
-// and does not return the NUL-terminated string.
-void
-bwritef(Buf *b, char *fmt, ...)
-{
-       va_list arg;
-       char buf[4096];
-       
-       va_start(arg, fmt);
-       vsnprintf(buf, sizeof buf, fmt, arg);
-       va_end(arg);
-       bwritestr(b, buf);
-}
-
-// breadfrom appends to b all the data that can be read from fd.
-static void
-breadfrom(Buf *b, int fd)
-{
-       int n;
-
-       for(;;) {
-               bgrow(b, 4096);
-               n = read(fd, b->p+b->len, 4096);
-               if(n < 0)
-                       fatal("read: %s", strerror(errno));
-               if(n == 0)
-                       break;
-               b->len += n;
-       }
-}
-
-// xgetenv replaces b with the value of the named environment variable.
-void
-xgetenv(Buf *b, char *name)
-{
-       char *p;
-       
-       breset(b);
-       p = getenv(name);
-       if(p != NULL)
-               bwritestr(b, p);
-}
-
-static void genrun(Buf *b, char *dir, int mode, Vec *argv, int bg);
-
-// run runs the command named by cmd.
-// If b is not nil, run replaces b with the output of the command.
-// If dir is not nil, run runs the command in that directory.
-// If mode is CheckExit, run calls fatal if the command is not successful.
-void
-run(Buf *b, char *dir, int mode, char *cmd, ...)
-{
-       va_list arg;
-       Vec argv;
-       char *p;
-       
-       vinit(&argv);
-       vadd(&argv, cmd);
-       va_start(arg, cmd);
-       while((p = va_arg(arg, char*)) != nil)
-               vadd(&argv, p);
-       va_end(arg);
-       
-       runv(b, dir, mode, &argv);
-       
-       vfree(&argv);
-}
-
-// runv is like run but takes a vector.
-void
-runv(Buf *b, char *dir, int mode, Vec *argv)
-{
-       genrun(b, dir, mode, argv, 1);
-}
-
-// bgrunv is like run but runs the command in the background.
-// bgwait waits for pending bgrunv to finish.
-void
-bgrunv(char *dir, int mode, Vec *argv)
-{
-       genrun(nil, dir, mode, argv, 0);
-}
-
-#define MAXBG 4 /* maximum number of jobs to run at once */
-
-static struct {
-       int pid;
-       int mode;
-       char *cmd;
-       Buf *b;
-} bg[MAXBG];
-static int nbg;
-static int maxnbg = nelem(bg);
-
-static void bgwait1(void);
-
-// genrun is the generic run implementation.
-static void
-genrun(Buf *b, char *dir, int mode, Vec *argv, int wait)
-{
-       int i, p[2], pid;
-       Buf cmd;
-       char *q;
-
-       while(nbg >= maxnbg)
-               bgwait1();
-
-       // Generate a copy of the command to show in a log.
-       // Substitute $WORK for the work directory.
-       binit(&cmd);
-       for(i=0; i<argv->len; i++) {
-               if(i > 0)
-                       bwritestr(&cmd, " ");
-               q = argv->p[i];
-               if(workdir != nil && hasprefix(q, workdir)) {
-                       bwritestr(&cmd, "$WORK");
-                       q += strlen(workdir);
-               }
-               bwritestr(&cmd, q);
-       }
-       if(vflag > 1)
-               errprintf("%s\n", bstr(&cmd));
-
-       if(b != nil) {
-               breset(b);
-               if(pipe(p) < 0)
-                       fatal("pipe: %s", strerror(errno));
-       }
-
-       switch(pid = fork()) {
-       case -1:
-               fatal("fork: %s", strerror(errno));
-       case 0:
-               if(b != nil) {
-                       close(0);
-                       close(p[0]);
-                       dup2(p[1], 1);
-                       dup2(p[1], 2);
-                       if(p[1] > 2)
-                               close(p[1]);
-               }
-               if(dir != nil) {
-                       if(chdir(dir) < 0) {
-                               fprintf(stderr, "chdir %s: %s\n", dir, strerror(errno));
-                               _exit(1);
-                       }
-               }
-               vadd(argv, nil);
-               execvp(argv->p[0], argv->p);
-               fprintf(stderr, "%s\n", bstr(&cmd));
-               fprintf(stderr, "exec %s: %s\n", argv->p[0], strerror(errno));
-               _exit(1);
-       }
-       if(b != nil) {
-               close(p[1]);
-               breadfrom(b, p[0]);
-               close(p[0]);
-       }
-
-       if(nbg < 0)
-               fatal("bad bookkeeping");
-       bg[nbg].pid = pid;
-       bg[nbg].mode = mode;
-       bg[nbg].cmd = btake(&cmd);
-       bg[nbg].b = b;
-       nbg++;
-       
-       if(wait)
-               bgwait();
-
-       bfree(&cmd);
-}
-
-// bgwait1 waits for a single background job.
-static void
-bgwait1(void)
-{
-       int i, pid, status, mode;
-       char *cmd;
-       Buf *b;
-
-       errno = 0;
-       while((pid = wait(&status)) < 0) {
-               if(errno != EINTR)
-                       fatal("waitpid: %s", strerror(errno));
-       }
-       for(i=0; i<nbg; i++)
-               if(bg[i].pid == pid)
-                       goto ok;
-       fatal("waitpid: unexpected pid");
-
-ok:
-       cmd = bg[i].cmd;
-       mode = bg[i].mode;
-       bg[i].pid = 0;
-       b = bg[i].b;
-       bg[i].b = nil;
-       bg[i] = bg[--nbg];
-       
-       if(mode == CheckExit && (!WIFEXITED(status) || WEXITSTATUS(status) != 0)) {
-               if(b != nil)
-                       xprintf("%s\n", bstr(b));
-               fatal("FAILED: %s", cmd);
-       }
-       xfree(cmd);
-}
-
-// bgwait waits for all the background jobs.
-void
-bgwait(void)
-{
-       while(nbg > 0)
-               bgwait1();
-}
-
-// xgetwd replaces b with the current directory.
-void
-xgetwd(Buf *b)
-{
-       char buf[MAXPATHLEN];
-       
-       breset(b);
-       if(getcwd(buf, MAXPATHLEN) == nil)
-               fatal("getcwd: %s", strerror(errno));
-       bwritestr(b, buf);      
-}
-
-// xrealwd replaces b with the 'real' name for the given path.
-// real is defined as what getcwd returns in that directory.
-void
-xrealwd(Buf *b, char *path)
-{
-       int fd;
-       
-       fd = open(".", 0);
-       if(fd < 0)
-               fatal("open .: %s", strerror(errno));
-       if(chdir(path) < 0)
-               fatal("chdir %s: %s", path, strerror(errno));
-       xgetwd(b);
-       if(fchdir(fd) < 0)
-               fatal("fchdir: %s", strerror(errno));
-       close(fd);
-}
-
-// isdir reports whether p names an existing directory.
-bool
-isdir(char *p)
-{
-       struct stat st;
-       
-       return stat(p, &st) >= 0 && S_ISDIR(st.st_mode);
-}
-
-// isfile reports whether p names an existing file.
-bool
-isfile(char *p)
-{
-       struct stat st;
-       
-       return stat(p, &st) >= 0 && S_ISREG(st.st_mode);
-}
-
-// mtime returns the modification time of the file p.
-Time
-mtime(char *p)
-{
-       struct stat st;
-       
-       if(stat(p, &st) < 0)
-               return 0;
-       return (Time)st.st_mtime*1000000000LL;
-}
-
-// isabs reports whether p is an absolute path.
-bool
-isabs(char *p)
-{
-       return hasprefix(p, "/");
-}
-
-// readfile replaces b with the content of the named file.
-void
-readfile(Buf *b, char *file)
-{
-       int fd;
-       
-       breset(b);
-       fd = open(file, 0);
-       if(fd < 0)
-               fatal("open %s: %s", file, strerror(errno));
-       breadfrom(b, fd);
-       close(fd);
-}
-
-// writefile writes b to the named file, creating it if needed.  if
-// exec is non-zero, marks the file as executable.
-void
-writefile(Buf *b, char *file, int exec)
-{
-       int fd;
-       
-       fd = creat(file, 0666);
-       if(fd < 0)
-               fatal("create %s: %s", file, strerror(errno));
-       if(write(fd, b->p, b->len) != b->len)
-               fatal("short write: %s", strerror(errno));
-       if(exec)
-               fchmod(fd, 0755);
-       close(fd);
-}
-
-// xmkdir creates the directory p.
-void
-xmkdir(char *p)
-{
-       if(mkdir(p, 0777) < 0)
-               fatal("mkdir %s: %s", p, strerror(errno));
-}
-
-// xmkdirall creates the directory p and its parents, as needed.
-void
-xmkdirall(char *p)
-{
-       char *q;
-
-       if(isdir(p))
-               return;
-       q = strrchr(p, '/');
-       if(q != nil) {
-               *q = '\0';
-               xmkdirall(p);
-               *q = '/';
-       }
-       xmkdir(p);
-}
-
-// xremove removes the file p.
-void
-xremove(char *p)
-{
-       if(vflag > 2)
-               errprintf("rm %s\n", p);
-       unlink(p);
-}
-
-// xremoveall removes the file or directory tree rooted at p.
-void
-xremoveall(char *p)
-{
-       int i;
-       Buf b;
-       Vec dir;
-
-       binit(&b);
-       vinit(&dir);
-
-       if(isdir(p)) {
-               xreaddir(&dir, p);
-               for(i=0; i<dir.len; i++) {
-                       bprintf(&b, "%s/%s", p, dir.p[i]);
-                       xremoveall(bstr(&b));
-               }
-               if(vflag > 2)
-                       errprintf("rm %s\n", p);
-               rmdir(p);
-       } else {
-               if(vflag > 2)
-                       errprintf("rm %s\n", p);
-               unlink(p);
-       }
-       
-       bfree(&b);
-       vfree(&dir);
-}
-
-// xreaddir replaces dst with a list of the names of the files in dir.
-// The names are relative to dir; they are not full paths.
-void
-xreaddir(Vec *dst, char *dir)
-{
-       DIR *d;
-       struct dirent *dp;
-
-       vreset(dst);
-       d = opendir(dir);
-       if(d == nil)
-               fatal("opendir %s: %s", dir, strerror(errno));
-       while((dp = readdir(d)) != nil) {
-               if(streq(dp->d_name, ".") || streq(dp->d_name, ".."))
-                       continue;
-               vadd(dst, dp->d_name);
-       }
-       closedir(d);
-}
-
-// xworkdir creates a new temporary directory to hold object files
-// and returns the name of that directory.
-char*
-xworkdir(void)
-{
-       Buf b;
-       char *p;
-
-       binit(&b);
-
-       xgetenv(&b, "TMPDIR");
-       if(b.len == 0)
-               bwritestr(&b, "/var/tmp");
-       if(b.p[b.len-1] != '/')
-               bwrite(&b, "/", 1);
-       bwritestr(&b, "go-cbuild-XXXXXX");
-       p = bstr(&b);
-       if(mkdtemp(p) == nil)
-               fatal("mkdtemp(%s): %s", p, strerror(errno));
-       p = btake(&b);
-
-       bfree(&b);
-
-       return p;
-}
-
-// fatal prints an error message to standard error and exits.
-void
-fatal(char *msg, ...)
-{
-       va_list arg;
-       
-       fflush(stdout);
-       fprintf(stderr, "go tool dist: ");
-       va_start(arg, msg);
-       vfprintf(stderr, msg, arg);
-       va_end(arg);
-       fprintf(stderr, "\n");
-       
-       bgwait();
-       exit(1);
-}
-
-// xmalloc returns a newly allocated zeroed block of n bytes of memory.
-// It calls fatal if it runs out of memory.
-void*
-xmalloc(int n)
-{
-       void *p;
-       
-       p = malloc(n);
-       if(p == nil)
-               fatal("out of memory");
-       memset(p, 0, n);
-       return p;
-}
-
-// xstrdup returns a newly allocated copy of p.
-// It calls fatal if it runs out of memory.
-char*
-xstrdup(char *p)
-{
-       p = strdup(p);
-       if(p == nil)
-               fatal("out of memory");
-       return p;
-}
-
-// xrealloc grows the allocation p to n bytes and
-// returns the new (possibly moved) pointer.
-// It calls fatal if it runs out of memory.
-void*
-xrealloc(void *p, int n)
-{
-       p = realloc(p, n);
-       if(p == nil)
-               fatal("out of memory");
-       return p;
-}
-
-// xfree frees the result returned by xmalloc, xstrdup, or xrealloc.
-void
-xfree(void *p)
-{
-       free(p);
-}
-
-// hassuffix reports whether p ends with suffix.
-bool
-hassuffix(char *p, char *suffix)
-{
-       int np, ns;
-
-       np = strlen(p);
-       ns = strlen(suffix);
-       return np >= ns && streq(p+np-ns, suffix);
-}
-
-// hasprefix reports whether p begins with prefix.
-bool
-hasprefix(char *p, char *prefix)
-{
-       return strncmp(p, prefix, strlen(prefix)) == 0;
-}
-
-// contains reports whether sep appears in p.
-bool
-contains(char *p, char *sep)
-{
-       return strstr(p, sep) != nil;
-}
-
-// streq reports whether p and q are the same string.
-bool
-streq(char *p, char *q)
-{
-       return strcmp(p, q) == 0;
-}
-
-// lastelem returns the final path element in p.
-char*
-lastelem(char *p)
-{
-       char *out;
-
-       out = p;
-       for(; *p; p++)
-               if(*p == '/')
-                       out = p+1;
-       return out;
-}
-
-// xmemmove copies n bytes from src to dst.
-void
-xmemmove(void *dst, void *src, int n)
-{
-       memmove(dst, src, n);
-}
-
-// xmemcmp compares the n-byte regions starting at a and at b.
-int
-xmemcmp(void *a, void *b, int n)
-{
-       return memcmp(a, b, n);
-}
-
-// xstrlen returns the length of the NUL-terminated string at p.
-int
-xstrlen(char *p)
-{
-       return strlen(p);
-}
-
-// xexit exits the process with return code n.
-void
-xexit(int n)
-{
-       exit(n);
-}
-
-// xatexit schedules the exit-handler f to be run when the program exits.
-void
-xatexit(void (*f)(void))
-{
-       atexit(f);
-}
-
-// xprintf prints a message to standard output.
-void
-xprintf(char *fmt, ...)
-{
-       va_list arg;
-       
-       va_start(arg, fmt);
-       vprintf(fmt, arg);
-       va_end(arg);
-}
-
-// errprintf prints a message to standard output.
-void
-errprintf(char *fmt, ...)
-{
-       va_list arg;
-       
-       va_start(arg, fmt);
-       vfprintf(stderr, fmt, arg);
-       va_end(arg);
-}
-
-// xsetenv sets the environment variable $name to the given value.
-void
-xsetenv(char *name, char *value)
-{
-       setenv(name, value, 1);
-}
-
-// main takes care of OS-specific startup and dispatches to xmain.
-int
-main(int argc, char **argv)
-{
-       Buf b;
-       int osx;
-       struct utsname u;
-
-       setvbuf(stdout, nil, _IOLBF, 0);
-       setvbuf(stderr, nil, _IOLBF, 0);
-
-       setenv("TERM", "dumb", 1); // disable escape codes in clang errors
-
-       binit(&b);
-       
-       slash = "/";
-
-#if defined(__APPLE__)
-       gohostos = "darwin";
-       // Even on 64-bit platform, darwin uname -m prints i386.
-       run(&b, nil, 0, "sysctl", "machdep.cpu.extfeatures", nil);
-       if(contains(bstr(&b), "EM64T"))
-               gohostarch = "amd64";
-#elif defined(__linux__)
-       gohostos = "linux";
-#elif defined(__DragonFly__)
-       gohostos = "dragonfly";
-#elif defined(__FreeBSD__)
-       gohostos = "freebsd";
-#elif defined(__FreeBSD_kernel__)
-       // detect debian/kFreeBSD. 
-       // http://wiki.debian.org/Debian_GNU/kFreeBSD_FAQ#Q._How_do_I_detect_kfreebsd_with_preprocessor_directives_in_a_C_program.3F
-       gohostos = "freebsd";   
-#elif defined(__OpenBSD__)
-       gohostos = "openbsd";
-#elif defined(__NetBSD__)
-       gohostos = "netbsd";
-#elif defined(__sun) && defined(__SVR4)
-       gohostos = "solaris";
-       // Even on 64-bit platform, solaris uname -m prints i86pc.
-       run(&b, nil, 0, "isainfo", "-n", nil);
-       if(contains(bstr(&b), "amd64"))
-               gohostarch = "amd64";
-       if(contains(bstr(&b), "i386"))
-               gohostarch = "386";
-#else
-       fatal("unknown operating system");
-#endif
-
-       if(gohostarch == nil) {
-               if(uname(&u) < 0)
-                       fatal("uname: %s", strerror(errno));
-               if(contains(u.machine, "x86_64") || contains(u.machine, "amd64"))
-                       gohostarch = "amd64";
-               else if(hassuffix(u.machine, "86"))
-                       gohostarch = "386";
-               else if(contains(u.machine, "arm"))
-                       gohostarch = "arm";
-               else if(contains(u.machine, "ppc64le"))
-                       gohostarch = "ppc64le";
-               else if(contains(u.machine, "ppc64"))
-                       gohostarch = "ppc64";
-               else
-                       fatal("unknown architecture: %s", u.machine);
-       }
-
-       if(streq(gohostarch, "arm"))
-               maxnbg = 1;
-
-       // The OS X 10.6 linker does not support external linking mode.
-       // See golang.org/issue/5130.
-       //
-       // OS X 10.6 does not work with clang either, but OS X 10.9 requires it.
-       // It seems to work with OS X 10.8, so we default to clang for 10.8 and later.
-       // See golang.org/issue/5822.
-       //
-       // Roughly, OS X 10.N shows up as uname release (N+4),
-       // so OS X 10.6 is uname version 10 and OS X 10.8 is uname version 12.
-       if(streq(gohostos, "darwin")) {
-               if(uname(&u) < 0)
-                       fatal("uname: %s", strerror(errno));
-               osx = atoi(u.release) - 4;
-               if(osx <= 6)
-                       goextlinkenabled = "0";
-               if(osx >= 8)
-                       defaultclang = 1;
-       }
-
-       init();
-       xmain(argc, argv);
-       bfree(&b);
-       return 0;
-}
-
-// xqsort is a wrapper for the C standard qsort.
-void
-xqsort(void *data, int n, int elemsize, int (*cmp)(const void*, const void*))
-{
-       qsort(data, n, elemsize, cmp);
-}
-
-// xstrcmp compares the NUL-terminated strings a and b.
-int
-xstrcmp(char *a, char *b)
-{
-       return strcmp(a, b);
-}
-
-// xstrstr returns a pointer to the first occurrence of b in a.
-char*
-xstrstr(char *a, char *b)
-{
-       return strstr(a, b);
-}
-
-// xstrrchr returns a pointer to the final occurrence of c in p.
-char*
-xstrrchr(char *p, int c)
-{
-       return strrchr(p, c);
-}
-
-// xsamefile reports whether f1 and f2 are the same file (or dir)
-int
-xsamefile(char *f1, char *f2)
-{
-       return streq(f1, f2); // suffice for now
-}
-
-sigjmp_buf sigill_jmpbuf;
-static void sigillhand(int);
-
-// xtryexecfunc tries to execute function f, if any illegal instruction
-// signal received in the course of executing that function, it will
-// return 0, otherwise it will return 1.
-// Some systems (notably NetBSD) will spin and spin when executing VFPv3
-// instructions on VFPv2 system (e.g. Raspberry Pi) without ever triggering
-// SIGILL, so we set a 1-second alarm to catch that case.
-int
-xtryexecfunc(void (*f)(void))
-{
-       int r;
-       r = 0;
-       signal(SIGILL, sigillhand);
-       signal(SIGALRM, sigillhand);
-       alarm(1);
-       if(sigsetjmp(sigill_jmpbuf, 1) == 0) {
-               f();
-               r = 1;
-       }
-       signal(SIGILL, SIG_DFL);
-       alarm(0);
-       signal(SIGALRM, SIG_DFL);
-       return r;
-}
-
-// SIGILL handler helper
-static void
-sigillhand(int signum)
-{
-       USED(signum);
-       siglongjmp(sigill_jmpbuf, 1);
-}
-
-static void
-__cpuid(int dst[4], int ax)
-{
-#ifdef __i386__
-       // we need to avoid ebx on i386 (esp. when -fPIC).
-       asm volatile(
-               "mov %%ebx, %%edi\n\t"
-               "cpuid\n\t"
-               "xchgl %%ebx, %%edi"
-               : "=a" (dst[0]), "=D" (dst[1]), "=c" (dst[2]), "=d" (dst[3])
-               : "0" (ax));
-#elif defined(__x86_64__)
-       asm volatile("cpuid"
-               : "=a" (dst[0]), "=b" (dst[1]), "=c" (dst[2]), "=d" (dst[3])
-               : "0" (ax));
-#else
-       dst[0] = dst[1] = dst[2] = dst[3] = 0;
-#endif
-}
-
-bool
-cansse2(void)
-{
-       int info[4];
-       
-       __cpuid(info, 1);
-       return (info[3] & (1<<26)) != 0;        // SSE2
-}
-
-#endif // PLAN9
-#endif // __WINDOWS__
diff --git a/src/cmd/dist/util.go b/src/cmd/dist/util.go
new file mode 100644 (file)
index 0000000..4628eea
--- /dev/null
@@ -0,0 +1,457 @@
+// Copyright 2012 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+       "fmt"
+       "io/ioutil"
+       "os"
+       "os/exec"
+       "path/filepath"
+       "runtime"
+       "sort"
+       "strconv"
+       "strings"
+       "sync"
+       "sync/atomic"
+       "time"
+)
+
+// pathf is fmt.Sprintf for generating paths
+// (on windows it turns / into \ after the printf).
+func pathf(format string, args ...interface{}) string {
+       return filepath.Clean(fmt.Sprintf(format, args...))
+}
+
+// filter returns a slice containing the elements x from list for which f(x) == true.
+func filter(list []string, f func(string) bool) []string {
+       var out []string
+       for _, x := range list {
+               if f(x) {
+                       out = append(out, x)
+               }
+       }
+       return out
+}
+
+// uniq returns a sorted slice containing the unique elements of list.
+func uniq(list []string) []string {
+       out := make([]string, len(list))
+       copy(out, list)
+       sort.Strings(out)
+       keep := out[:0]
+       for _, x := range out {
+               if len(keep) == 0 || keep[len(keep)-1] != x {
+                       keep = append(keep, x)
+               }
+       }
+       return keep
+}
+
+// splitlines returns a slice with the result of splitting
+// the input p after each \n.
+func splitlines(p string) []string {
+       return strings.SplitAfter(p, "\n")
+}
+
+// splitfields replaces the vector v with the result of splitting
+// the input p into non-empty fields containing no spaces.
+func splitfields(p string) []string {
+       return strings.Fields(p)
+}
+
+const (
+       CheckExit = 1 << iota
+       ShowOutput
+       Background
+)
+
+var outputLock sync.Mutex
+
+// run runs the command line cmd in dir.
+// If mode has ShowOutput set, run collects cmd's output and returns it as a string;
+// otherwise, run prints cmd's output to standard output after the command finishes.
+// If mode has CheckExit set and the command fails, run calls fatal.
+// If mode has Background set, this command is being run as a
+// Background job. Only bgrun should use the Background mode,
+// not other callers.
+func run(dir string, mode int, cmd ...string) string {
+       if vflag > 1 {
+               errprintf("run: %s\n", strings.Join(cmd, " "))
+       }
+
+       xcmd := exec.Command(cmd[0], cmd[1:]...)
+       xcmd.Dir = dir
+       var err error
+       data, err := xcmd.CombinedOutput()
+       if err != nil && mode&CheckExit != 0 {
+               outputLock.Lock()
+               if len(data) > 0 {
+                       xprintf("%s\n", data)
+               }
+               outputLock.Unlock()
+               atomic.AddInt32(&ndone, +1)
+               die := func() {
+                       time.Sleep(100 * time.Millisecond)
+                       fatal("FAILED: %v", strings.Join(cmd, " "))
+               }
+               if mode&Background != 0 {
+                       // This is a background run, and fatal will
+                       // wait for it to finish before exiting.
+                       // If we call fatal directly, that's a deadlock.
+                       // Instead, call fatal in a background goroutine
+                       // and let this run return normally, so that
+                       // fatal can wait for it to finish.
+                       go die()
+               } else {
+                       die()
+               }
+       }
+       if mode&ShowOutput != 0 {
+               os.Stdout.Write(data)
+       }
+       return string(data)
+}
+
+var maxbg = 4 /* maximum number of jobs to run at once */
+
+var (
+       bgwork = make(chan func())
+       bgdone = make(chan struct{}, 1e6)
+       nwork  int32
+       ndone  int32
+)
+
+func bginit() {
+       for i := 0; i < maxbg; i++ {
+               go bghelper()
+       }
+}
+
+func bghelper() {
+       for {
+               (<-bgwork)()
+       }
+}
+
+// bgrun is like run but runs the command in the background.
+// CheckExit|ShowOutput mode is implied (since output cannot be returned).
+func bgrun(dir string, cmd ...string) {
+       bgwork <- func() {
+               run(dir, CheckExit|ShowOutput|Background, cmd...)
+       }
+}
+
+// bgwait waits for pending bgruns to finish.
+func bgwait() {
+       var wg sync.WaitGroup
+       wg.Add(maxbg)
+       for i := 0; i < maxbg; i++ {
+               bgwork <- func() {
+                       wg.Done()
+                       wg.Wait()
+               }
+       }
+       wg.Wait()
+}
+
+// xgetwd returns the current directory.
+func xgetwd() string {
+       wd, err := os.Getwd()
+       if err != nil {
+               fatal("%s", err)
+       }
+       return wd
+}
+
+// xrealwd returns the 'real' name for the given path.
+// real is defined as what xgetwd returns in that directory.
+func xrealwd(path string) string {
+       old := xgetwd()
+       if err := os.Chdir(path); err != nil {
+               fatal("chdir %s: %v", path, err)
+       }
+       real := xgetwd()
+       if err := os.Chdir(old); err != nil {
+               fatal("chdir %s: %v", old, err)
+       }
+       return real
+}
+
+// isdir reports whether p names an existing directory.
+func isdir(p string) bool {
+       fi, err := os.Stat(p)
+       return err == nil && fi.IsDir()
+}
+
+// isfile reports whether p names an existing file.
+func isfile(p string) bool {
+       fi, err := os.Stat(p)
+       return err == nil && fi.Mode().IsRegular()
+}
+
+// mtime returns the modification time of the file p.
+func mtime(p string) time.Time {
+       fi, err := os.Stat(p)
+       if err != nil {
+               return time.Time{}
+       }
+       return fi.ModTime()
+}
+
+// isabs reports whether p is an absolute path.
+func isabs(p string) bool {
+       return filepath.IsAbs(p)
+}
+
+// readfile returns the content of the named file.
+func readfile(file string) string {
+       data, err := ioutil.ReadFile(file)
+       if err != nil {
+               fatal("%v", err)
+       }
+       return string(data)
+}
+
+// writefile writes b to the named file, creating it if needed.  if
+// exec is non-zero, marks the file as executable.
+func writefile(b, file string, exec int) {
+       mode := os.FileMode(0666)
+       if exec != 0 {
+               mode = 0777
+       }
+       err := ioutil.WriteFile(file, []byte(b), mode)
+       if err != nil {
+               fatal("%v", err)
+       }
+}
+
+// xmkdir creates the directory p.
+func xmkdir(p string) {
+       err := os.Mkdir(p, 0777)
+       if err != nil {
+               fatal("%v", err)
+       }
+}
+
+// xmkdirall creates the directory p and its parents, as needed.
+func xmkdirall(p string) {
+       err := os.MkdirAll(p, 0777)
+       if err != nil {
+               fatal("%v", err)
+       }
+}
+
+// xremove removes the file p.
+func xremove(p string) {
+       if vflag > 2 {
+               errprintf("rm %s\n", p)
+       }
+       os.Remove(p)
+}
+
+// xremoveall removes the file or directory tree rooted at p.
+func xremoveall(p string) {
+       if vflag > 2 {
+               errprintf("rm -r %s\n", p)
+       }
+       os.RemoveAll(p)
+}
+
+// xreaddir replaces dst with a list of the names of the files in dir.
+// The names are relative to dir; they are not full paths.
+func xreaddir(dir string) []string {
+       f, err := os.Open(dir)
+       if err != nil {
+               fatal("%v", err)
+       }
+       defer f.Close()
+       names, err := f.Readdirnames(-1)
+       if err != nil {
+               fatal("reading %s: %v", dir, err)
+       }
+       return names
+}
+
+// xworkdir creates a new temporary directory to hold object files
+// and returns the name of that directory.
+func xworkdir() string {
+       name, err := ioutil.TempDir("", "go-tool-dist-")
+       if err != nil {
+               fatal("%v", err)
+       }
+       return name
+}
+
+// fatal prints an error message to standard error and exits.
+func fatal(format string, args ...interface{}) {
+       fmt.Fprintf(os.Stderr, "go tool dist: %s\n", fmt.Sprintf(format, args...))
+       bgwait()
+       xexit(2)
+}
+
+var atexits []func()
+
+// xexit exits the process with return code n.
+func xexit(n int) {
+       for i := len(atexits) - 1; i >= 0; i-- {
+               atexits[i]()
+       }
+       os.Exit(n)
+}
+
+// xatexit schedules the exit-handler f to be run when the program exits.
+func xatexit(f func()) {
+       atexits = append(atexits, f)
+}
+
+// xprintf prints a message to standard output.
+func xprintf(format string, args ...interface{}) {
+       fmt.Printf(format, args...)
+}
+
+// errprintf prints a message to standard output.
+func errprintf(format string, args ...interface{}) {
+       fmt.Fprintf(os.Stderr, format, args...)
+}
+
+// main takes care of OS-specific startup and dispatches to xmain.
+func main() {
+       os.Setenv("TERM", "dumb") // disable escape codes in clang errors
+
+       slash = string(filepath.Separator)
+
+       gohostos = runtime.GOOS
+       switch gohostos {
+       case "darwin":
+               // Even on 64-bit platform, darwin uname -m prints i386.
+               if strings.Contains(run("", CheckExit, "sysctl", "machdep.cpu.extfeatures"), "EM64T") {
+                       gohostarch = "amd64"
+               }
+       case "solaris":
+               // Even on 64-bit platform, solaris uname -m prints i86pc.
+               out := run("", CheckExit, "isainfo", "-n")
+               if strings.Contains(out, "amd64") {
+                       gohostarch = "amd64"
+               }
+               if strings.Contains(out, "i386") {
+                       gohostarch = "386"
+               }
+       case "plan9":
+               gohostarch = os.Getenv("objtype")
+               if gohostarch == "" {
+                       fatal("$objtype is unset")
+               }
+       }
+
+       sysinit()
+
+       if gohostarch == "" {
+               // Default Unix system.
+               out := run("", CheckExit, "uname", "-m")
+               switch {
+               case strings.Contains(out, "x86_64"), strings.Contains(out, "amd64"):
+                       gohostarch = "amd64"
+               case strings.Contains(out, "86"):
+                       gohostarch = "386"
+               case strings.Contains(out, "arm"):
+                       gohostarch = "arm"
+               case strings.Contains(out, "ppc64le"):
+                       gohostarch = "ppc64le"
+               case strings.Contains(out, "ppc64"):
+                       gohostarch = "ppc64"
+               default:
+                       fatal("unknown architecture: %s", out)
+               }
+       }
+
+       if gohostarch == "arm" {
+               maxbg = 1
+       }
+       bginit()
+
+       // The OS X 10.6 linker does not support external linking mode.
+       // See golang.org/issue/5130.
+       //
+       // OS X 10.6 does not work with clang either, but OS X 10.9 requires it.
+       // It seems to work with OS X 10.8, so we default to clang for 10.8 and later.
+       // See golang.org/issue/5822.
+       //
+       // Roughly, OS X 10.N shows up as uname release (N+4),
+       // so OS X 10.6 is uname version 10 and OS X 10.8 is uname version 12.
+       if gohostos == "darwin" {
+               rel := run("", CheckExit, "uname", "-r")
+               if i := strings.Index(rel, "."); i >= 0 {
+                       rel = rel[:i]
+               }
+               osx, _ := strconv.Atoi(rel)
+               if osx <= 6+4 {
+                       goextlinkenabled = "0"
+               }
+               if osx >= 8+4 {
+                       defaultclang = true
+               }
+       }
+
+       xinit()
+       xmain()
+}
+
+// xsamefile reports whether f1 and f2 are the same file (or dir)
+func xsamefile(f1, f2 string) bool {
+       fi1, err1 := os.Stat(f1)
+       fi2, err2 := os.Stat(f2)
+       if err1 != nil || err2 != nil {
+               return f1 == f2
+       }
+       return os.SameFile(fi1, fi2)
+}
+
+func cpuid(info *[4]uint32, ax uint32)
+
+func cansse2() bool {
+       if gohostarch != "386" && gohostarch != "amd64" {
+               return false
+       }
+
+       var info [4]uint32
+       cpuid(&info, 1)
+       return info[3]&(1<<26) != 0 // SSE2
+}
+
+func xgetgoarm() string {
+       if goos == "nacl" {
+               // NaCl guarantees VFPv3 and is always cross-compiled.
+               return "7"
+       }
+       if gohostarch != "arm" || goos != gohostos {
+               // Conservative default for cross-compilation.
+               return "5"
+       }
+       if goos == "freebsd" {
+               // FreeBSD has broken VFP support.
+               return "5"
+       }
+       if xtryexecfunc(useVFPv3) {
+               return "7"
+       }
+       if xtryexecfunc(useVFPv1) {
+               return "6"
+       }
+       return "5"
+}
+
+func xtryexecfunc(f func()) bool {
+       // TODO(rsc): Implement.
+       // The C cmd/dist used this to test whether certain assembly
+       // sequences could be executed properly. It used signals and
+       // timers and sigsetjmp, which is basically not possible in Go.
+       // We probably have to invoke ourselves as a subprocess instead,
+       // to contain the fault/timeout.
+       return false
+}
+
+func useVFPv1()
+func useVFPv3()
diff --git a/src/cmd/dist/vfp_arm.s b/src/cmd/dist/vfp_arm.s
new file mode 100644 (file)
index 0000000..2dbc59a
--- /dev/null
@@ -0,0 +1,15 @@
+// Copyright 2015 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "textflag.h"
+
+// try to run "vmov.f64 d0, d0" instruction
+TEXT ·useVFPv1(SB),NOSPLIT,$0
+       WORD $0xeeb00b40        // vomv.f64 d0, d0
+       RET
+
+// try to run VFPv3-only "vmov.f64 d0, #112" instruction
+TEXT ·useVFPv3(SB),NOSPLIT,$0
+        WORD $0xeeb70b00       // vmov.f64 d0, #112
+       RET
diff --git a/src/cmd/dist/vfp_default.s b/src/cmd/dist/vfp_default.s
new file mode 100644 (file)
index 0000000..c795b35
--- /dev/null
@@ -0,0 +1,14 @@
+// Copyright 2015 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build !arm
+
+#include "textflag.h"
+
+TEXT ·useVFPv1(SB),NOSPLIT,$0
+       RET
+
+TEXT ·useVFPv3(SB),NOSPLIT,$0
+       RET
+
diff --git a/src/cmd/dist/windows.c b/src/cmd/dist/windows.c
deleted file mode 100644 (file)
index ff1a273..0000000
+++ /dev/null
@@ -1,989 +0,0 @@
-// Copyright 2012 The Go Authors.  All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// These #ifdefs are being used as a substitute for
-// build configuration, so that on any system, this
-// tool can be built with the local equivalent of
-//     cc *.c
-//
-#ifdef WIN32
-
-// Portability layer implemented for Windows.
-// See unix.c for doc comments about exported functions.
-
-#include "a.h"
-#include <windows.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdarg.h>
-
-/*
- * Windows uses 16-bit rune strings in the APIs.
- * Define conversions between Rune* and UTF-8 char*.
- */
-
-typedef unsigned char uchar;
-typedef unsigned short Rune;  // same as Windows
-
-// encoderune encodes the rune r into buf and returns
-// the number of bytes used.
-static int
-encoderune(char *buf, Rune r)
-{
-       if(r < 0x80) {  // 7 bits
-               buf[0] = r;
-               return 1;
-       }
-       if(r < 0x800) {  // 5+6 bits
-               buf[0] = 0xc0 | (r>>6);
-               buf[1] = 0x80 | (r&0x3f);
-               return 2;
-       }
-       buf[0] = 0xe0 | (r>>12);
-       buf[1] = 0x80 | ((r>>6)&0x3f);
-       buf[2] = 0x80 | (r&0x3f);
-       return 3;
-}
-
-// decoderune decodes the rune encoding at sbuf into r
-// and returns the number of bytes used.
-static int
-decoderune(Rune *r, char *sbuf)
-{
-       uchar *buf;
-
-       buf = (uchar*)sbuf;
-       if(buf[0] < 0x80) {
-               *r = buf[0];
-               return 1;
-       }
-       if((buf[0]&0xe0) == 0xc0 && (buf[1]&0xc0) == 0x80) {
-               *r = (buf[0]&~0xc0)<<6 | (buf[1]&~0x80);
-               if(*r < 0x80)
-                       goto err;
-               return 2;
-       }
-       if((buf[0]&0xf0) == 0xe0 && (buf[1]&0xc0) == 0x80 && (buf[2]&0xc0) == 0x80) {
-               *r = (buf[0]&~0xc0)<<12 | (buf[1]&~0x80)<<6 | (buf[2]&~0x80);
-               if(*r < 0x800)
-                       goto err;
-               return 3;
-       }
-err:
-       *r = 0xfffd;
-       return 1;
-}
-
-// toutf replaces b with the UTF-8 encoding of the rune string r.      
-static void
-toutf(Buf *b, Rune *r)
-{
-       int i, n;
-       char buf[4];
-
-       breset(b);
-       for(i=0; r[i]; i++) {
-               n = encoderune(buf, r[i]);
-               bwrite(b, buf, n);
-       }
-}
-
-// torune replaces *rp with a pointer to a newly allocated
-// rune string equivalent of the UTF-8 string p.
-static void
-torune(Rune **rp, char *p)
-{
-       Rune *r, *w;
-
-       r = xmalloc((strlen(p)+1) * sizeof r[0]);
-       w = r;
-       while(*p)
-               p += decoderune(w++, p);
-       *w = 0;
-       *rp = r;
-}
-
-// errstr returns the most recent Windows error, in string form.
-static char*
-errstr(void)
-{
-       DWORD code;
-       Rune *r;
-       Buf b;
-
-       binit(&b);
-       code = GetLastError();
-       r = nil;
-       FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS,
-               nil, code, 0, (Rune*)&r, 0, nil);
-       toutf(&b, r);
-       return bstr(&b);  // leak but we're dying anyway
-}
-
-void
-xgetenv(Buf *b, char *name)
-{
-       Rune *buf;
-       int n;
-       Rune *r;
-
-       breset(b);
-       torune(&r, name);
-       n = GetEnvironmentVariableW(r, NULL, 0);
-       if(n > 0) {
-               buf = xmalloc((n+1)*sizeof buf[0]);
-               GetEnvironmentVariableW(r, buf, n+1);
-               buf[n] = '\0';
-               toutf(b, buf);
-               xfree(buf);
-       }
-       xfree(r);
-}
-
-void
-xsetenv(char *name, char *value)
-{
-       Rune *rname, *rvalue;
-
-       torune(&rname, name);
-       torune(&rvalue, value);
-       SetEnvironmentVariableW(rname, rvalue);
-       xfree(rname);
-       xfree(rvalue);
-}
-
-char*
-bprintf(Buf *b, char *fmt, ...)
-{
-       va_list arg;
-       char buf[4096];
-       
-       breset(b);
-       va_start(arg, fmt);
-       vsnprintf(buf, sizeof buf, fmt, arg);
-       va_end(arg);
-       bwritestr(b, buf);
-       return bstr(b);
-}
-
-void
-bwritef(Buf *b, char *fmt, ...)
-{
-       va_list arg;
-       char buf[4096];
-       
-       // no reset
-       va_start(arg, fmt);
-       vsnprintf(buf, sizeof buf, fmt, arg);
-       va_end(arg);
-       bwritestr(b, buf);
-}
-
-// bpathf is like bprintf but replaces / with \ in the result,
-// to make it a canonical windows file path.
-char*
-bpathf(Buf *b, char *fmt, ...)
-{
-       int i;
-       va_list arg;
-       char buf[4096];
-       
-       breset(b);
-       va_start(arg, fmt);
-       vsnprintf(buf, sizeof buf, fmt, arg);
-       va_end(arg);
-       bwritestr(b, buf);
-
-       for(i=0; i<b->len; i++)
-               if(b->p[i] == '/')
-                       b->p[i] = '\\';
-
-       return bstr(b);
-}
-
-
-static void
-breadfrom(Buf *b, HANDLE h)
-{
-       DWORD n;
-
-       for(;;) {
-               if(b->len > 1<<22)
-                       fatal("unlikely file size in readfrom");
-               bgrow(b, 4096);
-               n = 0;
-               if(!ReadFile(h, b->p+b->len, 4096, &n, nil)) {
-                       // Happens for pipe reads.
-                       break;
-               }
-               if(n == 0)
-                       break;
-               b->len += n;
-       }
-}
-
-void
-run(Buf *b, char *dir, int mode, char *cmd, ...)
-{
-       va_list arg;
-       Vec argv;
-       char *p;
-       
-       vinit(&argv);
-       vadd(&argv, cmd);
-       va_start(arg, cmd);
-       while((p = va_arg(arg, char*)) != nil)
-               vadd(&argv, p);
-       va_end(arg);
-       
-       runv(b, dir, mode, &argv);
-       
-       vfree(&argv);
-}
-
-static void genrun(Buf*, char*, int, Vec*, int);
-
-void
-runv(Buf *b, char *dir, int mode, Vec *argv)
-{
-       genrun(b, dir, mode, argv, 1);
-}
-
-void
-bgrunv(char *dir, int mode, Vec *argv)
-{
-       genrun(nil, dir, mode, argv, 0);
-}
-
-#define MAXBG 4 /* maximum number of jobs to run at once */
-
-static struct {
-       PROCESS_INFORMATION pi;
-       int mode;
-       char *cmd;
-} bg[MAXBG];
-
-static int nbg;
-
-static void bgwait1(void);
-
-static void
-genrun(Buf *b, char *dir, int mode, Vec *argv, int wait)
-{
-       // Another copy of this logic is in ../../lib9/run_windows.c.
-       // If there's a bug here, fix the logic there too.
-       int i, j, nslash;
-       Buf cmd;
-       char *q;
-       Rune *rcmd, *rexe, *rdir;
-       STARTUPINFOW si;
-       PROCESS_INFORMATION pi;
-       HANDLE p[2];
-
-       while(nbg >= nelem(bg))
-               bgwait1();
-
-       binit(&cmd);
-
-       for(i=0; i<argv->len; i++) {
-               q = argv->p[i];
-               if(i == 0 && streq(q, "hg"))
-                       bwritestr(&cmd, "cmd.exe /c ");
-               if(i > 0)
-                       bwritestr(&cmd, " ");
-               if(contains(q, " ") || contains(q, "\t") || contains(q, "\"") || contains(q, "\\\\") || hassuffix(q, "\\")) {
-                       bwritestr(&cmd, "\"");
-                       nslash = 0;
-                       for(; *q; q++) {
-                               if(*q == '\\') {
-                                       nslash++;
-                                       continue;
-                               }
-                               if(*q == '"') {
-                                       for(j=0; j<2*nslash+1; j++)
-                                               bwritestr(&cmd, "\\");
-                                       nslash = 0;
-                               }
-                               for(j=0; j<nslash; j++)
-                                       bwritestr(&cmd, "\\");
-                               nslash = 0;
-                               bwrite(&cmd, q, 1);
-                       }
-                       for(j=0; j<2*nslash; j++)
-                               bwritestr(&cmd, "\\");
-                       bwritestr(&cmd, "\"");
-               } else {
-                       bwritestr(&cmd, q);
-               }
-       }
-       if(vflag > 1)
-               errprintf("%s\n", bstr(&cmd));
-
-       torune(&rcmd, bstr(&cmd));
-       rexe = nil;
-       rdir = nil;
-       if(dir != nil)
-               torune(&rdir, dir);
-
-       memset(&si, 0, sizeof si);
-       si.cb = sizeof si;
-       si.dwFlags = STARTF_USESTDHANDLES;
-       si.hStdInput = INVALID_HANDLE_VALUE;
-       if(b == nil) {
-               si.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
-               si.hStdError = GetStdHandle(STD_ERROR_HANDLE);
-       } else {
-               SECURITY_ATTRIBUTES seci;
-
-               memset(&seci, 0, sizeof seci);
-               seci.nLength = sizeof seci;
-               seci.bInheritHandle = 1;
-               breset(b);
-               if(!CreatePipe(&p[0], &p[1], &seci, 0))
-                       fatal("CreatePipe: %s", errstr());
-               si.hStdOutput = p[1];
-               si.hStdError = p[1];
-       }
-
-       if(!CreateProcessW(rexe, rcmd, nil, nil, TRUE, 0, nil, rdir, &si, &pi)) {
-               if(mode!=CheckExit)
-                       return;
-               fatal("%s: %s", argv->p[0], errstr());
-       }
-       if(rexe != nil)
-               xfree(rexe);
-       xfree(rcmd);
-       if(rdir != nil)
-               xfree(rdir);
-       if(b != nil) {
-               CloseHandle(p[1]);
-               breadfrom(b, p[0]);
-               CloseHandle(p[0]);
-       }
-
-       if(nbg < 0)
-               fatal("bad bookkeeping");
-       bg[nbg].pi = pi;
-       bg[nbg].mode = mode;
-       bg[nbg].cmd = btake(&cmd);
-       nbg++;
-
-       if(wait)
-               bgwait();
-
-       bfree(&cmd);
-}
-
-// closes the background job for bgwait1
-static void
-bgwaitclose(int i)
-{
-       if(i < 0 || i >= nbg)
-               return;
-
-       CloseHandle(bg[i].pi.hProcess);
-       CloseHandle(bg[i].pi.hThread);
-       
-       bg[i] = bg[--nbg];
-}
-
-// bgwait1 waits for a single background job
-static void
-bgwait1(void)
-{
-       int i, mode;
-       char *cmd;
-       HANDLE bgh[MAXBG];
-       DWORD code;
-
-       if(nbg == 0)
-               fatal("bgwait1: nothing left");
-
-       for(i=0; i<nbg; i++)
-               bgh[i] = bg[i].pi.hProcess;
-       i = WaitForMultipleObjects(nbg, bgh, FALSE, INFINITE);
-       if(i < 0 || i >= nbg)
-               fatal("WaitForMultipleObjects: %s", errstr());
-
-       cmd = bg[i].cmd;
-       mode = bg[i].mode;
-       if(!GetExitCodeProcess(bg[i].pi.hProcess, &code)) {
-               bgwaitclose(i);
-               fatal("GetExitCodeProcess: %s", errstr());
-               return;
-       }
-
-       if(mode==CheckExit && code != 0) {
-               bgwaitclose(i);
-               fatal("FAILED: %s", cmd);
-               return;
-       }
-
-       bgwaitclose(i);
-}
-
-void
-bgwait(void)
-{
-       while(nbg > 0)
-               bgwait1();
-}
-
-// rgetwd returns a rune string form of the current directory's path.
-static Rune*
-rgetwd(void)
-{
-       int n;
-       Rune *r;
-
-       n = GetCurrentDirectoryW(0, nil);
-       r = xmalloc((n+1)*sizeof r[0]);
-       GetCurrentDirectoryW(n+1, r);
-       r[n] = '\0';
-       return r;
-}
-
-void
-xgetwd(Buf *b)
-{
-       Rune *r;
-
-       r = rgetwd();
-       breset(b);
-       toutf(b, r);
-       xfree(r);
-}
-
-void
-xrealwd(Buf *b, char *path)
-{
-       Rune *old;
-       Rune *rnew;
-
-       old = rgetwd();
-       torune(&rnew, path);
-       if(!SetCurrentDirectoryW(rnew))
-               fatal("chdir %s: %s", path, errstr());
-       xfree(rnew);
-       xgetwd(b);
-       if(!SetCurrentDirectoryW(old)) {
-               breset(b);
-               toutf(b, old);
-               fatal("chdir %s: %s", bstr(b), errstr());
-       }
-}
-
-bool
-isdir(char *p)
-{
-       DWORD attr;
-       Rune *r;
-
-       torune(&r, p);
-       attr = GetFileAttributesW(r);
-       xfree(r);
-       return attr != INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_DIRECTORY);
-}
-
-bool
-isfile(char *p)
-{
-       DWORD attr;
-       Rune *r;
-
-       torune(&r, p);
-       attr = GetFileAttributesW(r);
-       xfree(r);
-       return attr != INVALID_FILE_ATTRIBUTES && !(attr & FILE_ATTRIBUTE_DIRECTORY);
-}
-
-Time
-mtime(char *p)
-{
-       HANDLE h;
-       WIN32_FIND_DATAW data;
-       Rune *r;
-       FILETIME *ft;
-
-       torune(&r, p);
-       h = FindFirstFileW(r, &data);
-       xfree(r);
-       if(h == INVALID_HANDLE_VALUE)
-               return 0;
-       FindClose(h);
-       ft = &data.ftLastWriteTime;
-       return (Time)ft->dwLowDateTime + ((Time)ft->dwHighDateTime<<32);
-}
-
-bool
-isabs(char *p)
-{
-       // c:/ or c:\ at beginning
-       if(('A' <= p[0] && p[0] <= 'Z') || ('a' <= p[0] && p[0] <= 'z'))
-               return p[1] == ':' && (p[2] == '/' || p[2] == '\\');
-       // / or \ at beginning
-       return p[0] == '/' || p[0] == '\\';
-}
-
-void
-readfile(Buf *b, char *file)
-{
-       HANDLE h;
-       Rune *r;
-
-       breset(b);
-       if(vflag > 2)
-               errprintf("read %s\n", file);
-       torune(&r, file);
-       h = CreateFileW(r, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE, nil, OPEN_EXISTING, 0, 0);
-       if(h == INVALID_HANDLE_VALUE)
-               fatal("open %s: %s", file, errstr());
-       breadfrom(b, h);
-       CloseHandle(h);
-}
-
-void
-writefile(Buf *b, char *file, int exec)
-{
-       HANDLE h;
-       Rune *r;
-       DWORD n;
-
-       USED(exec);
-
-       if(vflag > 2)
-               errprintf("write %s\n", file);
-       torune(&r, file);
-       h = CreateFileW(r, GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, nil, CREATE_ALWAYS, 0, 0);
-       if(h == INVALID_HANDLE_VALUE)
-               fatal("create %s: %s", file, errstr());
-       n = 0;
-       if(!WriteFile(h, b->p, b->len, &n, 0))
-               fatal("write %s: %s", file, errstr());
-       CloseHandle(h);
-}
-       
-
-void
-xmkdir(char *p)
-{
-       Rune *r;
-
-       torune(&r, p);
-       if(!CreateDirectoryW(r, nil))
-               fatal("mkdir %s: %s", p, errstr());
-       xfree(r);
-}
-
-void
-xmkdirall(char *p)
-{
-       int c;
-       char *q, *q2;
-       
-       if(isdir(p))
-               return;
-       q = strrchr(p, '/');
-       q2 = strrchr(p, '\\');
-       if(q2 != nil && (q == nil || q < q2))
-               q = q2;
-       if(q != nil) {
-               c = *q;
-               *q = '\0';
-               xmkdirall(p);
-               *q = c;
-       }
-       xmkdir(p);
-}
-
-void
-xremove(char *p)
-{
-       int attr;
-       Rune *r;
-
-       torune(&r, p);
-       attr = GetFileAttributesW(r);
-       if(attr >= 0) {
-               if(attr & FILE_ATTRIBUTE_DIRECTORY)
-                       RemoveDirectoryW(r);
-               else
-                       DeleteFileW(r);
-       }
-       xfree(r);
-}
-
-void
-xreaddir(Vec *dst, char *dir)
-{
-       Rune *r;
-       Buf b;
-       HANDLE h;
-       WIN32_FIND_DATAW data;
-       char *p, *q;
-
-       binit(&b);
-       vreset(dst);
-
-       bwritestr(&b, dir);
-       bwritestr(&b, "\\*");
-       torune(&r, bstr(&b));
-
-       h = FindFirstFileW(r, &data);
-       xfree(r);
-       if(h == INVALID_HANDLE_VALUE)
-               goto out;
-       do{
-               toutf(&b, data.cFileName);
-               p = bstr(&b);
-               q = xstrrchr(p, '\\');
-               if(q != nil)
-                       p = q+1;
-               if(!streq(p, ".") && !streq(p, ".."))
-                       vadd(dst, p);
-       }while(FindNextFileW(h, &data));
-       FindClose(h);
-
-out:
-       bfree(&b);
-}
-
-char*
-xworkdir(void)
-{
-       Rune buf[1024];
-       Rune tmp[MAX_PATH];
-       Rune go[3] = {'g', 'o', '\0'};
-       int n;
-       Buf b;
-
-       n = GetTempPathW(nelem(buf), buf);
-       if(n <= 0)
-               fatal("GetTempPath: %s", errstr());
-       buf[n] = '\0';
-
-       if(GetTempFileNameW(buf, go, 0, tmp) == 0)
-               fatal("GetTempFileName: %s", errstr());
-       DeleteFileW(tmp);
-       if(!CreateDirectoryW(tmp, nil))
-               fatal("create tempdir: %s", errstr());
-       
-       binit(&b);
-       toutf(&b, tmp);
-       return btake(&b);
-}
-
-void
-xremoveall(char *p)
-{
-       int i;
-       Buf b;
-       Vec dir;
-       Rune *r;
-
-       binit(&b);
-       vinit(&dir);
-
-       torune(&r, p);
-       if(isdir(p)) {
-               xreaddir(&dir, p);
-               for(i=0; i<dir.len; i++) {
-                       bprintf(&b, "%s/%s", p, dir.p[i]);
-                       xremoveall(bstr(&b));
-               }
-               RemoveDirectoryW(r);
-       } else {
-               DeleteFileW(r);
-       }
-       xfree(r);
-       
-       bfree(&b);
-       vfree(&dir);    
-}
-
-void
-fatal(char *msg, ...)
-{
-       static char buf1[1024];
-       va_list arg;
-
-       va_start(arg, msg);
-       vsnprintf(buf1, sizeof buf1, msg, arg);
-       va_end(arg);
-
-       errprintf("go tool dist: %s\n", buf1);
-       
-       bgwait();
-       ExitProcess(1);
-}
-
-// HEAP is the persistent handle to the default process heap.
-static HANDLE HEAP = INVALID_HANDLE_VALUE;
-
-void*
-xmalloc(int n)
-{
-       void *p;
-
-       if(HEAP == INVALID_HANDLE_VALUE)
-               HEAP = GetProcessHeap();
-       p = HeapAlloc(HEAP, 0, n);
-       if(p == nil)
-               fatal("out of memory allocating %d: %s", n, errstr());
-       memset(p, 0, n);
-       return p;
-}
-
-char*
-xstrdup(char *p)
-{
-       char *q;
-
-       q = xmalloc(strlen(p)+1);
-       strcpy(q, p);
-       return q;
-}
-
-void
-xfree(void *p)
-{
-       if(HEAP == INVALID_HANDLE_VALUE)
-               HEAP = GetProcessHeap();
-       HeapFree(HEAP, 0, p);
-}
-
-void*
-xrealloc(void *p, int n)
-{
-       if(p == nil)
-               return xmalloc(n);
-       if(HEAP == INVALID_HANDLE_VALUE)
-               HEAP = GetProcessHeap();
-       p = HeapReAlloc(HEAP, 0, p, n);
-       if(p == nil)
-               fatal("out of memory reallocating %d", n);
-       return p;
-}
-
-bool
-hassuffix(char *p, char *suffix)
-{
-       int np, ns;
-
-       np = strlen(p);
-       ns = strlen(suffix);
-       return np >= ns && streq(p+np-ns, suffix);
-}
-
-bool
-hasprefix(char *p, char *prefix)
-{
-       return strncmp(p, prefix, strlen(prefix)) == 0;
-}
-
-bool
-contains(char *p, char *sep)
-{
-       return strstr(p, sep) != nil;
-}
-
-bool
-streq(char *p, char *q)
-{
-       return strcmp(p, q) == 0;
-}
-
-char*
-lastelem(char *p)
-{
-       char *out;
-
-       out = p;
-       for(; *p; p++)
-               if(*p == '/' || *p == '\\')
-                       out = p+1;
-       return out;
-}
-
-void
-xmemmove(void *dst, void *src, int n)
-{
-       memmove(dst, src, n);
-}
-
-int
-xmemcmp(void *a, void *b, int n)
-{
-       return memcmp(a, b, n);
-}
-
-int
-xstrlen(char *p)
-{
-       return strlen(p);
-}
-
-void
-xexit(int n)
-{
-       ExitProcess(n);
-}
-
-void
-xatexit(void (*f)(void))
-{
-       atexit(f);
-}
-
-void
-xprintf(char *fmt, ...)
-{
-       va_list arg;
-       
-       va_start(arg, fmt);
-       vprintf(fmt, arg);
-       va_end(arg);
-}
-
-void
-errprintf(char *fmt, ...)
-{
-       va_list arg;
-       
-       va_start(arg, fmt);
-       vfprintf(stderr, fmt, arg);
-       va_end(arg);
-}
-
-int
-main(int argc, char **argv)
-{
-       SYSTEM_INFO si;
-
-       setvbuf(stdout, nil, _IOLBF, 0);
-       setvbuf(stderr, nil, _IOLBF, 0);
-
-       slash = "\\";
-       gohostos = "windows";
-
-       GetSystemInfo(&si);
-       switch(si.wProcessorArchitecture) {
-       case PROCESSOR_ARCHITECTURE_AMD64:
-               gohostarch = "amd64";
-               break;
-       case PROCESSOR_ARCHITECTURE_INTEL:
-               gohostarch = "386";
-               break;
-       default:
-               fatal("unknown processor architecture");
-       }
-
-       init();
-
-       xmain(argc, argv);
-       return 0;
-}
-
-void
-xqsort(void *data, int n, int elemsize, int (*cmp)(const void*, const void*))
-{
-       qsort(data, n, elemsize, cmp);
-}
-
-int
-xstrcmp(char *a, char *b)
-{
-       return strcmp(a, b);
-}
-
-char*
-xstrstr(char *a, char *b)
-{
-       return strstr(a, b);
-}
-
-char*
-xstrrchr(char *p, int c)
-{
-       char *ep;
-       
-       ep = p+strlen(p);
-       for(ep=p+strlen(p); ep >= p; ep--)
-               if(*ep == c)
-                       return ep;
-       return nil;
-}
-
-// xsamefile reports whether f1 and f2 are the same file (or dir)
-int
-xsamefile(char *f1, char *f2)
-{
-       Rune *ru;
-       HANDLE fd1, fd2;
-       BY_HANDLE_FILE_INFORMATION fi1, fi2;
-       int r;
-
-       // trivial case
-       if(streq(f1, f2))
-               return 1;
-       
-       torune(&ru, f1);
-       // refer to ../../os/stat_windows.go:/sameFile
-       fd1 = CreateFileW(ru, 0, 0, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0);
-       xfree(ru);
-       if(fd1 == INVALID_HANDLE_VALUE)
-               return 0;
-       torune(&ru, f2);
-       fd2 = CreateFileW(ru, 0, 0, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0);
-       xfree(ru);
-       if(fd2 == INVALID_HANDLE_VALUE) {
-               CloseHandle(fd1);
-               return 0;
-       }
-       r = GetFileInformationByHandle(fd1, &fi1) != 0 && GetFileInformationByHandle(fd2, &fi2) != 0;
-       CloseHandle(fd2);
-       CloseHandle(fd1);
-       if(r != 0 &&
-          fi1.dwVolumeSerialNumber == fi2.dwVolumeSerialNumber &&
-          fi1.nFileIndexHigh == fi2.nFileIndexHigh &&
-          fi1.nFileIndexLow == fi2.nFileIndexLow)
-               return 1;
-       return 0;
-}
-
-// xtryexecfunc tries to execute function f, if any illegal instruction
-// signal received in the course of executing that function, it will
-// return 0, otherwise it will return 1.
-int
-xtryexecfunc(void (*f)(void))
-{
-       return 0; // suffice for now
-}
-
-static void
-cpuid(int dst[4], int ax)
-{
-       // NOTE: This asm statement is for mingw.
-       // If we ever support MSVC, use __cpuid(dst, ax)
-       // to use the built-in.
-#if defined(__i386__) || defined(__x86_64__)
-       asm volatile("cpuid"
-               : "=a" (dst[0]), "=b" (dst[1]), "=c" (dst[2]), "=d" (dst[3])
-               : "0" (ax));
-#else
-       dst[0] = dst[1] = dst[2] = dst[3] = 0;
-#endif
-}
-
-bool
-cansse2(void)
-{
-       int info[4];
-       
-       cpuid(info, 1);
-       return (info[3] & (1<<26)) != 0;        // SSE2
-}
-
-
-#endif // __WINDOWS__
index a90937a77e7ccfa0e2f049c01140cfe31377819d..c8573c9954b1e10be028405909ff1ced226b0d82 100755 (executable)
@@ -3,6 +3,8 @@
 # Use of this source code is governed by a BSD-style
 # license that can be found in the LICENSE file.
 
+# See golang.org/s/go15bootstrap for an overview of the build process.
+
 # Environment variables that control make.bash:
 #
 # GOROOT_FINAL: The expected final Go root, baked into binaries.
@@ -110,26 +112,16 @@ rm -f ./runtime/runtime_defs.go
 
 # Finally!  Run the build.
 
-echo '##### Building C bootstrap tool.'
+echo '##### Building Go bootstrap tool.'
 echo cmd/dist
 export GOROOT="$(cd .. && pwd)"
-GOROOT_FINAL="${GOROOT_FINAL:-$GOROOT}"
-DEFGOROOT='-DGOROOT_FINAL="'"$GOROOT_FINAL"'"'
-
-mflag=""
-case "$GOHOSTARCH" in
-386) mflag=-m32;;
-amd64) mflag=-m64;;
-esac
-if [ "$(uname)" == "Darwin" ]; then
-       # golang.org/issue/5261
-       mflag="$mflag -mmacosx-version-min=10.6"
-fi
-# if gcc does not exist and $CC is not set, try clang if available.
-if [ -z "$CC" -a -z "$(type -t gcc)" -a -n "$(type -t clang)" ]; then
-       export CC=clang CXX=clang++
+GOROOT_BOOTSTRAP=${GOROOT_BOOTSTRAP:-$HOME/go1.4}
+if [ ! -x "$GOROOT_BOOTSTRAP/bin/go" ]; then
+       echo "ERROR: Cannot find $GOROOT_BOOTSTRAP/bin/go." >&2
+       echo "Set \$GOROOT_BOOTSTRAP to a working Go tree >= Go 1.4." >&2
 fi
-${CC:-gcc} $mflag -O2 -Wall -Werror -o cmd/dist/dist -Icmd/dist "$DEFGOROOT" cmd/dist/*.c
+rm -f cmd/dist/dist
+GOROOT="$GOROOT_BOOTSTRAP" GOOS="" GOARCH="" "$GOROOT_BOOTSTRAP/bin/go" build -o cmd/dist/dist ./cmd/dist
 
 # -e doesn't propagate out of eval, so check success by hand.
 eval $(./cmd/dist/dist env -p || echo FAIL=true)
index 8d035b0d22ef553fa3b7e76f63f1539c7847cbd1..fab9c88ff6e6f243168549e24e6dcbb667953caa 100644 (file)
@@ -45,24 +45,24 @@ goto fail
 :: Clean old generated file that will cause problems in the build.
 del /F ".\pkg\runtime\runtime_defs.go" 2>NUL
 
-:: Grab default GOROOT_FINAL and set GOROOT for build.
-:: The expression %VAR:\=\\% means to take %VAR%
-:: and apply the substitution \ = \\, escaping the
-:: backslashes.  Then we wrap that in quotes to create
-:: a C string.
+:: Set GOROOT for build.
 cd ..
 set GOROOT=%CD%
 cd src
-if "x%GOROOT_FINAL%"=="x" set GOROOT_FINAL=%GOROOT%
-set DEFGOROOT=-DGOROOT_FINAL="\"%GOROOT_FINAL:\=\\%\""
 
-echo ##### Building C bootstrap tool.
+echo ##### Building Go bootstrap tool.
 echo cmd/dist
 if not exist ..\bin\tool mkdir ..\bin\tool
-:: Windows has no glob expansion, so spell out cmd/dist/*.c.
-gcc -O2 -Wall -Werror -o cmd/dist/dist.exe -Icmd/dist %DEFGOROOT% cmd/dist/buf.c cmd/dist/build.c cmd/dist/buildgc.c cmd/dist/buildgo.c cmd/dist/buildruntime.c cmd/dist/main.c cmd/dist/windows.c cmd/dist/arm.c
+if "x%GOROOT_BOOTSTRAP%"=="x" set GOROOT_BOOTSTRAP=%HOMEDRIVE%%HOMEPATH%\Go1.4
+if not exist "%GOROOT_BOOTSTRAP%\bin\go.exe" goto bootstrapfail
+setlocal
+set GOROOT=%GOROOT_BOOTSTRAP%
+set GOOS=
+set GOARCH=
+"%GOROOT_BOOTSTRAP%\bin\go" build -o cmd\dist\dist.exe .\cmd\dist
+endlocal
 if errorlevel 1 goto fail
-.\cmd\dist\dist env -wp >env.bat
+.\cmd\dist\dist env -w -p >env.bat
 if errorlevel 1 goto fail
 call env.bat
 del env.bat
@@ -113,6 +113,10 @@ mkdir "%GOTOOLDIR%" 2>NUL
 copy cmd\dist\dist.exe "%GOTOOLDIR%\"
 goto end
 
+:bootstrapfail
+echo ERROR: Cannot find %GOROOT_BOOTSTRAP%\bin\go.exe
+echo "Set GOROOT_BOOTSTRAP to a working Go tree >= Go 1.4."
+
 :fail
 set GOBUILDFAIL=1
 if x%GOBUILDEXIT%==x1 exit %GOBUILDFAIL%
index 7a62d6af005a7dbe8f737104f59c743ad23d8704..5fe30aced7ca2e5ba3ec400009b1946313e66437 100755 (executable)
@@ -3,6 +3,8 @@
 # Use of this source code is governed by a BSD-style
 # license that can be found in the LICENSE file.
 
+# See golang.org/s/go15bootstrap for an overview of the build process.
+
 # Environment variables that control make.rc:
 #
 # GOROOT_FINAL: The expected final Go root, baked into binaries.
@@ -45,17 +47,18 @@ rm -f ./runtime/runtime_defs.go
 # Determine the host compiler toolchain.
 eval `{grep '^(CC|LD|O)=' /$objtype/mkfile}
 
-echo '# Building C bootstrap tool.'
+echo '# Building Go bootstrap tool.'
 echo cmd/dist
 GOROOT = `{cd .. && pwd}
-if(! ~ $#GOROOT_FINAL 1)
-       GOROOT_FINAL = $GOROOT
-DEFGOROOT='-DGOROOT_FINAL="'$GOROOT_FINAL'"'
-
-for(i in cmd/dist/*.c)
-       $CC -FTVwp+ -DPLAN9 $DEFGOROOT $i
-$LD -o cmd/dist/dist *.$O
-rm *.$O
+if(! ~ $#GOROOT_BOOTSTRAP 1)
+       GOROOT_BOOTSTRAP = $home/go1.4
+if(! test -x $GOROOT_BOOTSTRAP/bin/go){
+       echo 'ERROR: Cannot find '$GOROOT_BOOTSTRAP'/bin/go.' >[1=2]
+       echo 'Set $GOROOT_BOOTSTRAP to a working Go tree >= Go 1.4.' >[1=2]
+       exit bootstrap
+}
+rm -f cmd/dist/dist
+GOROOT=$GOROOT_BOOTSTRAP GOOS='' GOARCH='' $GOROOT_BOOTSTRAP/bin/go build -o cmd/dist/dist ./cmd/dist
 
 eval `{./cmd/dist/dist env -9}
 echo
diff --git a/src/sudo.bash b/src/sudo.bash
deleted file mode 100755 (executable)
index 33254c2..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-#!/usr/bin/env bash
-# Copyright 2009 The Go Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style
-# license that can be found in the LICENSE file.
-
-set -e
-
-case "`uname`" in
-Darwin)
-       ;;
-*)
-       exit 0
-esac
-
-# Check that the go command exists
-if ! go help >/dev/null 2>&1; then
-       echo "The go command is not in your PATH." >&2
-       exit 2
-fi
-
-eval $(go env)
-if ! [ -x $GOTOOLDIR/prof ]; then
-       echo "You don't need to run sudo.bash." >&2
-       exit 2
-fi
-
-if [[ ! -d /usr/local/bin ]]; then
-       echo 1>&2 'sudo.bash: problem with /usr/local/bin; cannot install tools.'
-       exit 2
-fi
-
-cd $(dirname $0)
-for i in prof
-do
-       # Remove old binaries if present
-       sudo rm -f /usr/local/bin/6$i
-       # Install new binaries
-       sudo cp $GOTOOLDIR/$i /usr/local/bin/go$i
-       sudo chgrp procmod /usr/local/bin/go$i
-       sudo chmod g+s /usr/local/bin/go$i
-done