This source file includes following definitions.
- find
- init
- rmworkdir
- chomp
- findgoversion
- setup
- install
- matchfield
- shouldbuild
- copy
- dopack
- clean
- usage
- cmdenv
- cmdbootstrap
- defaulttarg
- cmdinstall
- cmdclean
- cmdbanner
- cmdversion
#include "a.h"
#include "arg.h"
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;
char *defaultcc;
char *defaultcflags;
char *defaultldflags;
char *defaultcxxtarget;
char *defaultcctarget;
bool rebuildall;
bool defaultclang;
static bool shouldbuild(char*, char*);
static void copy(char*, char*, int);
static void dopack(char*, char*, char**, int);
static char *findgoversion(void);
static char *gochars = "5668";
static char *okgoarch[] = {
"arm",
"amd64",
"amd64p32",
"386",
};
static char *okgoos[] = {
"darwin",
"dragonfly",
"linux",
"solaris",
"freebsd",
"nacl",
"netbsd",
"openbsd",
"plan9",
"windows",
};
static void rmworkdir(void);
int
find(char *p, char **l, int n)
{
int i;
for(i=0; i<n; i++)
if(streq(p, l[i]))
return i;
return -1;
}
void
init(void)
{
char *p;
int i;
Buf b;
binit(&b);
xgetenv(&b, "GOROOT");
if(b.len > 0) {
if(b.len >= 2 && b.p[b.len - 1] == slash[0])
b.len--;
goroot = btake(&b);
}
xgetenv(&b, "GOBIN");
if(b.len == 0)
bprintf(&b, "%s%sbin", goroot, slash);
gobin = btake(&b);
xgetenv(&b, "GOOS");
if(b.len == 0)
bwritestr(&b, gohostos);
goos = btake(&b);
if(find(goos, okgoos, nelem(okgoos)) < 0)
fatal("unknown $GOOS %s", goos);
xgetenv(&b, "GOARM");
if(b.len == 0)
bwritestr(&b, xgetgoarm());
goarm = btake(&b);
xgetenv(&b, "GO386");
if(b.len == 0) {
if(cansse2())
bwritestr(&b, "sse2");
else
bwritestr(&b, "387");
}
go386 = btake(&b);
p = bpathf(&b, "%s/include/u.h", goroot);
if(!isfile(p)) {
fatal("$GOROOT is not set correctly or not exported\n"
"\tGOROOT=%s\n"
"\t%s does not exist", goroot, p);
}
xgetenv(&b, "GOHOSTARCH");
if(b.len > 0)
gohostarch = btake(&b);
i = find(gohostarch, okgoarch, nelem(okgoarch));
if(i < 0)
fatal("unknown $GOHOSTARCH %s", gohostarch);
bprintf(&b, "%c", gochars[i]);
gohostchar = btake(&b);
xgetenv(&b, "GOARCH");
if(b.len == 0)
bwritestr(&b, gohostarch);
goarch = btake(&b);
i = find(goarch, okgoarch, nelem(okgoarch));
if(i < 0)
fatal("unknown $GOARCH %s", goarch);
bprintf(&b, "%c", gochars[i]);
gochar = btake(&b);
xgetenv(&b, "GO_EXTLINK_ENABLED");
if(b.len > 0) {
goextlinkenabled = btake(&b);
if(!streq(goextlinkenabled, "0") && !streq(goextlinkenabled, "1"))
fatal("unknown $GO_EXTLINK_ENABLED %s", goextlinkenabled);
}
xgetenv(&b, "CC");
if(b.len == 0) {
if(defaultclang)
bprintf(&b, "clang");
else
bprintf(&b, "gcc");
}
defaultcc = btake(&b);
xgetenv(&b, "CFLAGS");
defaultcflags = btake(&b);
xgetenv(&b, "LDFLAGS");
defaultldflags = btake(&b);
xgetenv(&b, "CC_FOR_TARGET");
if(b.len == 0) {
bprintf(&b, defaultcc);
}
defaultcctarget = btake(&b);
xgetenv(&b, "CXX_FOR_TARGET");
if(b.len == 0) {
xgetenv(&b, "CXX");
if(b.len == 0) {
if(defaultclang)
bprintf(&b, "clang++");
else
bprintf(&b, "g++");
}
}
defaultcxxtarget = btake(&b);
xsetenv("GOROOT", goroot);
xsetenv("GOARCH", goarch);
xsetenv("GOOS", goos);
xsetenv("GOARM", goarm);
xsetenv("GO386", go386);
xsetenv("LANG", "C");
xsetenv("LANGUAGE", "en_US.UTF8");
goversion = findgoversion();
workdir = xworkdir();
xatexit(rmworkdir);
bpathf(&b, "%s/pkg/tool/%s_%s", goroot, gohostos, gohostarch);
tooldir = btake(&b);
bfree(&b);
}
static void
rmworkdir(void)
{
if(vflag > 1)
errprintf("rm -rf %s\n", workdir);
xremoveall(workdir);
}
static void
chomp(Buf *b)
{
int c;
while(b->len > 0 && ((c=b->p[b->len-1]) == ' ' || c == '\t' || c == '\r' || c == '\n'))
b->len--;
}
static char*
findgoversion(void)
{
char *tag, *rev, *p;
int i, nrev;
Buf b, path, bmore, branch;
Vec tags;
binit(&b);
binit(&path);
binit(&bmore);
binit(&branch);
vinit(&tags);
bpathf(&path, "%s/VERSION", goroot);
if(isfile(bstr(&path))) {
readfile(&b, bstr(&path));
chomp(&b);
if(b.len > 0)
goto done;
}
bpathf(&path, "%s/VERSION.cache", goroot);
if(isfile(bstr(&path))) {
readfile(&b, bstr(&path));
chomp(&b);
goto done;
}
run(&branch, goroot, CheckExit, "hg", "identify", "-b", nil);
chomp(&branch);
tag = "devel";
rev = ".";
run(&b, goroot, CheckExit, "hg", "log", "-b", bstr(&branch), "-r", ".:0", "--template", "{tags} + ", nil);
splitfields(&tags, bstr(&b));
nrev = 0;
for(i=0; i<tags.len; i++) {
p = tags.p[i];
if(streq(p, "+"))
nrev++;
if(hasprefix(p, "go") && (!contains(p, "beta") || nrev == 0)) {
tag = xstrdup(p);
if(nrev == 0)
rev = "";
break;
}
}
if(tag[0] == '\0') {
bprintf(&b, "branch.%s", bstr(&branch));
tag = btake(&b);
}
if(rev[0]) {
run(&bmore, goroot, CheckExit, "hg", "log", "--template", " +{node|short} {date|date}", "-r", rev, nil);
chomp(&bmore);
}
bprintf(&b, "%s", tag);
if(bmore.len > 0)
bwriteb(&b, &bmore);
writefile(&b, bstr(&path), 0);
done:
p = btake(&b);
bfree(&b);
bfree(&path);
bfree(&bmore);
bfree(&branch);
vfree(&tags);
return p;
}
static char *oldtool[] = {
"5a", "5c", "5g", "5l",
"6a", "6c", "6g", "6l",
"8a", "8c", "8g", "8l",
"6cov",
"6nm",
"6prof",
"cgo",
"ebnflint",
"goapi",
"gofix",
"goinstall",
"gomake",
"gopack",
"gopprof",
"gotest",
"gotype",
"govet",
"goyacc",
"quietgcc",
};
static char *unreleased[] = {
"src/cmd/link",
"src/pkg/debug/goobj",
"src/pkg/old",
};
static void
setup(void)
{
int i;
Buf b;
char *p;
binit(&b);
p = bpathf(&b, "%s/bin", goroot);
if(!isdir(p))
xmkdir(p);
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);
}
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(rebuildall)
xremoveall(tooldir);
xmkdirall(tooldir);
xremoveall(bpathf(&b, "%s/bin/tool", goroot));
for(i=0; i<nelem(oldtool); i++)
xremove(bpathf(&b, "%s/bin/%s", goroot, oldtool[i]));
for(i=0; gochars[i]; i++) {
if(isfile(bprintf(&b, "%s%s%c%s", gobin, slash, gochars[i], "g"))) {
for(i=0; i<nelem(oldtool); i++)
xremove(bprintf(&b, "%s%s%s", gobin, slash, oldtool[i]));
break;
}
}
if(hasprefix(goversion, "release.") || (hasprefix(goversion, "go") && !contains(goversion, "beta"))) {
for(i=0; i<nelem(unreleased); i++)
if(isdir(bpathf(&b, "%s/%s", goroot, unreleased[i])))
fatal("%s should not exist in release build", bstr(&b));
}
bfree(&b);
}
static char *proto_gccargs[] = {
"-Wall",
"-Wstrict-prototypes",
"-Wextra",
"-Wunused",
"-Wno-sign-compare",
"-Wno-missing-braces",
"-Wno-parentheses",
"-Wno-unknown-pragmas",
"-Wno-switch",
"-Wno-comment",
"-Wno-missing-field-initializers",
"-Werror",
"-fno-common",
"-ggdb",
"-pipe",
};
static char *proto_gccargs2[] = {
"-Wuninitialized",
#if defined(__NetBSD__) && defined(__arm__)
"-O1",
#else
"-O2",
#endif
};
static Vec gccargs, ldargs;
static struct {
char *prefix;
char *dep[20];
} deptab[] = {
{"lib9", {
"$GOROOT/include/u.h",
"$GOROOT/include/utf.h",
"$GOROOT/include/fmt.h",
"$GOROOT/include/libc.h",
"fmt/*",
"utf/*",
}},
{"libbio", {
"$GOROOT/include/u.h",
"$GOROOT/include/utf.h",
"$GOROOT/include/fmt.h",
"$GOROOT/include/libc.h",
"$GOROOT/include/bio.h",
}},
{"liblink", {
"$GOROOT/include/u.h",
"$GOROOT/include/utf.h",
"$GOROOT/include/fmt.h",
"$GOROOT/include/libc.h",
"$GOROOT/include/bio.h",
"$GOROOT/include/ar.h",
"$GOROOT/include/link.h",
"anames5.c",
"anames6.c",
"anames8.c",
}},
{"cmd/cc", {
"-pgen.c",
"-pswt.c",
}},
{"cmd/gc", {
"-cplx.c",
"-pgen.c",
"-plive.c",
"-popt.c",
"-y1.tab.c",
"opnames.h",
}},
{"cmd/5c", {
"../cc/pgen.c",
"../cc/pswt.c",
"$GOROOT/pkg/obj/$GOHOSTOS_$GOHOSTARCH/libcc.a",
}},
{"cmd/6c", {
"../cc/pgen.c",
"../cc/pswt.c",
"$GOROOT/pkg/obj/$GOHOSTOS_$GOHOSTARCH/libcc.a",
}},
{"cmd/8c", {
"../cc/pgen.c",
"../cc/pswt.c",
"$GOROOT/pkg/obj/$GOHOSTOS_$GOHOSTARCH/libcc.a",
}},
{"cmd/5g", {
"../gc/cplx.c",
"../gc/pgen.c",
"../gc/plive.c",
"../gc/popt.c",
"../gc/popt.h",
"$GOROOT/pkg/obj/$GOHOSTOS_$GOHOSTARCH/libgc.a",
}},
{"cmd/6g", {
"../gc/cplx.c",
"../gc/pgen.c",
"../gc/plive.c",
"../gc/popt.c",
"../gc/popt.h",
"$GOROOT/pkg/obj/$GOHOSTOS_$GOHOSTARCH/libgc.a",
}},
{"cmd/8g", {
"../gc/cplx.c",
"../gc/pgen.c",
"../gc/plive.c",
"../gc/popt.c",
"../gc/popt.h",
"$GOROOT/pkg/obj/$GOHOSTOS_$GOHOSTARCH/libgc.a",
}},
{"cmd/5l", {
"../ld/*",
}},
{"cmd/6l", {
"../ld/*",
}},
{"cmd/8l", {
"../ld/*",
}},
{"cmd/go", {
"zdefaultcc.go",
}},
{"cmd/", {
"$GOROOT/pkg/obj/$GOHOSTOS_$GOHOSTARCH/liblink.a",
"$GOROOT/pkg/obj/$GOHOSTOS_$GOHOSTARCH/libbio.a",
"$GOROOT/pkg/obj/$GOHOSTOS_$GOHOSTARCH/lib9.a",
}},
{"pkg/runtime", {
"zaexperiment.h",
"zasm_$GOOS_$GOARCH.h",
"zsys_$GOOS_$GOARCH.s",
"zgoarch_$GOARCH.go",
"zgoos_$GOOS.go",
"zruntime_defs_$GOOS_$GOARCH.go",
"zversion.go",
}},
};
char *depsuffix[] = {
".c",
".h",
".s",
".go",
".goc",
};
static struct {
char *nameprefix;
void (*gen)(char*, char*);
} gentab[] = {
{"opnames.h", gcopnames},
{"anames5.c", mkanames},
{"anames6.c", mkanames},
{"anames8.c", mkanames},
{"zasm_", mkzasm},
{"zdefaultcc.go", mkzdefaultcc},
{"zsys_", mkzsys},
{"zgoarch_", mkzgoarch},
{"zgoos_", mkzgoos},
{"zruntime_defs_", mkzruntimedefs},
{"zversion.go", mkzversion},
{"zaexperiment.h", mkzexperiment},
{"enam.c", nil},
};
static void
install(char *dir)
{
char *name, *p, *elem, *prefix, *exe;
bool islib, ispkg, isgo, stale, ispackcmd;
Buf b, b1, path;
Vec compile, files, link, go, missing, clean, lib, extra;
Time ttarg, t;
int i, j, k, n, doclean, targ;
if(vflag) {
if(!streq(goos, gohostos) || !streq(goarch, gohostarch))
errprintf("%s (%s/%s)\n", dir, goos, goarch);
else
errprintf("%s\n", dir);
}
binit(&b);
binit(&b1);
binit(&path);
vinit(&compile);
vinit(&files);
vinit(&link);
vinit(&go);
vinit(&missing);
vinit(&clean);
vinit(&lib);
vinit(&extra);
bpathf(&path, "%s/src/%s", goroot, dir);
name = lastelem(dir);
if(hasprefix(dir, "misc/")) {
copy(bpathf(&b, "%s/%s", tooldir, name),
bpathf(&b1, "%s/misc/%s", goroot, name), 1);
goto out;
}
if(gccargs.len == 0) {
bprintf(&b, "%s %s", defaultcc, defaultcflags);
splitfields(&gccargs, bstr(&b));
for(i=0; i<nelem(proto_gccargs); i++)
vadd(&gccargs, proto_gccargs[i]);
if(defaultcflags[0] == '\0') {
for(i=0; i<nelem(proto_gccargs2); i++)
vadd(&gccargs, proto_gccargs2[i]);
}
if(contains(gccargs.p[0], "clang")) {
vadd(&gccargs, "-fno-caret-diagnostics");
vadd(&gccargs, "-Qunused-arguments");
}
vadd(&gccargs, "-fmessage-length=0");
if(streq(gohostos, "darwin")) {
vadd(&gccargs, "-mmacosx-version-min=10.6");
}
}
if(ldargs.len == 0 && defaultldflags[0] != '\0') {
bprintf(&b, "%s", defaultldflags);
splitfields(&ldargs, bstr(&b));
}
islib = hasprefix(dir, "lib") || streq(dir, "cmd/cc") || streq(dir, "cmd/gc");
ispkg = hasprefix(dir, "pkg");
isgo = ispkg || streq(dir, "cmd/go") || streq(dir, "cmd/cgo");
exe = "";
if(streq(gohostos, "windows"))
exe = ".exe";
ispackcmd = 0;
if(islib) {
vadd(&link, "ar");
if(streq(gohostos, "plan9"))
vadd(&link, "rc");
else
vadd(&link, "rsc");
prefix = "";
if(!hasprefix(name, "lib"))
prefix = "lib";
targ = link.len;
vadd(&link, bpathf(&b, "%s/pkg/obj/%s_%s/%s%s.a", goroot, gohostos, gohostarch, prefix, name));
} else if(ispkg) {
ispackcmd = 1;
vadd(&link, "pack");
p = bprintf(&b, "%s/pkg/%s_%s/%s", goroot, goos, goarch, dir+4);
*xstrrchr(p, '/') = '\0';
xmkdirall(p);
targ = link.len;
vadd(&link, bpathf(&b, "%s/pkg/%s_%s/%s.a", goroot, goos, goarch, dir+4));
} else if(streq(dir, "cmd/go") || streq(dir, "cmd/cgo")) {
vadd(&link, bpathf(&b, "%s/%sl", tooldir, gochar));
vadd(&link, "-o");
elem = name;
if(streq(elem, "go"))
elem = "go_bootstrap";
targ = link.len;
vadd(&link, bpathf(&b, "%s/%s%s", tooldir, elem, exe));
} else {
if(streq(gohostos, "plan9")) {
vadd(&link, bprintf(&b, "%sl", gohostchar));
vadd(&link, "-o");
targ = link.len;
vadd(&link, bpathf(&b, "%s/%s", tooldir, name));
} else {
vcopy(&link, gccargs.p, gccargs.len);
vcopy(&link, ldargs.p, ldargs.len);
if(sflag)
vadd(&link, "-static");
vadd(&link, "-o");
targ = link.len;
vadd(&link, bpathf(&b, "%s/%s%s", tooldir, name, exe));
if(streq(gohostarch, "amd64"))
vadd(&link, "-m64");
else if(streq(gohostarch, "386"))
vadd(&link, "-m32");
}
}
ttarg = mtime(link.p[targ]);
xreaddir(&files, bstr(&path));
n = 0;
for(i=0; i<files.len; i++) {
p = files.p[i];
if(hasprefix(p, ".") || (hasprefix(p, "_") && hassuffix(p, ".go")))
xfree(p);
else
files.p[n++] = p;
}
files.len = n;
for(i=0; i<nelem(deptab); i++) {
if(streq(dir, deptab[i].prefix) ||
(hassuffix(deptab[i].prefix, "/") && hasprefix(dir, deptab[i].prefix))) {
for(j=0; (p=deptab[i].dep[j])!=nil; j++) {
breset(&b1);
bwritestr(&b1, p);
bsubst(&b1, "$GOROOT", goroot);
bsubst(&b1, "$GOOS", goos);
bsubst(&b1, "$GOARCH", goarch);
bsubst(&b1, "$GOHOSTOS", gohostos);
bsubst(&b1, "$GOHOSTARCH", gohostarch);
p = bstr(&b1);
if(hassuffix(p, ".a")) {
vadd(&lib, bpathf(&b, "%s", p));
continue;
}
if(hassuffix(p, "/*")) {
bpathf(&b, "%s/%s", bstr(&path), p);
b.len -= 2;
xreaddir(&extra, bstr(&b));
bprintf(&b, "%s", p);
b.len -= 2;
for(k=0; k<extra.len; k++)
vadd(&files, bpathf(&b1, "%s/%s", bstr(&b), extra.p[k]));
continue;
}
if(hasprefix(p, "-")) {
p++;
n = 0;
for(k=0; k<files.len; k++) {
if(hasprefix(files.p[k], p))
xfree(files.p[k]);
else
files.p[n++] = files.p[k];
}
files.len = n;
continue;
}
vadd(&files, p);
}
}
}
vuniq(&files);
for(i=0; i<files.len; i++) {
if(!isabs(files.p[i])) {
bpathf(&b, "%s/%s", bstr(&path), files.p[i]);
xfree(files.p[i]);
files.p[i] = btake(&b);
}
}
stale = rebuildall;
n = 0;
for(i=0; i<files.len; i++) {
p = files.p[i];
for(j=0; j<nelem(depsuffix); j++)
if(hassuffix(p, depsuffix[j]))
goto ok;
xfree(files.p[i]);
continue;
ok:
t = mtime(p);
if(t != 0 && !hassuffix(p, ".a") && !shouldbuild(p, dir)) {
xfree(files.p[i]);
continue;
}
if(hassuffix(p, ".go"))
vadd(&go, p);
if(t > ttarg)
stale = 1;
if(t == 0) {
vadd(&missing, p);
files.p[n++] = files.p[i];
continue;
}
files.p[n++] = files.p[i];
}
files.len = n;
if(files.len == 0)
goto out;
for(i=0; i<lib.len && !stale; i++)
if(mtime(lib.p[i]) > ttarg)
stale = 1;
if(!stale)
goto out;
if(streq(dir, "pkg/runtime")) {
copy(bpathf(&b, "%s/arch_GOARCH.h", workdir),
bpathf(&b1, "%s/arch_%s.h", bstr(&path), goarch), 0);
copy(bpathf(&b, "%s/defs_GOOS_GOARCH.h", workdir),
bpathf(&b1, "%s/defs_%s_%s.h", bstr(&path), goos, goarch), 0);
p = bpathf(&b1, "%s/signal_%s_%s.h", bstr(&path), goos, goarch);
if(isfile(p))
copy(bpathf(&b, "%s/signal_GOOS_GOARCH.h", workdir), p, 0);
copy(bpathf(&b, "%s/os_GOOS.h", workdir),
bpathf(&b1, "%s/os_%s.h", bstr(&path), goos), 0);
copy(bpathf(&b, "%s/signals_GOOS.h", workdir),
bpathf(&b1, "%s/signals_%s.h", bstr(&path), goos), 0);
}
for(i=0; i<files.len; i++) {
p = files.p[i];
elem = lastelem(p);
for(j=0; j<nelem(gentab); j++) {
if(gentab[j].gen == nil)
continue;
if(hasprefix(elem, gentab[j].nameprefix)) {
if(vflag > 1)
errprintf("generate %s\n", p);
gentab[j].gen(bstr(&path), p);
goto built;
}
}
if(find(p, missing.p, missing.len) >= 0)
fatal("missing file %s", p);
built:;
}
if(streq(dir, "pkg/runtime")) {
copy(bpathf(&b, "%s/zasm_GOOS_GOARCH.h", workdir),
bpathf(&b1, "%s/zasm_%s_%s.h", bstr(&path), goos, goarch), 0);
}
if(streq(dir, "pkg/runtime")) {
for(i=0; i<files.len; i++) {
p = files.p[i];
if(!hassuffix(p, ".goc"))
continue;
bprintf(&b, "%s%sz%s", bstr(&path), slash, lastelem(p));
b.len -= 4;
bwritef(&b, "_%s_%s.c", goos, goarch);
goc2c(p, bstr(&b));
vadd(&files, bstr(&b));
}
vuniq(&files);
}
if((!streq(goos, gohostos) || !streq(goarch, gohostarch)) && isgo) {
if(vflag > 1)
errprintf("skip build for cross-compile %s\n", dir);
goto nobuild;
}
for(i=0; i<files.len; i++) {
if(!hassuffix(files.p[i], ".c") && !hassuffix(files.p[i], ".s"))
continue;
name = lastelem(files.p[i]);
vreset(&compile);
if(!isgo) {
if(streq(gohostos, "plan9")) {
vadd(&compile, bprintf(&b, "%sc", gohostchar));
vadd(&compile, "-FTVwp");
vadd(&compile, "-DPLAN9");
vadd(&compile, "-D__STDC__=1");
vadd(&compile, "-D__SIZE_TYPE__=ulong");
vadd(&compile, bpathf(&b, "-I%s/include/plan9", goroot));
vadd(&compile, bpathf(&b, "-I%s/include/plan9/%s", goroot, gohostarch));
} else {
vcopy(&compile, gccargs.p, gccargs.len);
vadd(&compile, "-c");
if(streq(gohostarch, "amd64"))
vadd(&compile, "-m64");
else if(streq(gohostarch, "386"))
vadd(&compile, "-m32");
vadd(&compile, "-I");
vadd(&compile, bpathf(&b, "%s/include", goroot));
}
if(streq(dir, "lib9"))
vadd(&compile, "-DPLAN9PORT");
vadd(&compile, "-I");
vadd(&compile, bstr(&path));
if(streq(name, "goos.c")) {
vadd(&compile, "-D");
vadd(&compile, bprintf(&b, "GOOS=\"%s\"", goos));
vadd(&compile, "-D");
vadd(&compile, bprintf(&b, "GOARCH=\"%s\"", goarch));
bprintf(&b1, "%s", goroot_final);
bsubst(&b1, "\\", "\\\\");
vadd(&compile, "-D");
vadd(&compile, bprintf(&b, "GOROOT=\"%s\"", bstr(&b1)));
vadd(&compile, "-D");
vadd(&compile, bprintf(&b, "GOVERSION=\"%s\"", goversion));
vadd(&compile, "-D");
vadd(&compile, bprintf(&b, "GOARM=\"%s\"", goarm));
vadd(&compile, "-D");
vadd(&compile, bprintf(&b, "GO386=\"%s\"", go386));
vadd(&compile, "-D");
vadd(&compile, bprintf(&b, "GO_EXTLINK_ENABLED=\"%s\"", goextlinkenabled));
}
if(streq(name, "lex.c")) {
xgetenv(&b, "GOEXPERIMENT");
vadd(&compile, "-D");
vadd(&compile, bprintf(&b1, "GOEXPERIMENT=\"%s\"", bstr(&b)));
}
} else {
if(hassuffix(files.p[i], ".s"))
vadd(&compile, bpathf(&b, "%s/%sa", tooldir, gochar));
else {
vadd(&compile, bpathf(&b, "%s/%sc", tooldir, gochar));
vadd(&compile, "-F");
vadd(&compile, "-V");
vadd(&compile, "-w");
}
vadd(&compile, "-I");
vadd(&compile, workdir);
vadd(&compile, "-I");
vadd(&compile, bprintf(&b, "%s/pkg/%s_%s", goroot, goos, goarch));
vadd(&compile, "-D");
vadd(&compile, bprintf(&b, "GOOS_%s", goos));
vadd(&compile, "-D");
vadd(&compile, bprintf(&b, "GOARCH_%s", goarch));
vadd(&compile, "-D");
vadd(&compile, bprintf(&b, "GOOS_GOARCH_%s_%s", goos, goarch));
}
bpathf(&b, "%s/%s", workdir, lastelem(files.p[i]));
doclean = 1;
if(!isgo && streq(gohostos, "darwin")) {
bpathf(&b1, "%s/pkg/obj/%s", goroot, dir);
xmkdirall(bstr(&b1));
bpathf(&b, "%s/%s", bstr(&b1), lastelem(files.p[i]));
doclean = 0;
}
if(streq(gohostos, "plan9"))
b.p[b.len-1] = gohostchar[0];
else
b.p[b.len-1] = 'o';
vadd(&compile, "-o");
vadd(&compile, bstr(&b));
vadd(&compile, files.p[i]);
bgrunv(bstr(&path), CheckExit, &compile);
vadd(&link, bstr(&b));
if(doclean)
vadd(&clean, bstr(&b));
}
bgwait();
if(isgo) {
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));
vadd(&compile, "-p");
if(hasprefix(dir, "pkg/"))
vadd(&compile, dir+4);
else
vadd(&compile, "main");
if(streq(dir, "pkg/runtime"))
vadd(&compile, "-+");
vcopy(&compile, go.p, go.len);
runv(nil, bstr(&path), CheckExit, &compile);
if(ispackcmd) {
xremove(link.p[targ]);
dopack(link.p[targ], bstr(&b), &link.p[targ+1], link.len - (targ+1));
goto nobuild;
}
}
if(!islib && !isgo) {
vcopy(&link, lib.p, lib.len);
if(!streq(gohostos, "plan9"))
vadd(&link, "-lm");
}
xremove(link.p[targ]);
runv(nil, nil, CheckExit, &link);
nobuild:
if(streq(dir, "pkg/runtime")) {
copy(bpathf(&b, "%s/pkg/%s_%s/cgocall.h", goroot, goos, goarch),
bpathf(&b1, "%s/src/pkg/runtime/cgocall.h", goroot), 0);
copy(bpathf(&b, "%s/pkg/%s_%s/runtime.h", goroot, goos, goarch),
bpathf(&b1, "%s/src/pkg/runtime/runtime.h", goroot), 0);
}
out:
for(i=0; i<clean.len; i++)
xremove(clean.p[i]);
bfree(&b);
bfree(&b1);
bfree(&path);
vfree(&compile);
vfree(&files);
vfree(&link);
vfree(&go);
vfree(&missing);
vfree(&clean);
vfree(&lib);
vfree(&extra);
}
static bool
matchfield(char *f)
{
char *p;
bool res;
p = xstrrchr(f, ',');
if(p == nil)
return streq(f, goos) || streq(f, goarch) || streq(f, "cmd_go_bootstrap") || streq(f, "go1.1");
*p = 0;
res = matchfield(f) && matchfield(p+1);
*p = ',';
return res;
}
static bool
shouldbuild(char *file, char *dir)
{
char *name, *p;
int i, j, ret;
Buf b;
Vec lines, fields;
name = lastelem(file);
for(i=0; i<nelem(okgoos); i++)
if(contains(name, okgoos[i]) && !streq(okgoos[i], goos))
return 0;
for(i=0; i<nelem(okgoarch); i++)
if(contains(name, okgoarch[i]) && !streq(okgoarch[i], goarch))
return 0;
if(contains(name, "_test"))
return 0;
if(hassuffix(file, "cmd/go/doc.go") || hassuffix(file, "cmd\\go\\doc.go"))
return 0;
if(hassuffix(file, "cmd/cgo/doc.go") || hassuffix(file, "cmd\\cgo\\doc.go"))
return 0;
binit(&b);
vinit(&lines);
vinit(&fields);
ret = 1;
readfile(&b, file);
splitlines(&lines, bstr(&b));
for(i=0; i<lines.len; i++) {
p = lines.p[i];
while(*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n')
p++;
if(*p == '\0')
continue;
if(contains(p, "package documentation")) {
ret = 0;
goto out;
}
if(contains(p, "package main") && !streq(dir, "cmd/go") && !streq(dir, "cmd/cgo")) {
ret = 0;
goto out;
}
if(!hasprefix(p, "//"))
break;
if(!contains(p, "+build"))
continue;
splitfields(&fields, lines.p[i]);
if(fields.len < 2 || !streq(fields.p[1], "+build"))
continue;
for(j=2; j<fields.len; j++) {
p = fields.p[j];
if((*p == '!' && !matchfield(p+1)) || matchfield(p))
goto fieldmatch;
}
ret = 0;
goto out;
fieldmatch:;
}
out:
bfree(&b);
vfree(&lines);
vfree(&fields);
return ret;
}
static void
copy(char *dst, char *src, int exec)
{
Buf b;
if(vflag > 1)
errprintf("cp %s %s\n", src, dst);
binit(&b);
readfile(&b, src);
writefile(&b, dst, exec);
bfree(&b);
}
static void
dopack(char *dst, char *src, char **extra, int nextra)
{
int i;
char c, *p, *q;
Buf b, bdst;
binit(&b);
binit(&bdst);
readfile(&bdst, src);
for(i=0; i<nextra; i++) {
readfile(&b, extra[i]);
p = xstrrchr(extra[i], '/');
if(p)
p++;
q = xstrrchr(extra[i], '\\');
if(q) {
q++;
if(p == nil || q > p)
p = q;
}
if(p == nil)
p = extra[i];
bwritef(&bdst, "%-16.16s%-12d%-6d%-6d%-8o%-10d`\n", p, 0, 0, 0, 0644, b.len);
bwriteb(&bdst, &b);
if(b.len&1) {
c = 0;
bwrite(&bdst, &c, 1);
}
}
writefile(&bdst, dst, 0);
bfree(&b);
bfree(&bdst);
}
static char *buildorder[] = {
"lib9",
"libbio",
"liblink",
"misc/pprof",
"cmd/cc",
"cmd/gc",
"cmd/%sl",
"cmd/%sa",
"cmd/%sc",
"cmd/%sg",
"pkg/runtime",
"pkg/errors",
"pkg/sync/atomic",
"pkg/sync",
"pkg/io",
"pkg/unicode",
"pkg/unicode/utf8",
"pkg/unicode/utf16",
"pkg/bytes",
"pkg/math",
"pkg/strings",
"pkg/strconv",
"pkg/bufio",
"pkg/sort",
"pkg/container/heap",
"pkg/encoding/base64",
"pkg/syscall",
"pkg/time",
"pkg/os",
"pkg/reflect",
"pkg/fmt",
"pkg/encoding",
"pkg/encoding/json",
"pkg/flag",
"pkg/path/filepath",
"pkg/path",
"pkg/io/ioutil",
"pkg/log",
"pkg/regexp/syntax",
"pkg/regexp",
"pkg/go/token",
"pkg/go/scanner",
"pkg/go/ast",
"pkg/go/parser",
"pkg/os/exec",
"pkg/os/signal",
"pkg/net/url",
"pkg/text/template/parse",
"pkg/text/template",
"pkg/go/doc",
"pkg/go/build",
"cmd/go",
};
static char *cleantab[] = {
"cmd/5a",
"cmd/5c",
"cmd/5g",
"cmd/5l",
"cmd/6a",
"cmd/6c",
"cmd/6g",
"cmd/6l",
"cmd/8a",
"cmd/8c",
"cmd/8g",
"cmd/8l",
"cmd/cc",
"cmd/gc",
"cmd/go",
"lib9",
"libbio",
"liblink",
"pkg/bufio",
"pkg/bytes",
"pkg/container/heap",
"pkg/encoding",
"pkg/encoding/base64",
"pkg/encoding/json",
"pkg/errors",
"pkg/flag",
"pkg/fmt",
"pkg/go/ast",
"pkg/go/build",
"pkg/go/doc",
"pkg/go/parser",
"pkg/go/scanner",
"pkg/go/token",
"pkg/io",
"pkg/io/ioutil",
"pkg/log",
"pkg/math",
"pkg/net/url",
"pkg/os",
"pkg/os/exec",
"pkg/path",
"pkg/path/filepath",
"pkg/reflect",
"pkg/regexp",
"pkg/regexp/syntax",
"pkg/runtime",
"pkg/sort",
"pkg/strconv",
"pkg/strings",
"pkg/sync",
"pkg/sync/atomic",
"pkg/syscall",
"pkg/text/template",
"pkg/text/template/parse",
"pkg/time",
"pkg/unicode",
"pkg/unicode/utf16",
"pkg/unicode/utf8",
};
static void
clean(void)
{
int i, j, k;
Buf b, path;
Vec dir;
binit(&b);
binit(&path);
vinit(&dir);
for(i=0; i<nelem(cleantab); i++) {
bpathf(&path, "%s/src/%s", goroot, cleantab[i]);
xreaddir(&dir, bstr(&path));
for(j=0; j<dir.len; j++) {
for(k=0; k<nelem(gentab); k++) {
if(hasprefix(dir.p[j], gentab[k].nameprefix))
xremove(bpathf(&b, "%s/%s", bstr(&path), dir.p[j]));
}
}
if(hasprefix(cleantab[i], "cmd/"))
xremove(bpathf(&b, "%s/%s", bstr(&path), cleantab[i]+4));
}
vreset(&dir);
bpathf(&path, "%s/src/pkg/runtime", goroot);
xreaddir(&dir, bstr(&path));
for(j=0; j<dir.len; j++) {
if(hasprefix(dir.p[j], "z"))
xremove(bpathf(&b, "%s/%s", bstr(&path), dir.p[j]));
}
if(rebuildall) {
xremoveall(bpathf(&b, "%s/pkg/obj/%s_%s", goroot, gohostos, gohostarch));
xremoveall(bpathf(&b, "%s/pkg/%s_%s", goroot, gohostos, gohostarch));
xremoveall(bpathf(&b, "%s/pkg/%s_%s", goroot, goos, goarch));
xremoveall(tooldir);
xremove(bpathf(&b, "%s/VERSION.cache", goroot));
}
bfree(&b);
bfree(&path);
vfree(&dir);
}
void
usage(void)
{
xprintf("usage: go tool dist [command]\n"
"Commands are:\n"
"\n"
"banner print installation banner\n"
"bootstrap rebuild everything\n"
"clean deletes all built files\n"
"env [-p] print environment (-p: include $PATH)\n"
"install [dir] install individual directory\n"
"version print Go version\n"
"\n"
"All commands take -v flags to emit extra information.\n"
);
xexit(2);
}
void
cmdenv(int argc, char **argv)
{
bool pflag;
char *sep;
Buf b, b1;
char *format;
binit(&b);
binit(&b1);
format = "%s=\"%s\"\n";
pflag = 0;
ARGBEGIN{
case '9':
format = "%s='%s'\n";
break;
case 'p':
pflag = 1;
break;
case 'v':
vflag++;
break;
case 'w':
format = "set %s=%s\r\n";
break;
default:
usage();
}ARGEND
if(argc > 0)
usage();
xprintf(format, "CC", defaultcc);
xprintf(format, "CC_FOR_TARGET", defaultcctarget);
xprintf(format, "GOROOT", goroot);
xprintf(format, "GOBIN", gobin);
xprintf(format, "GOARCH", goarch);
xprintf(format, "GOOS", goos);
xprintf(format, "GOHOSTARCH", gohostarch);
xprintf(format, "GOHOSTOS", gohostos);
xprintf(format, "GOTOOLDIR", tooldir);
xprintf(format, "GOCHAR", gochar);
if(streq(goarch, "arm"))
xprintf(format, "GOARM", goarm);
if(streq(goarch, "386"))
xprintf(format, "GO386", go386);
if(pflag) {
sep = ":";
if(streq(gohostos, "windows"))
sep = ";";
xgetenv(&b, "PATH");
bprintf(&b1, "%s%s%s", gobin, sep, bstr(&b));
xprintf(format, "PATH", bstr(&b1));
}
bfree(&b);
bfree(&b1);
}
void
cmdbootstrap(int argc, char **argv)
{
int i;
Buf b;
char *oldgoos, *oldgoarch, *oldgochar;
binit(&b);
ARGBEGIN{
case 'a':
rebuildall = 1;
break;
case 's':
sflag++;
break;
case 'v':
vflag++;
break;
default:
usage();
}ARGEND
if(argc > 0)
usage();
if(rebuildall)
clean();
goversion = findgoversion();
setup();
xsetenv("GOROOT", goroot);
xsetenv("GOROOT_FINAL", goroot_final);
oldgoos = goos;
oldgoarch = goarch;
oldgochar = gochar;
goos = gohostos;
goarch = gohostarch;
gochar = gohostchar;
xsetenv("GOARCH", goarch);
xsetenv("GOOS", goos);
for(i=0; i<nelem(buildorder); i++) {
install(bprintf(&b, buildorder[i], gohostchar));
if(!streq(oldgochar, gohostchar) && xstrstr(buildorder[i], "%s"))
install(bprintf(&b, buildorder[i], oldgochar));
}
goos = oldgoos;
goarch = oldgoarch;
gochar = oldgochar;
xsetenv("GOARCH", goarch);
xsetenv("GOOS", goos);
if(!streq(goos, gohostos) || !streq(goarch, gohostarch))
install("pkg/runtime");
bfree(&b);
}
static char*
defaulttarg(void)
{
char *p;
Buf pwd, src, real_src;
binit(&pwd);
binit(&src);
binit(&real_src);
xgetwd(&pwd);
p = btake(&pwd);
bpathf(&src, "%s/src/", goroot);
xrealwd(&real_src, bstr(&src));
if(!hasprefix(p, bstr(&real_src)))
fatal("current directory %s is not under %s", p, bstr(&real_src));
p += real_src.len;
if(*p == slash[0])
p++;
bfree(&pwd);
bfree(&src);
bfree(&real_src);
return p;
}
void
cmdinstall(int argc, char **argv)
{
int i;
ARGBEGIN{
case 's':
sflag++;
break;
case 'v':
vflag++;
break;
default:
usage();
}ARGEND
if(argc == 0)
install(defaulttarg());
for(i=0; i<argc; i++)
install(argv[i]);
}
void
cmdclean(int argc, char **argv)
{
ARGBEGIN{
case 'v':
vflag++;
break;
default:
usage();
}ARGEND
if(argc > 0)
usage();
clean();
}
void
cmdbanner(int argc, char **argv)
{
char *pathsep, *pid, *ns;
Buf b, b1, search, path;
ARGBEGIN{
case 'v':
vflag++;
break;
default:
usage();
}ARGEND
if(argc > 0)
usage();
binit(&b);
binit(&b1);
binit(&search);
binit(&path);
xprintf("\n");
xprintf("---\n");
xprintf("Installed Go for %s/%s in %s\n", goos, goarch, goroot);
xprintf("Installed commands in %s\n", gobin);
if(!xsamefile(goroot_final, goroot)) {
} else if(streq(gohostos, "plan9")) {
readfile(&b, "#c/pid");
bsubst(&b, " ", "");
pid = btake(&b);
bprintf(&b, "/proc/%s/ns", pid);
ns = btake(&b);
readfile(&b, ns);
bprintf(&search, "bind -b %s /bin\n", gobin);
if(xstrstr(bstr(&b), bstr(&search)) == nil)
xprintf("*** You need to bind %s before /bin.\n", gobin);
} else {
xgetenv(&b, "PATH");
pathsep = ":";
if(streq(gohostos, "windows"))
pathsep = ";";
bprintf(&b1, "%s%s%s", pathsep, bstr(&b), pathsep);
bprintf(&search, "%s%s%s", pathsep, gobin, pathsep);
if(xstrstr(bstr(&b1), bstr(&search)) == nil)
xprintf("*** You need to add %s to your PATH.\n", gobin);
}
if(streq(gohostos, "darwin")) {
if(isfile(bpathf(&path, "%s/cov", tooldir)))
xprintf("\n"
"On OS X the debuggers must be installed setgid procmod.\n"
"Read and run ./sudo.bash to install the debuggers.\n");
}
if(!xsamefile(goroot_final, goroot)) {
xprintf("\n"
"The binaries expect %s to be copied or moved to %s\n",
goroot, goroot_final);
}
bfree(&b);
bfree(&b1);
bfree(&search);
bfree(&path);
}
void
cmdversion(int argc, char **argv)
{
ARGBEGIN{
case 'v':
vflag++;
break;
default:
usage();
}ARGEND
if(argc > 0)
usage();
xprintf("%s\n", goversion);
}