mirror of
https://github.com/golang/go
synced 2024-10-04 13:11:22 -06:00
917 lines
19 KiB
C
917 lines
19 KiB
C
|
// 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"
|
||
|
|
||
|
/*
|
||
|
* Initialization for any invocation.
|
||
|
*/
|
||
|
|
||
|
// The usual variables.
|
||
|
char *goarch;
|
||
|
char *gobin;
|
||
|
char *gohostarch;
|
||
|
char *gohostos;
|
||
|
char *goos;
|
||
|
char *goroot;
|
||
|
char *workdir;
|
||
|
char *gochar;
|
||
|
char *goroot_final;
|
||
|
char *goversion = "go1"; // TODO: Read correct version
|
||
|
char *slash; // / for unix, \ for windows
|
||
|
char *default_goroot;
|
||
|
|
||
|
static void fixslash(Buf*);
|
||
|
static bool shouldbuild(char*, char*);
|
||
|
static void copy(char*, char*);
|
||
|
|
||
|
// The known architecture letters.
|
||
|
static char *gochars = "568";
|
||
|
|
||
|
// The known architectures.
|
||
|
static char *okgoarch[] = {
|
||
|
// same order as gochars
|
||
|
"arm",
|
||
|
"amd64",
|
||
|
"386",
|
||
|
};
|
||
|
|
||
|
// The known operating systems.
|
||
|
static char *okgoos[] = {
|
||
|
"darwin",
|
||
|
"linux",
|
||
|
"freebsd",
|
||
|
"netbsd",
|
||
|
"openbsd",
|
||
|
"plan9",
|
||
|
"windows",
|
||
|
};
|
||
|
|
||
|
static void rmworkdir(void);
|
||
|
|
||
|
// find reports the first index of p in l[0:n], or else -1.
|
||
|
static int
|
||
|
find(char *p, char **l, int n)
|
||
|
{
|
||
|
int i;
|
||
|
|
||
|
for(i=0; i<n; i++)
|
||
|
if(streq(p, l[i]))
|
||
|
return i;
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
// init handles initialization of the various global state, like goroot and goarch.
|
||
|
void
|
||
|
init(void)
|
||
|
{
|
||
|
char *p;
|
||
|
int i;
|
||
|
Buf b;
|
||
|
|
||
|
binit(&b);
|
||
|
|
||
|
xgetenv(&b, "GOROOT");
|
||
|
if(b.len == 0) {
|
||
|
if(default_goroot == nil)
|
||
|
fatal("$GOROOT not set and not available");
|
||
|
bwritestr(&b, default_goroot);
|
||
|
}
|
||
|
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);
|
||
|
|
||
|
p = bprintf(&b, "%s/include/u.h", goroot);
|
||
|
fixslash(&b);
|
||
|
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);
|
||
|
|
||
|
if(find(gohostarch, okgoarch, nelem(okgoarch)) < 0)
|
||
|
fatal("unknown $GOHOSTARCH %s", gohostarch);
|
||
|
|
||
|
xgetenv(&b, "GOARCH");
|
||
|
if(b.len == 0)
|
||
|
bwritestr(&b, gohostarch);
|
||
|
goarch = btake(&b);
|
||
|
if((i=find(goarch, okgoarch, nelem(okgoarch))) < 0)
|
||
|
fatal("unknown $GOARCH %s", goarch);
|
||
|
bprintf(&b, "%c", gochars[i]);
|
||
|
gochar = btake(&b);
|
||
|
|
||
|
xgetenv(&b, "GOROOT_FINAL");
|
||
|
if(b.len > 0)
|
||
|
goroot_final = btake(&b);
|
||
|
else
|
||
|
goroot_final = goroot;
|
||
|
|
||
|
xsetenv("GOROOT", goroot);
|
||
|
xsetenv("GOARCH", goarch);
|
||
|
xsetenv("GOOS", goos);
|
||
|
|
||
|
// Make the environment more predictable.
|
||
|
xsetenv("LANG", "C");
|
||
|
xsetenv("LANGUAGE", "en_US.UTF8");
|
||
|
|
||
|
workdir = xworkdir();
|
||
|
xatexit(rmworkdir);
|
||
|
|
||
|
bfree(&b);
|
||
|
}
|
||
|
|
||
|
// rmworkdir deletes the work directory.
|
||
|
static void
|
||
|
rmworkdir(void)
|
||
|
{
|
||
|
xprintf("rm -rf %s\n", workdir);
|
||
|
xremoveall(workdir);
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Initial tree setup.
|
||
|
*/
|
||
|
|
||
|
// The old tools that no longer live in $GOBIN or $GOROOT/bin.
|
||
|
static char *oldtool[] = {
|
||
|
"5a", "5c", "5g", "5l",
|
||
|
"6a", "6c", "6g", "6l",
|
||
|
"8a", "8c", "8g", "8l",
|
||
|
"6cov",
|
||
|
"6nm",
|
||
|
"cgo",
|
||
|
"ebnflint",
|
||
|
"goapi",
|
||
|
"gofix",
|
||
|
"goinstall",
|
||
|
"gomake",
|
||
|
"gopack",
|
||
|
"gopprof",
|
||
|
"gotest",
|
||
|
"gotype",
|
||
|
"govet",
|
||
|
"goyacc",
|
||
|
"quietgcc",
|
||
|
};
|
||
|
|
||
|
// setup sets up the tree for the initial build.
|
||
|
static void
|
||
|
setup(void)
|
||
|
{
|
||
|
int i;
|
||
|
Buf b;
|
||
|
char *p;
|
||
|
|
||
|
binit(&b);
|
||
|
|
||
|
run(&b, nil, 0, "ld", "--version", nil);
|
||
|
if(contains(bstr(&b), "gold") && contains(bstr(&b), " 2.20")) {
|
||
|
fatal("Your system has gold 2.20 installed.\n"
|
||
|
"This version is shipped by Ubuntu even though\n"
|
||
|
"it is known not to work on Ubuntu.\n"
|
||
|
"Binaries built with this linker are likely to fail in mysterious ways.\n"
|
||
|
"\n"
|
||
|
"Run sudo apt-get remove binutils-gold.");
|
||
|
}
|
||
|
|
||
|
// Create tool directory.
|
||
|
p = bprintf(&b, "%s/bin", goroot);
|
||
|
fixslash(&b);
|
||
|
if(!isdir(p))
|
||
|
xmkdir(p);
|
||
|
p = bprintf(&b, "%s/bin/go-tool", goroot);
|
||
|
fixslash(&b);
|
||
|
if(!isdir(p))
|
||
|
xmkdir(p);
|
||
|
|
||
|
// Create package directory.
|
||
|
p = bprintf(&b, "%s/pkg", goroot);
|
||
|
fixslash(&b);
|
||
|
if(!isdir(p))
|
||
|
xmkdir(p);
|
||
|
p = bprintf(&b, "%s/pkg/%s_%s", goroot, goos, goarch);
|
||
|
fixslash(&b);
|
||
|
xremoveall(p);
|
||
|
xmkdir(p);
|
||
|
|
||
|
// Remove old pre-tool binaries.
|
||
|
for(i=0; i<nelem(oldtool); i++)
|
||
|
xremove(bprintf(&b, "%s%s%s%s%s", goroot, slash, "bin", slash, oldtool[i]));
|
||
|
|
||
|
// If $GOBIN is set and has a Go compiler, it must be cleaned.
|
||
|
for(i=0; gochars[i]; i++) {
|
||
|
if(isfile(bprintf(&b, "%s%s%c%s", gobin, slash, gochars[i], "g"))) {
|
||
|
for(i=0; i<nelem(oldtool); i++)
|
||
|
xremove(bprintf(&b, "%s%s%s", gobin, slash, oldtool[i]));
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
bfree(&b);
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* C library and tool building
|
||
|
*/
|
||
|
|
||
|
// gccargs is the gcc command line to use for compiling a single C file.
|
||
|
static char *gccargs[] = {
|
||
|
"gcc",
|
||
|
"-Wall",
|
||
|
"-Wno-sign-compare",
|
||
|
"-Wno-missing-braces",
|
||
|
"-Wno-parentheses",
|
||
|
"-Wno-unknown-pragmas",
|
||
|
"-Wno-switch",
|
||
|
"-Wno-comment",
|
||
|
"-Werror",
|
||
|
"-fno-common",
|
||
|
"-ggdb",
|
||
|
"-O2",
|
||
|
"-c",
|
||
|
};
|
||
|
|
||
|
// deptab lists changes to the default dependencies for a given prefix.
|
||
|
// deps ending in /* read the whole directory; deps beginning with -
|
||
|
// exclude files with that prefix.
|
||
|
static struct {
|
||
|
char *prefix; // prefix of target
|
||
|
char *dep[20]; // dependency tweaks for targets with that prefix
|
||
|
} deptab[] = {
|
||
|
{"lib9", {
|
||
|
"$GOROOT/include/u.h",
|
||
|
"$GOROOT/include/utf.h",
|
||
|
"$GOROOT/include/fmt.h",
|
||
|
"$GOROOT/include/libc.h",
|
||
|
"fmt/*",
|
||
|
"utf/*",
|
||
|
"-utf/mkrunetype",
|
||
|
"-utf\\mkrunetype",
|
||
|
"-utf/runetypebody",
|
||
|
"-utf\\runetypebody",
|
||
|
}},
|
||
|
{"libbio", {
|
||
|
"$GOROOT/include/u.h",
|
||
|
"$GOROOT/include/utf.h",
|
||
|
"$GOROOT/include/fmt.h",
|
||
|
"$GOROOT/include/libc.h",
|
||
|
"$GOROOT/include/bio.h",
|
||
|
}},
|
||
|
{"libmach", {
|
||
|
"$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/bootexec.h",
|
||
|
"$GOROOT/include/mach.h",
|
||
|
"$GOROOT/include/ureg_amd64.h",
|
||
|
"$GOROOT/include/ureg_arm.h",
|
||
|
"$GOROOT/include/ureg_x86.h",
|
||
|
}},
|
||
|
{"cmd/cc", {
|
||
|
"-pgen.c",
|
||
|
"-pswt.c",
|
||
|
}},
|
||
|
{"cmd/gc", {
|
||
|
"-cplx.c",
|
||
|
"-pgen.c",
|
||
|
"-y1.tab.c", // makefile dreg
|
||
|
"opnames.h",
|
||
|
}},
|
||
|
{"cmd/5c", {
|
||
|
"../cc/pgen.c",
|
||
|
"../cc/pswt.c",
|
||
|
"../5l/enam.c",
|
||
|
"$GOROOT/lib/libcc.a",
|
||
|
}},
|
||
|
{"cmd/6c", {
|
||
|
"../cc/pgen.c",
|
||
|
"../cc/pswt.c",
|
||
|
"../6l/enam.c",
|
||
|
"$GOROOT/lib/libcc.a",
|
||
|
}},
|
||
|
{"cmd/8c", {
|
||
|
"../cc/pgen.c",
|
||
|
"../cc/pswt.c",
|
||
|
"../8l/enam.c",
|
||
|
"$GOROOT/lib/libcc.a",
|
||
|
}},
|
||
|
{"cmd/5g", {
|
||
|
"../gc/cplx.c",
|
||
|
"../gc/pgen.c",
|
||
|
"../5l/enam.c",
|
||
|
"$GOROOT/lib/libgc.a",
|
||
|
}},
|
||
|
{"cmd/6g", {
|
||
|
"../gc/cplx.c",
|
||
|
"../gc/pgen.c",
|
||
|
"../6l/enam.c",
|
||
|
"$GOROOT/lib/libgc.a",
|
||
|
}},
|
||
|
{"cmd/8g", {
|
||
|
"../gc/cplx.c",
|
||
|
"../gc/pgen.c",
|
||
|
"../8l/enam.c",
|
||
|
"$GOROOT/lib/libgc.a",
|
||
|
}},
|
||
|
{"cmd/5l", {
|
||
|
"../ld/*",
|
||
|
"enam.c",
|
||
|
}},
|
||
|
{"cmd/6l", {
|
||
|
"../ld/*",
|
||
|
"enam.c",
|
||
|
}},
|
||
|
{"cmd/8l", {
|
||
|
"../ld/*",
|
||
|
"enam.c",
|
||
|
}},
|
||
|
{"cmd/", {
|
||
|
"$GOROOT/lib/libmach.a",
|
||
|
"$GOROOT/lib/libbio.a",
|
||
|
"$GOROOT/lib/lib9.a",
|
||
|
}},
|
||
|
};
|
||
|
|
||
|
// depsuffix records the allowed suffixes for source files.
|
||
|
char *depsuffix[] = {
|
||
|
".c",
|
||
|
".h",
|
||
|
".s",
|
||
|
".go",
|
||
|
};
|
||
|
|
||
|
// gentab records how to generate some trivial files.
|
||
|
static struct {
|
||
|
char *name;
|
||
|
void (*gen)(char*, char*);
|
||
|
} gentab[] = {
|
||
|
{"opnames.h", gcopnames},
|
||
|
{"enam.c", mkenam},
|
||
|
};
|
||
|
|
||
|
// install installs the library, package, or binary associated with dir,
|
||
|
// which is relative to $GOROOT/src.
|
||
|
static void
|
||
|
install(char *dir)
|
||
|
{
|
||
|
char *name, *p, *elem, *prefix;
|
||
|
bool islib, ispkg, isgo, stale;
|
||
|
Buf b, b1, path;
|
||
|
Vec compile, files, link, go, missing, clean, lib, extra;
|
||
|
Time ttarg, t;
|
||
|
int i, j, k, n;
|
||
|
|
||
|
binit(&b);
|
||
|
binit(&b1);
|
||
|
binit(&path);
|
||
|
vinit(&compile);
|
||
|
vinit(&files);
|
||
|
vinit(&link);
|
||
|
vinit(&go);
|
||
|
vinit(&missing);
|
||
|
vinit(&clean);
|
||
|
vinit(&lib);
|
||
|
vinit(&extra);
|
||
|
|
||
|
// path = full path to dir.
|
||
|
bprintf(&path, "%s/src/%s", goroot, dir);
|
||
|
fixslash(&path);
|
||
|
name = lastelem(dir);
|
||
|
|
||
|
islib = hasprefix(dir, "lib") || streq(dir, "cmd/cc") || streq(dir, "cmd/gc");
|
||
|
ispkg = hasprefix(dir, "pkg");
|
||
|
isgo = ispkg || streq(dir, "cmd/go");
|
||
|
|
||
|
|
||
|
// Start final link command line.
|
||
|
// Note: code below knows that link.p[2] is the target.
|
||
|
if(islib) {
|
||
|
// C library.
|
||
|
vadd(&link, "ar");
|
||
|
vadd(&link, "rsc");
|
||
|
prefix = "";
|
||
|
if(!hasprefix(name, "lib"))
|
||
|
prefix = "lib";
|
||
|
bprintf(&b, "%s/lib/%s%s.a", goroot, prefix, name);
|
||
|
fixslash(&b);
|
||
|
vadd(&link, bstr(&b));
|
||
|
} else if(ispkg) {
|
||
|
// Go library (package).
|
||
|
bprintf(&b, "%s/bin/go-tool/pack", goroot);
|
||
|
fixslash(&b);
|
||
|
vadd(&link, bstr(&b));
|
||
|
vadd(&link, "grc");
|
||
|
p = bprintf(&b, "%s/pkg/%s_%s/%s", goroot, goos, goarch, dir+4);
|
||
|
*xstrrchr(p, '/') = '\0';
|
||
|
xmkdirall(p);
|
||
|
bprintf(&b, "%s/pkg/%s_%s/%s.a", goroot, goos, goarch, dir+4);
|
||
|
fixslash(&b);
|
||
|
vadd(&link, bstr(&b));
|
||
|
} else if(streq(dir, "cmd/go")) {
|
||
|
// Go command.
|
||
|
bprintf(&b, "%s/bin/go-tool/%sl", goroot, gochar);
|
||
|
fixslash(&b);
|
||
|
vadd(&link, bstr(&b));
|
||
|
vadd(&link, "-o");
|
||
|
bprintf(&b, "%s/bin/go-tool/go_bootstrap", goroot);
|
||
|
fixslash(&b);
|
||
|
vadd(&link, bstr(&b));
|
||
|
} else {
|
||
|
// C command.
|
||
|
vadd(&link, "gcc");
|
||
|
vadd(&link, "-o");
|
||
|
bprintf(&b, "%s/bin/go-tool/%s", goroot, name);
|
||
|
fixslash(&b);
|
||
|
vadd(&link, bstr(&b));
|
||
|
}
|
||
|
ttarg = mtime(link.p[2]);
|
||
|
|
||
|
// Gather files that are sources for this target.
|
||
|
// Everything in that directory, and any target-specific
|
||
|
// additions.
|
||
|
xreaddir(&files, bstr(&path));
|
||
|
for(i=0; i<nelem(deptab); i++) {
|
||
|
if(hasprefix(dir, deptab[i].prefix)) {
|
||
|
for(j=0; (p=deptab[i].dep[j])!=nil; j++) {
|
||
|
if(hasprefix(p, "$GOROOT/")) {
|
||
|
bprintf(&b1, "%s/%s", goroot, p+8);
|
||
|
p = bstr(&b1);
|
||
|
}
|
||
|
if(hassuffix(p, ".a")) {
|
||
|
vadd(&lib, p);
|
||
|
continue;
|
||
|
}
|
||
|
if(hassuffix(p, "/*")) {
|
||
|
bprintf(&b, "%s/%s", bstr(&path), p);
|
||
|
b.len -= 2;
|
||
|
fixslash(&b);
|
||
|
xreaddir(&extra, bstr(&b));
|
||
|
bprintf(&b, "%s", p);
|
||
|
b.len -= 2;
|
||
|
for(k=0; k<extra.len; k++) {
|
||
|
bprintf(&b1, "%s/%s", bstr(&b), extra.p[k]);
|
||
|
fixslash(&b1);
|
||
|
vadd(&files, bstr(&b1));
|
||
|
}
|
||
|
continue;
|
||
|
}
|
||
|
if(hasprefix(p, "-")) {
|
||
|
p++;
|
||
|
n = 0;
|
||
|
for(k=0; k<files.len; k++) {
|
||
|
if(hasprefix(files.p[k], p))
|
||
|
xfree(files.p[k]);
|
||
|
else
|
||
|
files.p[n++] = files.p[k];
|
||
|
}
|
||
|
files.len = n;
|
||
|
continue;
|
||
|
}
|
||
|
vadd(&files, p);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
vuniq(&files);
|
||
|
|
||
|
// Convert to absolute paths.
|
||
|
for(i=0; i<files.len; i++) {
|
||
|
if(!isabs(files.p[i])) {
|
||
|
bprintf(&b, "%s/%s", bstr(&path), files.p[i]);
|
||
|
fixslash(&b);
|
||
|
xfree(files.p[i]);
|
||
|
files.p[i] = btake(&b);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// For package runtime, copy some files into the work space.
|
||
|
if(streq(dir, "pkg/runtime")) {
|
||
|
copy(bprintf(&b, "%s/arch_GOARCH.h", workdir),
|
||
|
bprintf(&b1, "%s/arch_%s.h", bstr(&path), goarch));
|
||
|
copy(bprintf(&b, "%s/defs_GOOS_GOARCH.h", workdir),
|
||
|
bprintf(&b1, "%s/defs_%s_%s.h", bstr(&path), goos, goarch));
|
||
|
copy(bprintf(&b, "%s/os_GOOS.h", workdir),
|
||
|
bprintf(&b1, "%s/os_%s.h", bstr(&path), goos));
|
||
|
copy(bprintf(&b, "%s/signals_GOOS.h", workdir),
|
||
|
bprintf(&b1, "%s/signals_%s.h", bstr(&path), goos));
|
||
|
copy(bprintf(&b, "%s/zasm_GOOS_GOARCH.h", workdir),
|
||
|
bprintf(&b1, "%s/zasm_%s_%s.h", bstr(&path), goos, goarch));
|
||
|
}
|
||
|
|
||
|
|
||
|
// Is the target up-to-date?
|
||
|
stale = 1; // TODO: Decide when 0 is okay.
|
||
|
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 > ttarg)
|
||
|
stale = 1;
|
||
|
if(t == 0) {
|
||
|
vadd(&missing, p);
|
||
|
files.p[n++] = files.p[i];
|
||
|
continue;
|
||
|
}
|
||
|
if(!hassuffix(p, ".a") && !shouldbuild(p, dir)) {
|
||
|
xfree(files.p[i]);
|
||
|
continue;
|
||
|
}
|
||
|
if(hassuffix(p, ".go"))
|
||
|
vadd(&go, p);
|
||
|
files.p[n++] = files.p[i];
|
||
|
}
|
||
|
files.len = n;
|
||
|
|
||
|
for(i=0; i<lib.len && !stale; i++)
|
||
|
if(mtime(lib.p[i]) > ttarg)
|
||
|
stale = 1;
|
||
|
|
||
|
if(!stale)
|
||
|
goto out;
|
||
|
|
||
|
// Generate any missing files.
|
||
|
for(i=0; i<missing.len; i++) {
|
||
|
p = missing.p[i];
|
||
|
elem = lastelem(p);
|
||
|
for(j=0; j<nelem(gentab); j++) {
|
||
|
if(streq(gentab[j].name, elem)) {
|
||
|
gentab[j].gen(bstr(&path), p);
|
||
|
vadd(&clean, p);
|
||
|
goto built;
|
||
|
}
|
||
|
}
|
||
|
fatal("missing file %s", p);
|
||
|
built:;
|
||
|
}
|
||
|
|
||
|
// Compile the files.
|
||
|
for(i=0; i<files.len; i++) {
|
||
|
if(!hassuffix(files.p[i], ".c") && !hassuffix(files.p[i], ".s"))
|
||
|
continue;
|
||
|
name = lastelem(files.p[i]);
|
||
|
|
||
|
vreset(&compile);
|
||
|
if(!isgo) {
|
||
|
// C library or tool.
|
||
|
vcopy(&compile, gccargs, nelem(gccargs));
|
||
|
if(streq(gohostarch, "amd64"))
|
||
|
vadd(&compile, "-m64");
|
||
|
else if(streq(gohostarch, "386"))
|
||
|
vadd(&compile, "-m32");
|
||
|
if(streq(dir, "lib9"))
|
||
|
vadd(&compile, "-DPLAN9PORT");
|
||
|
|
||
|
bprintf(&b, "%s/include", goroot);
|
||
|
fixslash(&b);
|
||
|
vadd(&compile, "-I");
|
||
|
vadd(&compile, bstr(&b));
|
||
|
|
||
|
vadd(&compile, "-I");
|
||
|
vadd(&compile, bstr(&path));
|
||
|
|
||
|
// runtime/goos.c gets the default constants hard-coded.
|
||
|
if(streq(name, "goos.c")) {
|
||
|
vadd(&compile, bprintf(&b, "-DGOOS=\"%s\"", goos));
|
||
|
vadd(&compile, bprintf(&b, "-DGOARCH=\"%s\"", goarch));
|
||
|
vadd(&compile, bprintf(&b, "-DGOROOT=\"%s\"", goroot));
|
||
|
vadd(&compile, bprintf(&b, "-DGOVERSION=\"%s\"", goversion));
|
||
|
}
|
||
|
|
||
|
// gc/lex.c records the GOEXPERIMENT setting used during the build.
|
||
|
if(streq(name, "lex.c")) {
|
||
|
xgetenv(&b, "GOEXPERIMENT");
|
||
|
vadd(&compile, bprintf(&b1, "-DGOEXPERIMENT=\"%s\"", bstr(&b)));
|
||
|
}
|
||
|
} else {
|
||
|
// Supporting files for a Go package.
|
||
|
if(hassuffix(files.p[i], ".s")) {
|
||
|
bprintf(&b, "%s/bin/go-tool/%sa", goroot, gochar);
|
||
|
fixslash(&b);
|
||
|
vadd(&compile, bstr(&b));
|
||
|
} else {
|
||
|
bprintf(&b, "%s/bin/go-tool/%sc", goroot, gochar);
|
||
|
fixslash(&b);
|
||
|
vadd(&compile, bstr(&b));
|
||
|
vadd(&compile, "-FVw");
|
||
|
}
|
||
|
vadd(&compile, "-I");
|
||
|
vadd(&compile, workdir);
|
||
|
vadd(&compile, bprintf(&b, "-DGOOS_%s", goos));
|
||
|
vadd(&compile, bprintf(&b, "-DGOARCH_%s", goos));
|
||
|
}
|
||
|
|
||
|
bprintf(&b, "%s/%s", workdir, lastelem(files.p[i]));
|
||
|
b.p[b.len-1] = 'o'; // was c or s
|
||
|
fixslash(&b);
|
||
|
vadd(&compile, "-o");
|
||
|
vadd(&compile, bstr(&b));
|
||
|
vadd(&link, bstr(&b));
|
||
|
vadd(&clean, bstr(&b));
|
||
|
|
||
|
vadd(&compile, files.p[i]);
|
||
|
|
||
|
runv(nil, bstr(&path), CheckExit, &compile);
|
||
|
vreset(&compile);
|
||
|
}
|
||
|
|
||
|
if(isgo) {
|
||
|
// The last loop was compiling individual files.
|
||
|
// Hand the Go files to the compiler en masse.
|
||
|
vreset(&compile);
|
||
|
bprintf(&b, "%s/bin/go-tool/%sg", goroot, gochar);
|
||
|
fixslash(&b);
|
||
|
vadd(&compile, bstr(&b));
|
||
|
|
||
|
bprintf(&b, "%s/_go_.%s", workdir, gochar);
|
||
|
fixslash(&b);
|
||
|
vadd(&compile, "-o");
|
||
|
vadd(&compile, bstr(&b));
|
||
|
vadd(&clean, bstr(&b));
|
||
|
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(!islib && !isgo) {
|
||
|
// C binaries need the libraries explicitly, and -lm.
|
||
|
vcopy(&link, lib.p, lib.len);
|
||
|
vadd(&link, "-lm");
|
||
|
}
|
||
|
|
||
|
// Remove target before writing it.
|
||
|
xremove(link.p[2]);
|
||
|
|
||
|
runv(nil, nil, CheckExit, &link);
|
||
|
|
||
|
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);
|
||
|
}
|
||
|
|
||
|
// matchfield reports whether the field matches this build.
|
||
|
static bool
|
||
|
matchfield(char *f)
|
||
|
{
|
||
|
return streq(f, goos) || streq(f, goarch) || streq(f, "cmd_go_bootstrap");
|
||
|
}
|
||
|
|
||
|
// shouldbuild reports whether we should build this file.
|
||
|
// It applies the same rules that are used with context tags
|
||
|
// in package go/build, except that the GOOS and GOARCH
|
||
|
// can appear anywhere in the file name, not just after _.
|
||
|
// In particular, they can be the entire file name (like windows.c).
|
||
|
// We also allow the special tag cmd_go_bootstrap.
|
||
|
// See ../go/bootstrap.go and package go/build.
|
||
|
static bool
|
||
|
shouldbuild(char *file, char *dir)
|
||
|
{
|
||
|
char *name, *p;
|
||
|
int i, j, ret, true;
|
||
|
Buf b;
|
||
|
Vec lines, fields;
|
||
|
|
||
|
// Check file name for GOOS or GOARCH.
|
||
|
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;
|
||
|
|
||
|
// Omit test files.
|
||
|
if(contains(name, "_test"))
|
||
|
return 0;
|
||
|
|
||
|
// Check file contents for // +build lines.
|
||
|
binit(&b);
|
||
|
vinit(&lines);
|
||
|
vinit(&fields);
|
||
|
|
||
|
ret = 1;
|
||
|
readfile(&b, file);
|
||
|
splitlines(&lines, bstr(&b));
|
||
|
for(i=0; i<lines.len; i++) {
|
||
|
p = lines.p[i];
|
||
|
while(*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n')
|
||
|
p++;
|
||
|
if(*p == '\0')
|
||
|
continue;
|
||
|
if(contains(p, "package documentation")) {
|
||
|
ret = 0;
|
||
|
goto out;
|
||
|
}
|
||
|
if(contains(p, "package main") && !streq(dir, "cmd/go")) {
|
||
|
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;
|
||
|
}
|
||
|
|
||
|
// fixslash rewrites / to \ when the slash character is \, so that the paths look conventional.
|
||
|
static void
|
||
|
fixslash(Buf *b)
|
||
|
{
|
||
|
int i;
|
||
|
|
||
|
if(slash[0] == '/')
|
||
|
return;
|
||
|
for(i=0; i<b->len; i++)
|
||
|
if(b->p[i] == '/')
|
||
|
b->p[i] = '\\';
|
||
|
}
|
||
|
|
||
|
// copy copies the file src to dst, via memory (so only good for small files).
|
||
|
static void
|
||
|
copy(char *dst, char *src)
|
||
|
{
|
||
|
Buf b;
|
||
|
|
||
|
binit(&b);
|
||
|
readfile(&b, src);
|
||
|
writefile(&b, dst);
|
||
|
bfree(&b);
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* command implementations
|
||
|
*/
|
||
|
|
||
|
// The env command prints the default environment.
|
||
|
void
|
||
|
cmdenv(int argc, char **argv)
|
||
|
{
|
||
|
USED(argc);
|
||
|
USED(argv);
|
||
|
|
||
|
xprintf("GOROOT=%s\n", goroot);
|
||
|
xprintf("GOARCH=%s\n", goarch);
|
||
|
xprintf("GOOS=%s\n", goos);
|
||
|
}
|
||
|
|
||
|
// buildorder records the order of builds for the 'go bootstrap' command.
|
||
|
static char *buildorder[] = {
|
||
|
"lib9",
|
||
|
"libbio",
|
||
|
"libmach",
|
||
|
|
||
|
"cmd/cov",
|
||
|
"cmd/nm",
|
||
|
"cmd/pack",
|
||
|
"cmd/prof",
|
||
|
|
||
|
"cmd/cc", // must be before c
|
||
|
"cmd/gc", // must be before g
|
||
|
"cmd/%sl", // must be before a, c, g
|
||
|
"cmd/%sa",
|
||
|
"cmd/%sc",
|
||
|
"cmd/%sg",
|
||
|
|
||
|
// The dependency order here was copied from a buildscript
|
||
|
// back when there were build scripts. Will have to
|
||
|
// be maintained by hand, but shouldn't change very
|
||
|
// often.
|
||
|
"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/json",
|
||
|
"pkg/encoding/gob",
|
||
|
"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/go/build",
|
||
|
"pkg/os/exec",
|
||
|
"pkg/net/url",
|
||
|
"pkg/text/template/parse",
|
||
|
"pkg/text/template",
|
||
|
|
||
|
"cmd/go",
|
||
|
};
|
||
|
|
||
|
// 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 *p;
|
||
|
|
||
|
setup();
|
||
|
|
||
|
// TODO: nuke();
|
||
|
|
||
|
binit(&b);
|
||
|
for(i=0; i<nelem(buildorder); i++) {
|
||
|
p = bprintf(&b, buildorder[i], gochar);
|
||
|
xprintf("%s\n", p);
|
||
|
install(p);
|
||
|
}
|
||
|
bfree(&b);
|
||
|
}
|
||
|
|
||
|
// Install installs the list of packages named on the command line.
|
||
|
void
|
||
|
cmdinstall(int argc, char **argv)
|
||
|
{
|
||
|
int i;
|
||
|
|
||
|
for(i=1; i<argc; i++)
|
||
|
install(argv[i]);
|
||
|
}
|