From ad6ee36cac122894f7ea4043289c10a50e48ac01 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Wed, 7 Jan 2015 11:37:04 -0500 Subject: [PATCH 1/7] cmd/dist: remove C sources, rename some to Go files This CL makes the next one have nice cross-file diffs. Change-Id: I9ce897dc505dea9923be4e823bae31f4f7fa2ee2 Reviewed-on: https://go-review.googlesource.com/2471 Reviewed-by: Ian Lance Taylor --- src/cmd/dist/a.h | 165 --- src/cmd/dist/arg.h | 49 - src/cmd/dist/arm.c | 72 -- src/cmd/dist/buf.c | 284 ----- src/cmd/dist/{build.c => build.go} | 0 src/cmd/dist/{buildgc.c => buildgc.go} | 0 src/cmd/dist/{buildgo.c => buildgo.go} | 0 .../dist/{buildruntime.c => buildruntime.go} | 0 src/cmd/dist/{main.c => main.go} | 0 src/cmd/dist/plan9.c | 758 -------------- src/cmd/dist/{unix.c => util.go} | 0 src/cmd/dist/windows.c | 989 ------------------ 12 files changed, 2317 deletions(-) delete mode 100644 src/cmd/dist/a.h delete mode 100644 src/cmd/dist/arg.h delete mode 100644 src/cmd/dist/arm.c delete mode 100644 src/cmd/dist/buf.c rename src/cmd/dist/{build.c => build.go} (100%) rename src/cmd/dist/{buildgc.c => buildgc.go} (100%) rename src/cmd/dist/{buildgo.c => buildgo.go} (100%) rename src/cmd/dist/{buildruntime.c => buildruntime.go} (100%) rename src/cmd/dist/{main.c => main.go} (100%) delete mode 100644 src/cmd/dist/plan9.c rename src/cmd/dist/{unix.c => util.go} (100%) delete mode 100644 src/cmd/dist/windows.c diff --git a/src/cmd/dist/a.h b/src/cmd/dist/a.h deleted file mode 100644 index 288063b94b..0000000000 --- a/src/cmd/dist/a.h +++ /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 index 9819765b17..0000000000 --- a/src/cmd/dist/arg.h +++ /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 index 1ce7b7710d..0000000000 --- a/src/cmd/dist/arm.c +++ /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 index fbecd567ad..0000000000 --- a/src/cmd/dist/buf.c +++ /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; ilen; 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; ip[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; ilen; 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.go similarity index 100% rename from src/cmd/dist/build.c rename to src/cmd/dist/build.go diff --git a/src/cmd/dist/buildgc.c b/src/cmd/dist/buildgc.go similarity index 100% rename from src/cmd/dist/buildgc.c rename to src/cmd/dist/buildgc.go diff --git a/src/cmd/dist/buildgo.c b/src/cmd/dist/buildgo.go similarity index 100% rename from src/cmd/dist/buildgo.c rename to src/cmd/dist/buildgo.go diff --git a/src/cmd/dist/buildruntime.c b/src/cmd/dist/buildruntime.go similarity index 100% rename from src/cmd/dist/buildruntime.c rename to src/cmd/dist/buildruntime.go diff --git a/src/cmd/dist/main.c b/src/cmd/dist/main.go similarity index 100% rename from src/cmd/dist/main.c rename to src/cmd/dist/main.go diff --git a/src/cmd/dist/plan9.c b/src/cmd/dist/plan9.c deleted file mode 100644 index 13bee4a057..0000000000 --- a/src/cmd/dist/plan9.c +++ /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 -#include -#include -#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; ilen; 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; ipid) - 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 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= 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/unix.c b/src/cmd/dist/util.go similarity index 100% rename from src/cmd/dist/unix.c rename to src/cmd/dist/util.go diff --git a/src/cmd/dist/windows.c b/src/cmd/dist/windows.c deleted file mode 100644 index ff1a273512..0000000000 --- a/src/cmd/dist/windows.c +++ /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 -#include -#include -#include - -/* - * 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; ilen; 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; ilen; 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 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) - 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= 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__ From 20a10e7ddd1b2305f1279043ec281301c9199359 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Wed, 7 Jan 2015 11:38:00 -0500 Subject: [PATCH 2/7] build: require old Go to build new Go (and convert cmd/dist to Go) This CL introduces the bootstrap requirement that in order to build the current release (or development version) of Go, you need an older Go release (1.4 or newer) already installed. This requirement is the whole point of this CL. To enforce the requirement, convert cmd/dist from C to Go. With this bootstrapping out of the way, we can move on to replacing other, larger C programs like the Go compiler, the assemblers, and the linker. See golang.org/s/go15bootstrap for details. Change-Id: I53fd08ddacf3df9fae94fe2c986dba427ee4a21d Reviewed-on: https://go-review.googlesource.com/2470 Reviewed-by: Ian Lance Taylor Reviewed-by: Rob Pike --- src/cmd/dist/README | 62 +- src/cmd/dist/build.go | 2014 +++++++++++++++------------------- src/cmd/dist/buildgc.go | 298 +++-- src/cmd/dist/buildgo.go | 48 +- src/cmd/dist/buildruntime.go | 66 +- src/cmd/dist/cpuid_386.s | 14 + src/cmd/dist/cpuid_amd64.s | 14 + src/cmd/dist/cpuid_default.s | 10 + src/cmd/dist/main.go | 89 +- src/cmd/dist/sys_default.go | 10 + src/cmd/dist/sys_windows.go | 49 + src/cmd/dist/util.go | 1074 ++++++------------ src/cmd/dist/vfp_arm.s | 15 + src/cmd/dist/vfp_default.s | 14 + src/make.bash | 26 +- src/sudo.bash | 41 - 16 files changed, 1591 insertions(+), 2253 deletions(-) create mode 100644 src/cmd/dist/cpuid_386.s create mode 100644 src/cmd/dist/cpuid_amd64.s create mode 100644 src/cmd/dist/cpuid_default.s create mode 100644 src/cmd/dist/sys_default.go create mode 100644 src/cmd/dist/sys_windows.go create mode 100644 src/cmd/dist/vfp_arm.s create mode 100644 src/cmd/dist/vfp_default.s delete mode 100755 src/sudo.bash diff --git a/src/cmd/dist/README b/src/cmd/dist/README index e6d08cf028..0649e887f4 100644 --- a/src/cmd/dist/README +++ b/src/cmd/dist/README @@ -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/build.go b/src/cmd/dist/build.go index e4b8b58e43..9e4d1e3c22 100644 --- a/src/cmd/dist/build.go +++ b/src/cmd/dist/build.go @@ -2,47 +2,58 @@ // 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" +package main -/* - * Initialization for any invocation. - */ +import ( + "bytes" + "flag" + "fmt" + "os" + "path/filepath" + "runtime" + "strings" +) + +// 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; +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 -static bool shouldbuild(char*, char*); -static void dopack(char*, char*, char**, int); -static char *findgoversion(void); + sflag bool // build static binaries + vflag int // verbosity +) // The known architecture letters. -static char *gochars = "566899"; +var gochars = "566899" // The known architectures. -static char *okgoarch[] = { +var okgoarch = []string{ // same order as gochars "arm", "amd64", @@ -50,10 +61,10 @@ static char *okgoarch[] = { "386", "ppc64", "ppc64le", -}; +} // The known operating systems. -static char *okgoos[] = { +var okgoos = []string{ "darwin", "dragonfly", "linux", @@ -65,294 +76,252 @@ static char *okgoos[] = { "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 0) { - // if not "/", then strip trailing path separator - if(b.len >= 2 && b.p[b.len - 1] == slash[0]) - b.len--; - goroot = btake(&b); +// 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") } - 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); + goroot_final = os.Getenv("GOROOT_FINAL") + if goroot_final == "" { + goroot_final = goroot } - 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); + b := os.Getenv("GOBIN") + if b == "" { + b = goroot + slash + "bin" } - - xgetenv(&b, "CC"); - if(b.len == 0) { + 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) - 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++"); + if defaultclang { + b = "clang" + } else { + b = "gcc" } } - defaultcxxtarget = btake(&b); + defaultcc = b - xsetenv("GOROOT", goroot); - xsetenv("GOARCH", goarch); - xsetenv("GOOS", goos); - xsetenv("GOARM", goarm); - xsetenv("GO386", go386); + 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. - xsetenv("LANG", "C"); - xsetenv("LANGUAGE", "en_US.UTF8"); + os.Setenv("LANG", "C") + os.Setenv("LANGUAGE", "en_US.UTF8") - goversion = findgoversion(); + goversion = findgoversion() - workdir = xworkdir(); - xatexit(rmworkdir); + workdir = xworkdir() + xatexit(rmworkdir) - bpathf(&b, "%s/pkg/tool/%s_%s", goroot, gohostos, gohostarch); - tooldir = btake(&b); - - bfree(&b); + tooldir = pathf("%s/pkg/tool/%s_%s", goroot, gohostos, gohostarch) } // rmworkdir deletes the work directory. -static void -rmworkdir(void) -{ - if(vflag > 1) - errprintf("rm -rf %s\n", workdir); - xremoveall(workdir); +func rmworkdir() { + 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--; +func chomp(s string) string { + return strings.TrimRight(s, " \t\r\n") } -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++) { +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/. - p = xstrstr(tags.p[i], " refs/tags/"); - if(p == nil) - continue; - p += xstrlen(" 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). - 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; + 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 } - - bfree(&b); - bfree(&arg); - vfree(&tags); - return tag; + return } // 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); - +func findgoversion() string { // 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); + 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. - if(b.len > 0) - goto done; + // 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. - bpathf(&path, "%s/VERSION.cache", goroot); - if(isfile(bstr(&path))) { - readfile(&b, bstr(&path)); - chomp(&b); - goto done; + path = pathf("%s/VERSION.cache", goroot) + if isfile(path) { + return chomp(readfile(path)) } // Otherwise, use Git. // What is the current branch? - run(&branch, goroot, CheckExit, "git", "rev-parse", "--abbrev-ref", "HEAD", nil); - chomp(&branch); + branch := chomp(run(goroot, CheckExit, "git", "rev-parse", "--abbrev-ref", "HEAD")) // What are the tags along the current branch? - tag = "devel"; - precise = 0; + 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(hasprefix(bstr(&branch), "release-branch.")) - tag = branchtag(bstr(&branch), &precise); + if strings.HasPrefix(branch, "release-branch.") { + tag, precise = branchtag(branch) + } - bprintf(&b, "%s", tag); - if(!precise) { + 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); + tag += chomp(run(goroot, CheckExit, "git", "log", "-n", "1", "--format=format: +%h %cd", "HEAD")) } // Cache version. - writefile(&b, bstr(&path), 0); + writefile(tag, path, 0) -done: - p = btake(&b); - - - bfree(&b); - bfree(&path); - bfree(&bmore); - bfree(&branch); - - return p; + return tag } /* @@ -360,7 +329,7 @@ done: */ // The old tools that no longer live in $GOBIN or $GOROOT/bin. -static char *oldtool[] = { +var oldtool = []string{ "5a", "5c", "5g", "5l", "6a", "6c", "6g", "6l", "8a", "8c", "8g", "8l", @@ -381,44 +350,40 @@ static char *oldtool[] = { "govet", "goyacc", "quietgcc", -}; +} // Unreleased directories (relative to $GOROOT) that should // not be in release branches. -static char *unreleased[] = { +var unreleased = []string{ "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); - +func setup() { // Create bin directory. - p = bpathf(&b, "%s/bin", goroot); - if(!isdir(p)) - xmkdir(p); + if p := pathf("%s/bin", goroot); !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); + 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. @@ -426,44 +391,48 @@ setup(void) // 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); + 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); + if rebuildall { + xremoveall(tooldir) + } + xmkdirall(tooldir) // Remove tool binaries from before the tool/gohostos_gohostarch - xremoveall(bpathf(&b, "%s/bin/tool", goroot)); + xremoveall(pathf("%s/bin/tool", goroot)) // Remove old pre-tool binaries. - for(i=0; i 0 { + if goos != gohostos || 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); - + var clean []string + defer func() { + for _, name := range clean { + xremove(name) + } + }() // path = full path to dir. - bpathf(&path, "%s/src/%s", goroot, dir); - bpathf(&final_path, "%s/src/%s", goroot_final, dir); - name = lastelem(dir); + path := pathf("%s/src/%s", goroot, dir) + name := filepath.Base(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 ttarg) - stale = 1; - if(t == 0) { - vadd(&missing, p); - files.p[n++] = files.p[i]; - continue; + if strings.HasSuffix(p, ".go") { + gofiles = append(gofiles, p) } - files.p[n++] = files.p[i]; - } - files.len = n; + 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(files.len == 0) - goto out; - - for(i=0; i ttarg) - stale = 1; + if len(files) == 0 { + return + } - if(!stale) - goto out; + 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(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); + 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(i=0; i 1) - errprintf("generate %s\n", p); - gentab[j].gen(bstr(&path), p); + 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, @@ -907,222 +844,173 @@ install(char *dir) // exist (it does not know how to build them). // The 'clean' command can remove // the generated files. - goto built; + goto built } } // Did not rebuild p. - if(find(p, missing.p, missing.len) >= 0) - fatal("missing file %s", p); - built:; + if find(p, missing) >= 0 { + fatal("missing file %s", p) + } + built: } - if((!streq(goos, gohostos) || !streq(goarch, gohostarch)) && isgo) { + 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); - goto nobuild; + if vflag > 1 { + errprintf("skip build for cross-compile %s\n", dir) + } + return } - if(isgo) { + 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. - 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)); + pkg := dir + if strings.HasPrefix(dir, "cmd/") { + pkg = "main" } - - vcopy(&compile, go.p, go.len); - - runv(nil, bstr(&path), CheckExit, &compile); + 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(i=0; i 1) - errprintf("cp %s %s\n", src, dst); - - binit(&b); - readfile(&b, src); - writefile(&b, dst, exec); - bfree(&b); +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. -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 p) - p = q; + i := strings.LastIndex(file, "/") + 1 + j := strings.LastIndex(file, `\`) + 1 + if i < j { + i = j } - 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); + 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, dst, 0); - - bfree(&b); - bfree(&bdst); + writefile(bdst.String(), dst, 0) } // buildorder records the order of builds for the 'go bootstrap' command. -static char *buildorder[] = { +var buildorder = []string{ "lib9", "libbio", "liblink", "cmd/gc", // must be before g - "cmd/%sl", // must be before a, g + "cmd/%sl", // must be before a, g "cmd/%sa", "cmd/%sg", @@ -1337,12 +1180,12 @@ static char *buildorder[] = { "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[] = { +var cleantab = []string{ // Commands and C libraries. "cmd/5a", "cmd/5g", @@ -1357,7 +1200,7 @@ static char *cleantab[] = { "cmd/9g", "cmd/9l", "cmd/gc", - "cmd/go", + "cmd/go", "lib9", "libbio", "liblink", @@ -1403,383 +1246,246 @@ static char *cleantab[] = { "unicode", "unicode/utf16", "unicode/utf8", -}; +} -static char *runtimegen[] = { +var runtimegen = []string{ "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 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)); + format := "%s=\"%s\"\n" + switch { + case *plan9: + format = "%s='%s'\n" + case *windows: + format = "set %s=%s\r\n" } - bfree(&b); - bfree(&b1); + 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. -void -cmdbootstrap(int argc, char **argv) -{ - int i; - Buf b; - char *oldgoos, *oldgoarch, *oldgochar; +func cmdbootstrap() { + flag.BoolVar(&rebuildall, "a", rebuildall, "rebuild all") + flag.BoolVar(&sflag, "s", sflag, "build static binaries") + xflagparse(0) - 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 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(); - goversion = findgoversion(); - setup(); - xsetenv("GOROOT", goroot); - xsetenv("GOROOT_FINAL", goroot_final); + 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; - xsetenv("GOARCH", goarch); - xsetenv("GOOS", goos); + 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(i=0; i 0) - usage(); - - clean(); +func cmdclean() { + xflagparse(0) + 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; +func cmdbanner() { + xflagparse(0) - ARGBEGIN{ - case 'v': - vflag++; - break; - default: - usage(); - }ARGEND + xprintf("\n") + xprintf("---\n") + xprintf("Installed Go for %s/%s in %s\n", goos, goarch, goroot) + xprintf("Installed commands in %s\n", gobin) - 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 !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")) { + } else if 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); + 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. - 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); + 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(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" + if !xsamefile(goroot_final, goroot) { + xprintf("\n"+ "The binaries expect %s to be copied or moved to %s\n", - goroot, goroot_final); + 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); +func cmdversion() { + xflagparse(0) + xprintf("%s\n", goversion) } diff --git a/src/cmd/dist/buildgc.go b/src/cmd/dist/buildgc.go index 64434d51e1..b1b5d5e7ba 100644 --- a/src/cmd/dist/buildgc.go +++ b/src/cmd/dist/buildgc.go @@ -2,7 +2,14 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -#include "a.h" +package main + +import ( + "bytes" + "fmt" + "strconv" + "strings" +) /* * Helpers for building cmd/gc. @@ -12,207 +19,152 @@ // 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")); +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") - readfile(&in, bprintf(&b, "%s/go.h", dir)); - splitlines(&lines, bstr(&in)); - i = 0; - while(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 } } - - bwritestr(&out, bprintf(&b, "};\n")); + fmt.Fprintf(&out, "};\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; + 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. -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]; +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) - binit(&b); - binit(&in); - binit(&out); - binit(&out2); - vinit(&lines); - for(i=0; i\n")); - bwritestr(&out, bprintf(&b, "#include \n")); - bwritestr(&out, bprintf(&b, "#include \n")); - bwritestr(&out, bprintf(&b, "#include \n")); - bwritestr(&out, bprintf(&b, "#include \"../cmd/%cl/%c.out.h\"\n", ch, ch)); - bwritestr(&out, bprintf(&b, "\n")); + var out bytes.Buffer + fmt.Fprintf(&out, "// auto generated by go tool dist\n") + fmt.Fprintf(&out, "#include \n") + fmt.Fprintf(&out, "#include \n") + fmt.Fprintf(&out, "#include \n") + fmt.Fprintf(&out, "#include \n") + fmt.Fprintf(&out, "#include \"../cmd/%cl/%c.out.h\"\n", ch, ch) + fmt.Fprintf(&out, "\n") - bwritestr(&out, bprintf(&b, "char* anames%c[] = {\n", ch)); - for(i=0; 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) } } - bwritestr(&out, "};\n"); + fmt.Fprintf(&out, "};\n") - j=0; - bprintf(&out2, "char* cnames%c[] = {\n", ch); - for(i=0; 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++ } } - bwritestr(&out2, "};\n"); - if(j>0) - bwriteb(&out, &out2); + fmt.Fprintf(&out2, "};\n") + if j > 0 { + out.Write(out2.Bytes()) + } - j=unknown=0; - n=-1; - for(i=0; i= 0 { + line = line[:i] + } // 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; + 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 } - // Truncate space before '=' - while(*(p-1) == ' ' || *(p-1) == '\t') - p--; - *p = '\0'; - unknown = 0; + unknown = false } else { - n++; + 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= len(dnames) { + continue } - bwritestr(&out, "\",\n"); + + line = strings.TrimSpace(line) + line = line[len("D_"):] + + if strings.Contains(line, "LAST") { + continue + } + dnames[n] = append(dnames[n], line) + j++ } - bwritestr(&out, "};\n"); } - writefile(&out, file, 0); + 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") + } - bfree(&b); - bfree(&in); - bfree(&out); - bfree(&out2); - vfree(&lines); - for(i=0; i // // 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); +// but we also write cmd/cgo/zdefaultcc.go +func mkzdefaultcc(dir, file string) { + var out string - 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); + 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); + 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); + // 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.go b/src/cmd/dist/buildruntime.go index add6897682..c0ec2efbd6 100644 --- a/src/cmd/dist/buildruntime.go +++ b/src/cmd/dist/buildruntime.go @@ -2,7 +2,12 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -#include "a.h" +package main + +import ( + "fmt" + "os" +) /* * Helpers for building runtime. @@ -14,55 +19,28 @@ // const defaultGoroot = // const theVersion = // -void -mkzversion(char *dir, char *file) -{ - Buf b, out; - - USED(dir); +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) - 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); + writefile(out, file, 0) } // mkzexperiment writes zaexperiment.h (sic): // // #define GOEXPERIMENT "experiment string" // -void -mkzexperiment(char *dir, char *file) -{ - Buf b, out, exp; - - USED(dir); +func mkzexperiment(dir, file string) { + out := fmt.Sprintf( + "// auto generated by go tool dist\n"+ + "\n"+ + "#define GOEXPERIMENT \"%s\"\n", os.Getenv("GOEXPERIMENT")) - 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); + writefile(out, file, 0) } diff --git a/src/cmd/dist/cpuid_386.s b/src/cmd/dist/cpuid_386.s new file mode 100644 index 0000000000..853824a1bc --- /dev/null +++ b/src/cmd/dist/cpuid_386.s @@ -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 index 0000000000..dbb1085e89 --- /dev/null +++ b/src/cmd/dist/cpuid_amd64.s @@ -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 index 0000000000..e5bfd183d9 --- /dev/null +++ b/src/cmd/dist/cpuid_default.s @@ -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.go b/src/cmd/dist/main.go index fad01802a5..a2ac65ee87 100644 --- a/src/cmd/dist/main.go +++ b/src/cmd/dist/main.go @@ -2,41 +2,84 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -#include "a.h" +package main -int vflag; -int sflag; -char *argv0; +import ( + "flag" + "fmt" + "os" + "strconv" +) // cmdtab records the available commands. -static struct { - char *name; - void (*f)(int, char**); -} cmdtab[] = { +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. -void -xmain(int argc, char **argv) -{ - int i; - - if(argc <= 1) - usage(); - - for(i=0; i= 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/sys_default.go b/src/cmd/dist/sys_default.go new file mode 100644 index 0000000000..ab97f19b3d --- /dev/null +++ b/src/cmd/dist/sys_default.go @@ -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,!plan9 + +package main + +func sysinit() { +} diff --git a/src/cmd/dist/sys_windows.go b/src/cmd/dist/sys_windows.go new file mode 100644 index 0000000000..c6867fb895 --- /dev/null +++ b/src/cmd/dist/sys_windows.go @@ -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 = syscall.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/util.go b/src/cmd/dist/util.go index 0fd17c1509..4628eead80 100644 --- a/src/cmd/dist/util.go +++ b/src/cmd/dist/util.go @@ -2,722 +2,375 @@ // 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 +package main -#include "a.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +import ( + "fmt" + "io/ioutil" + "os" + "os/exec" + "path/filepath" + "runtime" + "sort" + "strconv" + "strings" + "sync" + "sync/atomic" + "time" +) -// 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); +// 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...)) } -// 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; ilen; i++) { - if(i > 0) - bwritestr(&cmd, " "); - q = argv->p[i]; - if(workdir != nil && hasprefix(q, workdir)) { - bwritestr(&cmd, "$WORK"); - q += strlen(workdir); +// 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) } - bwritestr(&cmd, q); } - if(vflag > 1) - errprintf("%s\n", bstr(&cmd)); + return out +} - 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]); +// 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) } - if(dir != nil) { - if(chdir(dir) < 0) { - fprintf(stderr, "chdir %s: %s\n", dir, strerror(errno)); - _exit(1); - } + } + 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() } - 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 mode&ShowOutput != 0 { + os.Stdout.Write(data) } - - 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); + return string(data) } -// bgwait1 waits for a single background job. -static void -bgwait1(void) -{ - int i, pid, status, mode; - char *cmd; - Buf *b; +var maxbg = 4 /* maximum number of jobs to run at once */ - errno = 0; - while((pid = wait(&status)) < 0) { - if(errno != EINTR) - fatal("waitpid: %s", strerror(errno)); +var ( + bgwork = make(chan func()) + bgdone = make(chan struct{}, 1e6) + nwork int32 + ndone int32 +) + +func bginit() { + for i := 0; i < maxbg; i++ { + go bghelper() } - for(i=0; i 0) - bgwait1(); +// 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...) + } } -// 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); +// 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() } -// 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); +// 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. -bool -isdir(char *p) -{ - struct stat st; - - return stat(p, &st) >= 0 && S_ISDIR(st.st_mode); +func isdir(p string) bool { + fi, err := os.Stat(p) + return err == nil && fi.IsDir() } // 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); +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. -Time -mtime(char *p) -{ - struct stat st; - - if(stat(p, &st) < 0) - return 0; - return (Time)st.st_mtime*1000000000LL; +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. -bool -isabs(char *p) -{ - return hasprefix(p, "/"); +func isabs(p string) bool { + return filepath.IsAbs(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); +// 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. -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); +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. -void -xmkdir(char *p) -{ - if(mkdir(p, 0777) < 0) - fatal("mkdir %s: %s", p, strerror(errno)); +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. -void -xmkdirall(char *p) -{ - char *q; - - if(isdir(p)) - return; - q = strrchr(p, '/'); - if(q != nil) { - *q = '\0'; - xmkdirall(p); - *q = '/'; +func xmkdirall(p string) { + err := os.MkdirAll(p, 0777) + if err != nil { + fatal("%v", err) } - xmkdir(p); } // xremove removes the file p. -void -xremove(char *p) -{ - if(vflag > 2) - errprintf("rm %s\n", p); - unlink(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. -void -xremoveall(char *p) -{ - int i; - Buf b; - Vec dir; - - binit(&b); - vinit(&dir); - - if(isdir(p)) { - xreaddir(&dir, p); - for(i=0; i 2) - errprintf("rm %s\n", p); - rmdir(p); - } else { - if(vflag > 2) - errprintf("rm %s\n", p); - unlink(p); +func xremoveall(p string) { + if vflag > 2 { + errprintf("rm -r %s\n", p) } - - bfree(&b); - vfree(&dir); + 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. -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); +func xreaddir(dir string) []string { + f, err := os.Open(dir) + if err != nil { + fatal("%v", err) } - closedir(d); + 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. -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; +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. -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); +func fatal(format string, args ...interface{}) { + fmt.Fprintf(os.Stderr, "go tool dist: %s\n", fmt.Sprintf(format, args...)) + bgwait() + xexit(2) } -// 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); -} +var atexits []func() // xexit exits the process with return code n. -void -xexit(int n) -{ - exit(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. -void -xatexit(void (*f)(void)) -{ - atexit(f); +func xatexit(f func()) { + atexits = append(atexits, 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); +func xprintf(format string, args ...interface{}) { + fmt.Printf(format, args...) } // 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); +func errprintf(format string, args ...interface{}) { + fmt.Fprintf(os.Stderr, format, args...) } // main takes care of OS-specific startup and dispatches to xmain. -int -main(int argc, char **argv) -{ - Buf b; - int osx; - struct utsname u; +func main() { + os.Setenv("TERM", "dumb") // disable escape codes in clang errors - setvbuf(stdout, nil, _IOLBF, 0); - setvbuf(stderr, nil, _IOLBF, 0); + slash = string(filepath.Separator) - 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); + 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") + } } - if(streq(gohostarch, "arm")) - maxnbg = 1; + 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. @@ -728,120 +381,77 @@ main(int argc, char **argv) // // 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; + 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 + } } - 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); + xinit() + xmain() } // 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; +func xsamefile(f1, f2 string) bool { + fi1, err1 := os.Stat(f1) + fi2, err2 := os.Stat(f2) + if err1 != nil || err2 != nil { + return f1 == f2 } - signal(SIGILL, SIG_DFL); - alarm(0); - signal(SIGALRM, SIG_DFL); - return r; + return os.SameFile(fi1, fi2) } -// SIGILL handler helper -static void -sigillhand(int signum) -{ - USED(signum); - siglongjmp(sigill_jmpbuf, 1); +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 } -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 +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" } -bool -cansse2(void) -{ - int info[4]; - - __cpuid(info, 1); - return (info[3] & (1<<26)) != 0; // SSE2 +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 } -#endif // PLAN9 -#endif // __WINDOWS__ +func useVFPv1() +func useVFPv3() diff --git a/src/cmd/dist/vfp_arm.s b/src/cmd/dist/vfp_arm.s new file mode 100644 index 0000000000..3cc11b298b --- /dev/null +++ b/src/cmd/dist/vfp_arm.s @@ -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 + VMOV.F64 D0, D0 + RET + +// try to run VFPv3-only "vmov.f64 d0, #112" instruction +TEXT useVFPv3(SB),NOSPLIT,$0 + VMOV.F64 $112, D0 + RET diff --git a/src/cmd/dist/vfp_default.s b/src/cmd/dist/vfp_default.s new file mode 100644 index 0000000000..c795b357f7 --- /dev/null +++ b/src/cmd/dist/vfp_default.s @@ -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/make.bash b/src/make.bash index a90937a77e..54c4d61249 100755 --- a/src/make.bash +++ b/src/make.bash @@ -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" +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 -# 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++ -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" "$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) diff --git a/src/sudo.bash b/src/sudo.bash deleted file mode 100755 index 33254c2c5e..0000000000 --- a/src/sudo.bash +++ /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 From d369f97342db25a6edd204ff938baa43d2f0ca5d Mon Sep 17 00:00:00 2001 From: Dave Cheney Date: Sun, 11 Jan 2015 06:12:20 +0000 Subject: [PATCH 3/7] cmd/dist: fix arm vfp detection * Use WORD declaration so 5a can't rewrite the instruction or complain about forms it doesn't know about. * Add the interpunct to function declaration. Change-Id: I8494548db21b3ea52f0e1e0e547d9ead8b93dfd1 Reviewed-on: https://go-review.googlesource.com/2682 Reviewed-by: Minux Ma --- src/cmd/dist/vfp_arm.s | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/cmd/dist/vfp_arm.s b/src/cmd/dist/vfp_arm.s index 3cc11b298b..2dbc59a5fb 100644 --- a/src/cmd/dist/vfp_arm.s +++ b/src/cmd/dist/vfp_arm.s @@ -5,11 +5,11 @@ #include "textflag.h" // try to run "vmov.f64 d0, d0" instruction -TEXT useVFPv1(SB),NOSPLIT,$0 - VMOV.F64 D0, D0 +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 - VMOV.F64 $112, D0 +TEXT ·useVFPv3(SB),NOSPLIT,$0 + WORD $0xeeb70b00 // vmov.f64 d0, #112 RET From afeca5c22ded0be2bafe6caa092280d1f8dd768a Mon Sep 17 00:00:00 2001 From: Brad Fitzpatrick Date: Mon, 12 Jan 2015 14:03:59 -0800 Subject: [PATCH 4/7] build: update Windows make.bat for Go-based dist These are corresponding Windows changes for the GOROOT_BOOTSTRAP and dist changes in https://golang.org/cl/2470 Change-Id: I21da2d63a60d8ae278ade9bb71ae0c314a2cf9b5 Reviewed-on: https://go-review.googlesource.com/2674 Reviewed-by: Alex Brainman --- src/cmd/dist/sys_windows.go | 2 +- src/make.bat | 16 ++++++++++++---- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/src/cmd/dist/sys_windows.go b/src/cmd/dist/sys_windows.go index c6867fb895..e9bfe9e3d9 100644 --- a/src/cmd/dist/sys_windows.go +++ b/src/cmd/dist/sys_windows.go @@ -11,7 +11,7 @@ import ( var ( modkernel32 = syscall.NewLazyDLL("kernel32.dll") - procGetSystemInfo = syscall.NewProc("GetSystemInfo") + procGetSystemInfo = modkernel32.NewProc("GetSystemInfo") ) // see http://msdn.microsoft.com/en-us/library/windows/desktop/ms724958(v=vs.85).aspx diff --git a/src/make.bat b/src/make.bat index 8d035b0d22..945c8cc5f9 100644 --- a/src/make.bat +++ b/src/make.bat @@ -56,13 +56,17 @@ 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% +"%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 +117,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% From b46b9429f05362b2b2227861811e50b47b9ec928 Mon Sep 17 00:00:00 2001 From: David du Colombier <0intro@gmail.com> Date: Tue, 13 Jan 2015 08:01:18 +0100 Subject: [PATCH 5/7] build: bootstrap on Plan 9 This change implements the requirement of old Go to build new Go on Plan 9. Also fix the build of the new cmd/dist written in Go. This is similar to the make.bash change in CL 2470, but applied to make.rc for Plan 9. Change-Id: Ifd9a3bd8658e2cee6f92b4c7f29ce86ee2a93c53 Reviewed-on: https://go-review.googlesource.com/2662 Reviewed-by: Brad Fitzpatrick --- src/cmd/dist/sys_default.go | 2 +- src/make.rc | 21 ++++++++++++--------- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/src/cmd/dist/sys_default.go b/src/cmd/dist/sys_default.go index ab97f19b3d..d7bc464f2a 100644 --- a/src/cmd/dist/sys_default.go +++ b/src/cmd/dist/sys_default.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build !windows,!plan9 +// +build !windows package main diff --git a/src/make.rc b/src/make.rc index 7a62d6af00..2d2076297e 100755 --- a/src/make.rc +++ b/src/make.rc @@ -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 $GOROOT_BOOTSTRAP/bin/go build -o cmd/dist/dist ./cmd/dist eval `{./cmd/dist/dist env -9} echo From db47a2706fb1078f6c5ddbaabc5bc09615c0457b Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Wed, 14 Jan 2015 11:50:21 -0500 Subject: [PATCH 6/7] [dev.cc] build: fix cross-compilation Fixes #9574. Change-Id: Ifd7ecccb25e934f9aba284b2d72b6b22f18cb0b6 Reviewed-on: https://go-review.googlesource.com/2812 Reviewed-by: Brad Fitzpatrick --- src/make.bash | 2 +- src/make.bat | 10 +++------- src/make.rc | 2 +- 3 files changed, 5 insertions(+), 9 deletions(-) diff --git a/src/make.bash b/src/make.bash index 54c4d61249..2b07ee7780 100755 --- a/src/make.bash +++ b/src/make.bash @@ -121,7 +121,7 @@ if [ ! -x "$GOROOT_BOOTSTRAP/bin/go" ]; then echo "Set \$GOROOT_BOOTSTRAP to a working Go tree >= Go 1.4." >&2 fi rm -f cmd/dist/dist -GOROOT="$GOROOT_BOOTSTRAP" "$GOROOT_BOOTSTRAP/bin/go" build -o cmd/dist/dist ./cmd/dist +GOROOT="$GOROOT_BOOTSTRAP" GOOS="$GOHOSTOS" GOARCH="$GOHOSTARCH" "$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) diff --git a/src/make.bat b/src/make.bat index 945c8cc5f9..62401b622d 100644 --- a/src/make.bat +++ b/src/make.bat @@ -45,16 +45,10 @@ 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 Go bootstrap tool. echo cmd/dist @@ -63,6 +57,8 @@ 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=%GOHOSTOS% +set GOARCH=%GOHOSTARCH% "%GOROOT_BOOTSTRAP%\bin\go" build -o cmd\dist\dist.exe .\cmd\dist endlocal if errorlevel 1 goto fail diff --git a/src/make.rc b/src/make.rc index 2d2076297e..761b93e995 100755 --- a/src/make.rc +++ b/src/make.rc @@ -58,7 +58,7 @@ if(! test -x $GOROOT_BOOTSTRAP/bin/go){ exit bootstrap } rm -f cmd/dist/dist -GOROOT=$GOROOT_BOOTSTRAP $GOROOT_BOOTSTRAP/bin/go build -o cmd/dist/dist ./cmd/dist +GOROOT=$GOROOT_BOOTSTRAP GOOS=$GOHOSTOS GOARCH=$GOHOSTARCH $GOROOT_BOOTSTRAP/bin/go build -o cmd/dist/dist ./cmd/dist eval `{./cmd/dist/dist env -9} echo From 1fac6d182916585ee30ce58486c443549c447a0e Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Wed, 14 Jan 2015 15:14:54 -0500 Subject: [PATCH 7/7] [dev.cc] build: do not pass GOHOSTOS and GOHOSTARCH to Go 1.4 build Go 1.4 should build what it knows how to build. GOHOSTOS and GOHOSTARCH are for the Go 1.5 build only. Change-Id: Id0f367f03485100a896e61cfdace4ac44a22e16d Reviewed-on: https://go-review.googlesource.com/2818 Reviewed-by: Brad Fitzpatrick --- src/make.bash | 2 +- src/make.bat | 4 ++-- src/make.rc | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/make.bash b/src/make.bash index 2b07ee7780..c8573c9954 100755 --- a/src/make.bash +++ b/src/make.bash @@ -121,7 +121,7 @@ if [ ! -x "$GOROOT_BOOTSTRAP/bin/go" ]; then echo "Set \$GOROOT_BOOTSTRAP to a working Go tree >= Go 1.4." >&2 fi rm -f cmd/dist/dist -GOROOT="$GOROOT_BOOTSTRAP" GOOS="$GOHOSTOS" GOARCH="$GOHOSTARCH" "$GOROOT_BOOTSTRAP/bin/go" build -o cmd/dist/dist ./cmd/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) diff --git a/src/make.bat b/src/make.bat index 62401b622d..fab9c88ff6 100644 --- a/src/make.bat +++ b/src/make.bat @@ -57,8 +57,8 @@ 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=%GOHOSTOS% -set GOARCH=%GOHOSTARCH% +set GOOS= +set GOARCH= "%GOROOT_BOOTSTRAP%\bin\go" build -o cmd\dist\dist.exe .\cmd\dist endlocal if errorlevel 1 goto fail diff --git a/src/make.rc b/src/make.rc index 761b93e995..5fe30aced7 100755 --- a/src/make.rc +++ b/src/make.rc @@ -58,7 +58,7 @@ if(! test -x $GOROOT_BOOTSTRAP/bin/go){ exit bootstrap } rm -f cmd/dist/dist -GOROOT=$GOROOT_BOOTSTRAP GOOS=$GOHOSTOS GOARCH=$GOHOSTARCH $GOROOT_BOOTSTRAP/bin/go build -o cmd/dist/dist ./cmd/dist +GOROOT=$GOROOT_BOOTSTRAP GOOS='' GOARCH='' $GOROOT_BOOTSTRAP/bin/go build -o cmd/dist/dist ./cmd/dist eval `{./cmd/dist/dist env -9} echo