2008-09-19 12:55:46 -06:00
|
|
|
// 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.
|
|
|
|
|
|
|
|
// Build a collection of go programs into a single package.
|
|
|
|
|
|
|
|
#include <u.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <libc.h>
|
|
|
|
#include <bio.h>
|
|
|
|
|
|
|
|
void
|
|
|
|
usage(void)
|
|
|
|
{
|
2008-11-18 18:11:56 -07:00
|
|
|
fprint(2, "usage: gobuild [-m] [packagename...]\n");
|
2008-09-19 12:55:46 -06:00
|
|
|
exits("usage");
|
|
|
|
}
|
|
|
|
|
|
|
|
int chatty;
|
|
|
|
int devnull; // fd of /dev/null
|
|
|
|
int makefile; // generate Makefile
|
|
|
|
char *thechar; // object character
|
2008-09-25 18:07:06 -06:00
|
|
|
char *goos;
|
|
|
|
char *goarch;
|
2008-11-18 18:11:56 -07:00
|
|
|
char *goroot;
|
|
|
|
char **oargv;
|
|
|
|
int oargc;
|
|
|
|
|
|
|
|
void writemakefile(void);
|
|
|
|
int sourcefilenames(char***);
|
|
|
|
|
|
|
|
void*
|
|
|
|
emalloc(int n)
|
|
|
|
{
|
|
|
|
void *v;
|
|
|
|
|
|
|
|
v = malloc(n);
|
|
|
|
if(v == nil)
|
|
|
|
sysfatal("out of memory");
|
|
|
|
memset(v, 0, n);
|
|
|
|
return v;
|
|
|
|
}
|
|
|
|
|
|
|
|
void*
|
|
|
|
erealloc(void *v, int n)
|
|
|
|
{
|
|
|
|
v = realloc(v, n);
|
|
|
|
if(v == nil)
|
|
|
|
sysfatal("out of memory");
|
|
|
|
return v;
|
|
|
|
}
|
2008-09-19 12:55:46 -06:00
|
|
|
|
|
|
|
// Info about when to compile a particular file.
|
|
|
|
typedef struct Job Job;
|
|
|
|
struct Job
|
|
|
|
{
|
|
|
|
char *name;
|
2008-11-18 18:11:56 -07:00
|
|
|
char *pkg;
|
2008-09-19 12:55:46 -06:00
|
|
|
int pass;
|
|
|
|
};
|
2008-11-18 18:11:56 -07:00
|
|
|
Job *job;
|
|
|
|
int njob;
|
|
|
|
|
|
|
|
char **pkg;
|
|
|
|
int npkg;
|
2008-09-19 12:55:46 -06:00
|
|
|
|
|
|
|
// Run the command in argv.
|
|
|
|
// Return -1 if it fails (non-zero exit status).
|
|
|
|
// Return 0 on success.
|
|
|
|
// Showoutput controls whether to let output from command display
|
|
|
|
// on standard output and standard error.
|
|
|
|
int
|
|
|
|
run(char **argv, int showoutput)
|
|
|
|
{
|
|
|
|
int pid, i;
|
|
|
|
Waitmsg *w;
|
|
|
|
vlong n0, n1;
|
2008-11-18 18:11:56 -07:00
|
|
|
char buf[100];
|
2008-09-19 12:55:46 -06:00
|
|
|
|
|
|
|
n0 = nsec();
|
|
|
|
pid = fork();
|
|
|
|
if(pid < 0)
|
|
|
|
sysfatal("fork: %r");
|
|
|
|
if(pid == 0){
|
|
|
|
dup(devnull, 0);
|
2008-11-18 18:11:56 -07:00
|
|
|
if(!showoutput)
|
2008-09-19 12:55:46 -06:00
|
|
|
dup(devnull, 2);
|
2008-11-18 18:11:56 -07:00
|
|
|
dup(2, 1);
|
2008-09-19 12:55:46 -06:00
|
|
|
if(devnull > 2)
|
|
|
|
close(devnull);
|
|
|
|
exec(argv[0], argv);
|
|
|
|
fprint(2, "exec %s: %r\n", argv[0]);
|
|
|
|
exit(1);
|
|
|
|
}
|
2008-11-18 18:11:56 -07:00
|
|
|
while((w = waitfor(pid)) == nil) {
|
|
|
|
rerrstr(buf, sizeof buf);
|
|
|
|
if(strstr(buf, "interrupt"))
|
|
|
|
continue;
|
2008-09-19 12:55:46 -06:00
|
|
|
sysfatal("waitfor %d: %r", pid);
|
2008-11-18 18:11:56 -07:00
|
|
|
}
|
|
|
|
n1 = nsec();
|
2008-09-19 12:55:46 -06:00
|
|
|
if(chatty > 1){
|
|
|
|
fprint(2, "%5.3f", (n1-n0)/1.e9);
|
|
|
|
for(i=0; argv[i]; i++)
|
|
|
|
fprint(2, " %s", argv[i]);
|
|
|
|
if(w->msg[0])
|
|
|
|
fprint(2, " [%s]", w->msg);
|
|
|
|
fprint(2, "\n");
|
|
|
|
}
|
|
|
|
if(w->msg[0])
|
|
|
|
return -1;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Build the file using the compiler cc.
|
|
|
|
// Return -1 on error, 0 on success.
|
|
|
|
// If show is set, print the command and the output.
|
|
|
|
int
|
|
|
|
buildcc(char *cc, char *file, int show)
|
|
|
|
{
|
|
|
|
char *argv[3];
|
|
|
|
|
|
|
|
if(show)
|
|
|
|
fprint(2, "$ %s %s\n", cc, file);
|
|
|
|
argv[0] = cc;
|
|
|
|
argv[1] = file;
|
|
|
|
argv[2] = nil;
|
|
|
|
return run(argv, show);
|
|
|
|
}
|
|
|
|
|
2008-11-18 18:11:56 -07:00
|
|
|
// Run ar to add the given files to pkg.a.
|
|
|
|
void
|
|
|
|
ar(char *pkg, char **file, int nfile)
|
|
|
|
{
|
|
|
|
char **arg;
|
|
|
|
int i, n;
|
|
|
|
char sixar[20];
|
|
|
|
char pkga[1000];
|
|
|
|
|
|
|
|
arg = emalloc((4+nfile)*sizeof arg[0]);
|
|
|
|
n = 0;
|
|
|
|
snprint(sixar, sizeof sixar, "%sar", thechar);
|
|
|
|
snprint(pkga, sizeof pkga, "%s.a", pkg);
|
|
|
|
arg[n++] = sixar;
|
|
|
|
arg[n++] = "grc";
|
|
|
|
arg[n++] = pkga;
|
|
|
|
for(i=0; i<nfile; i++)
|
|
|
|
arg[n++] = file[i];
|
|
|
|
arg[n] = nil;
|
|
|
|
|
|
|
|
if(run(arg, 1) < 0)
|
|
|
|
sysfatal("ar: %r");
|
|
|
|
}
|
|
|
|
|
2008-09-19 12:55:46 -06:00
|
|
|
// Return bool whether s ends in suffix.
|
|
|
|
int
|
|
|
|
suffix(char *s, char *suffix)
|
|
|
|
{
|
|
|
|
int n1, n2;
|
|
|
|
|
|
|
|
n1 = strlen(s);
|
|
|
|
n2 = strlen(suffix);
|
|
|
|
if(n1>n2 && strcmp(s+n1-n2, suffix) == 0)
|
|
|
|
return 1;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Return the name of the compiler for file.
|
|
|
|
char*
|
|
|
|
compiler(char *file)
|
|
|
|
{
|
|
|
|
static char buf[20];
|
|
|
|
|
|
|
|
if(suffix(file, ".go"))
|
|
|
|
snprint(buf, sizeof buf, "%sg", thechar);
|
|
|
|
else if(suffix(file, ".c"))
|
|
|
|
snprint(buf, sizeof buf, "%sc", thechar);
|
|
|
|
else if(suffix(file, ".s"))
|
|
|
|
snprint(buf, sizeof buf, "%sa", thechar);
|
|
|
|
else
|
|
|
|
sysfatal("don't know how to build %s", file);
|
|
|
|
return buf;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Return the object name for file, replacing the
|
|
|
|
// .c or .g or .a with .suffix.
|
|
|
|
char*
|
|
|
|
goobj(char *file, char *suffix)
|
|
|
|
{
|
|
|
|
char *p;
|
|
|
|
|
|
|
|
p = strrchr(file, '.');
|
|
|
|
if(p == nil)
|
|
|
|
sysfatal("don't know object name for %s", file);
|
|
|
|
return smprint("%.*s.%s", utfnlen(file, p-file), file, suffix);
|
|
|
|
}
|
|
|
|
|
2008-11-18 18:11:56 -07:00
|
|
|
// Figure out package of .go file.
|
|
|
|
// Maintain list of all packages seen so far.
|
|
|
|
// Returned package string is in that list,
|
|
|
|
// so caller can use pointer compares.
|
|
|
|
char*
|
|
|
|
getpkg(char *file)
|
|
|
|
{
|
|
|
|
Biobuf *b;
|
|
|
|
char *p, *q;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
if(!suffix(file, ".go"))
|
|
|
|
return nil;
|
|
|
|
if((b = Bopen(file, OREAD)) == nil)
|
|
|
|
sysfatal("open %s: %r", file);
|
|
|
|
while((p = Brdline(b, '\n')) != nil) {
|
|
|
|
p[Blinelen(b)-1] = '\0';
|
|
|
|
while(*p == ' ' || *p == '\t')
|
|
|
|
p++;
|
|
|
|
if(strncmp(p, "package", 7) == 0 && (p[7] == ' ' || p[7] == '\t')) {
|
|
|
|
p+=7;
|
|
|
|
while(*p == ' ' || *p == '\t')
|
|
|
|
p++;
|
|
|
|
q = p+strlen(p);
|
|
|
|
while(q > p && (*(q-1) == ' ' || *(q-1) == '\t'))
|
|
|
|
*--q = '\0';
|
|
|
|
for(i=0; i<npkg; i++) {
|
|
|
|
if(strcmp(pkg[i], p) == 0) {
|
|
|
|
Bterm(b);
|
|
|
|
return pkg[i];
|
|
|
|
}
|
|
|
|
}
|
2008-11-19 13:52:30 -07:00
|
|
|
// don't put main in the package list
|
|
|
|
if(strcmp(p, "main") == 0)
|
|
|
|
return "main";
|
2008-11-18 18:11:56 -07:00
|
|
|
npkg++;
|
|
|
|
pkg = erealloc(pkg, npkg*sizeof pkg[0]);
|
|
|
|
pkg[i] = emalloc(strlen(p)+1);
|
|
|
|
strcpy(pkg[i], p);
|
|
|
|
Bterm(b);
|
|
|
|
return pkg[i];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Bterm(b);
|
|
|
|
return nil;
|
|
|
|
}
|
|
|
|
|
2008-09-25 18:07:06 -06:00
|
|
|
// Format name using $(GOOS) and $(GOARCH).
|
|
|
|
int
|
|
|
|
dollarfmt(Fmt *f)
|
|
|
|
{
|
|
|
|
char *s;
|
|
|
|
Rune r;
|
|
|
|
int n;
|
|
|
|
|
|
|
|
s = va_arg(f->args, char*);
|
|
|
|
if(s == nil){
|
|
|
|
fmtstrcpy(f, "<nil>");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
for(; *s; s+=n){
|
|
|
|
n = strlen(goarch);
|
|
|
|
if(strncmp(s, goarch, n) == 0){
|
|
|
|
fmtstrcpy(f, "$(GOARCH)");
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
n = strlen(goos);
|
|
|
|
if(strncmp(s, goos, n) == 0){
|
|
|
|
fmtstrcpy(f, "$(GOOS)");
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
n = chartorune(&r, s);
|
|
|
|
fmtrune(f, r);
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2008-09-19 12:55:46 -06:00
|
|
|
// Makefile preamble template.
|
|
|
|
char preamble[] =
|
|
|
|
"O=%s\n"
|
|
|
|
"GC=$(O)g\n"
|
|
|
|
"CC=$(O)c -w\n"
|
|
|
|
"AS=$(O)a\n"
|
|
|
|
"AR=$(O)ar\n"
|
|
|
|
"\n"
|
2008-11-18 18:11:56 -07:00
|
|
|
"default: packages\n"
|
2008-09-19 12:55:46 -06:00
|
|
|
"\n"
|
|
|
|
"clean:\n"
|
2008-11-19 10:40:54 -07:00
|
|
|
"\trm -f *.$O *.a $O.out\n"
|
2008-11-18 18:11:56 -07:00
|
|
|
"\n"
|
|
|
|
"test: packages\n"
|
|
|
|
"\tgotest\n"
|
2008-09-19 12:55:46 -06:00
|
|
|
"\n"
|
2008-11-19 13:52:30 -07:00
|
|
|
"coverage: packages\n"
|
|
|
|
"\tgotest\n"
|
2008-11-19 20:11:01 -07:00
|
|
|
"\t6cov -g `pwd` | grep -v '^.*test\\.go:'\n"
|
2008-11-19 13:52:30 -07:00
|
|
|
"\n"
|
2008-09-19 12:55:46 -06:00
|
|
|
"%%.$O: %%.go\n"
|
|
|
|
"\t$(GC) $*.go\n"
|
|
|
|
"\n"
|
|
|
|
"%%.$O: %%.c\n"
|
|
|
|
"\t$(CC) $*.c\n"
|
|
|
|
"\n"
|
|
|
|
"%%.$O: %%.s\n"
|
|
|
|
"\t$(AS) $*.s\n"
|
|
|
|
"\n"
|
|
|
|
;
|
|
|
|
|
|
|
|
void
|
2008-11-18 18:11:56 -07:00
|
|
|
writemakefile(void)
|
2008-09-19 12:55:46 -06:00
|
|
|
{
|
|
|
|
Biobuf bout;
|
2008-11-18 18:11:56 -07:00
|
|
|
vlong o;
|
|
|
|
int i, k, l, pass;
|
|
|
|
char **obj;
|
|
|
|
int nobj;
|
|
|
|
|
|
|
|
// Write makefile.
|
|
|
|
Binit(&bout, 1, OWRITE);
|
|
|
|
Bprint(&bout, "# DO NOT EDIT. Automatically generated by gobuild.\n");
|
|
|
|
o = Boffset(&bout);
|
|
|
|
Bprint(&bout, "#");
|
|
|
|
for(i=0; i<oargc; i++){
|
|
|
|
if(Boffset(&bout) - o > 60){
|
|
|
|
Bprint(&bout, "\\\n# ");
|
|
|
|
o = Boffset(&bout);
|
|
|
|
}
|
|
|
|
Bprint(&bout, " %s", oargv[i]);
|
|
|
|
}
|
|
|
|
Bprint(&bout, " >Makefile\n");
|
|
|
|
Bprint(&bout, preamble, thechar);
|
|
|
|
|
|
|
|
// O2=\
|
|
|
|
// os_file.$O\
|
|
|
|
// os_time.$O\
|
|
|
|
//
|
|
|
|
obj = emalloc(njob*sizeof obj[0]);
|
|
|
|
for(pass=0;; pass++) {
|
|
|
|
nobj = 0;
|
|
|
|
for(i=0; i<njob; i++)
|
|
|
|
if(job[i].pass == pass)
|
|
|
|
obj[nobj++] = goobj(job[i].name, "$O");
|
|
|
|
if(nobj == 0)
|
|
|
|
break;
|
|
|
|
Bprint(&bout, "O%d=\\\n", pass+1);
|
|
|
|
for(i=0; i<nobj; i++)
|
|
|
|
Bprint(&bout, "\t%$\\\n", obj[i]);
|
|
|
|
Bprint(&bout, "\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
// math.a: a1 a2
|
|
|
|
for(i=0; i<npkg; i++) {
|
|
|
|
Bprint(&bout, "%s.a:", pkg[i]);
|
|
|
|
for(k=0; k<pass; k++)
|
|
|
|
Bprint(&bout, " a%d", k+1);
|
|
|
|
Bprint(&bout, "\n");
|
|
|
|
}
|
|
|
|
Bprint(&bout, "\n");
|
|
|
|
|
|
|
|
// a1: $(O1)
|
|
|
|
// $(AS) grc $(PKG) $(O1)
|
|
|
|
// rm -f $(O1)
|
|
|
|
for(k=0; k<pass; k++){
|
|
|
|
Bprint(&bout, "a%d:\t$(O%d)\n", k+1, k+1);
|
|
|
|
for(i=0; i<npkg; i++) {
|
|
|
|
nobj = 0;
|
|
|
|
for(l=0; l<njob; l++)
|
|
|
|
if(job[l].pass == k && job[l].pkg == pkg[i])
|
|
|
|
obj[nobj++] = goobj(job[l].name, "$O");
|
|
|
|
if(nobj > 0) {
|
|
|
|
Bprint(&bout, "\t$(AR) grc %s.a", pkg[i]);
|
|
|
|
for(l=0; l<nobj; l++)
|
|
|
|
Bprint(&bout, " %$", obj[l]);
|
|
|
|
Bprint(&bout, "\n");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Bprint(&bout, "\trm -f $(O%d)\n", k+1);
|
|
|
|
Bprint(&bout, "\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
// newpkg: clean
|
|
|
|
// 6ar grc pkg.a
|
|
|
|
Bprint(&bout, "newpkg: clean\n");
|
|
|
|
for(i=0; i<npkg; i++)
|
|
|
|
Bprint(&bout, "\t$(AR) grc %s.a\n", pkg[i]);
|
|
|
|
Bprint(&bout, "\n");
|
|
|
|
|
|
|
|
// $(O1): newpkg
|
|
|
|
// $(O2): a1
|
|
|
|
Bprint(&bout, "$(O1): newpkg\n");
|
|
|
|
for(i=1; i<pass; i++)
|
|
|
|
Bprint(&bout, "$(O%d): a%d\n", i+1, i);
|
|
|
|
Bprint(&bout, "\n");
|
|
|
|
|
|
|
|
// nuke: clean
|
|
|
|
// rm -f $(GOROOT)/pkg/xxx.a
|
|
|
|
Bprint(&bout, "nuke: clean\n");
|
|
|
|
Bprint(&bout, "\trm -f");
|
|
|
|
for(i=0; i<npkg; i++)
|
|
|
|
Bprint(&bout, " $(GOROOT)/pkg/%s.a", pkg[i]);
|
|
|
|
Bprint(&bout, "\n\n");
|
|
|
|
|
|
|
|
// packages: pkg.a
|
|
|
|
// rm -f $(GOROOT)/pkg/xxx.a
|
|
|
|
Bprint(&bout, "packages:");
|
|
|
|
for(i=0; i<npkg; i++)
|
|
|
|
Bprint(&bout, " %s.a", pkg[i]);
|
|
|
|
Bprint(&bout, "\n\n");
|
|
|
|
|
|
|
|
// install: packages
|
|
|
|
// cp xxx.a $(GOROOT)/pkg/xxx.a
|
|
|
|
Bprint(&bout, "install: packages\n");
|
|
|
|
for(i=0; i<npkg; i++)
|
|
|
|
Bprint(&bout, "\tcp %s.a $(GOROOT)/pkg/%s.a\n", pkg[i], pkg[i]);
|
|
|
|
Bprint(&bout, "\n");
|
|
|
|
|
|
|
|
Bterm(&bout);
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
sourcefilenames(char ***argvp)
|
|
|
|
{
|
|
|
|
Dir *d;
|
|
|
|
int dir, nd, i, argc;
|
|
|
|
char **argv;
|
|
|
|
|
|
|
|
if((dir = open(".", OREAD)) < 0)
|
|
|
|
sysfatal("open .: %r");
|
|
|
|
|
|
|
|
nd = dirreadall(dir, &d);
|
|
|
|
close(dir);
|
|
|
|
|
|
|
|
argv = emalloc((nd+1)*sizeof argv[0]);
|
|
|
|
argc = 0;
|
|
|
|
for(i=0; i<nd; i++) {
|
|
|
|
if(suffix(d[i].name, ".go")
|
|
|
|
|| suffix(d[i].name, ".c")
|
|
|
|
|| suffix(d[i].name, ".s"))
|
|
|
|
argv[argc++] = d[i].name;
|
|
|
|
}
|
|
|
|
*argvp = argv;
|
|
|
|
argv[argc] = nil;
|
|
|
|
return argc;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
main(int argc, char **argv)
|
|
|
|
{
|
|
|
|
int i, k, pass, npending, nfail, nsuccess, narfiles;
|
|
|
|
Job **pending, **fail, **success, *j;
|
|
|
|
char **arfiles;
|
2008-09-19 12:55:46 -06:00
|
|
|
|
|
|
|
oargc = argc;
|
|
|
|
oargv = argv;
|
2008-09-25 18:07:06 -06:00
|
|
|
fmtinstall('$', dollarfmt);
|
2008-09-19 12:55:46 -06:00
|
|
|
|
2008-09-25 18:07:06 -06:00
|
|
|
goos = getenv("GOOS");
|
|
|
|
if(goos == nil)
|
|
|
|
sysfatal("no $GOOS");
|
2008-09-19 12:55:46 -06:00
|
|
|
goarch = getenv("GOARCH");
|
|
|
|
if(goarch == nil)
|
|
|
|
sysfatal("no $GOARCH");
|
|
|
|
if(strcmp(goarch, "amd64") == 0)
|
|
|
|
thechar = "6";
|
|
|
|
else
|
|
|
|
sysfatal("unknown $GOARCH");
|
2008-11-18 18:11:56 -07:00
|
|
|
devnull = open("/dev/null", OWRITE);
|
|
|
|
if(devnull < 0)
|
|
|
|
sysfatal("open /dev/null: %r");
|
2008-09-19 12:55:46 -06:00
|
|
|
goroot = getenv("GOROOT");
|
|
|
|
if(goroot == nil)
|
|
|
|
sysfatal("no $GOROOT");
|
|
|
|
|
2008-11-18 18:11:56 -07:00
|
|
|
ARGBEGIN{
|
|
|
|
default:
|
2008-09-19 12:55:46 -06:00
|
|
|
usage();
|
2008-11-18 18:11:56 -07:00
|
|
|
case 'm':
|
|
|
|
makefile = 1;
|
|
|
|
break;
|
|
|
|
case 'v':
|
|
|
|
chatty++;
|
|
|
|
break;
|
|
|
|
}ARGEND
|
|
|
|
|
|
|
|
// If no arguments, use all source files in current directory.
|
|
|
|
if(argc == 0)
|
|
|
|
argc = sourcefilenames(&argv);
|
|
|
|
|
|
|
|
// Make the job list.
|
|
|
|
njob = 0;
|
|
|
|
job = emalloc(argc*sizeof job[0]);
|
|
|
|
for(i=0; i<argc; i++) {
|
2008-11-19 20:11:01 -07:00
|
|
|
if(strstr(argv[i], "test.go") != nil)
|
2008-11-18 18:11:56 -07:00
|
|
|
continue;
|
|
|
|
job[njob].name = argv[i];
|
|
|
|
job[njob].pass = -1;
|
|
|
|
job[njob].pkg = getpkg(argv[i]);
|
2008-11-19 13:52:30 -07:00
|
|
|
if(job[njob].pkg && strcmp(job[njob].pkg, "main") == 0)
|
|
|
|
continue;
|
2008-11-18 18:11:56 -07:00
|
|
|
njob++;
|
2008-09-19 12:55:46 -06:00
|
|
|
}
|
|
|
|
|
2008-11-18 18:11:56 -07:00
|
|
|
// Look for non-go files, which don't have packages.
|
|
|
|
// If there's only one package in the go files, use it.
|
|
|
|
for(i=0; i<njob; i++) {
|
|
|
|
if(job[i].pkg == nil) {
|
|
|
|
if(npkg == 1) {
|
|
|
|
job[i].pkg = pkg[0];
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
sysfatal("cannot determine package for %s", job[i].name);
|
|
|
|
}
|
2008-11-13 14:42:26 -07:00
|
|
|
}
|
|
|
|
|
2008-11-18 18:11:56 -07:00
|
|
|
// TODO: subdirectory packages
|
2008-09-19 12:55:46 -06:00
|
|
|
|
2008-11-18 18:11:56 -07:00
|
|
|
// Create empty archives for each package.
|
|
|
|
for(i=0; i<npkg; i++) {
|
|
|
|
unlink(smprint("%s.a", pkg[i]));
|
|
|
|
ar(pkg[i], nil, 0);
|
|
|
|
}
|
2008-09-19 12:55:46 -06:00
|
|
|
|
|
|
|
// Compile by repeated passes: build as many .6 as you can,
|
2008-11-18 18:11:56 -07:00
|
|
|
// put them in their archives, and repeat.
|
|
|
|
pending = emalloc(njob*sizeof pending[0]);
|
|
|
|
for(i=0; i<njob; i++)
|
|
|
|
pending[i] = &job[i];
|
|
|
|
npending = njob;
|
|
|
|
|
|
|
|
fail = emalloc(njob*sizeof fail[0]);
|
|
|
|
success = emalloc(njob*sizeof success[0]);
|
|
|
|
arfiles = emalloc(njob*sizeof arfiles[0]);
|
|
|
|
|
|
|
|
for(pass=0; npending > 0; pass++) {
|
|
|
|
// Run what we can.
|
|
|
|
nfail = 0;
|
|
|
|
nsuccess = 0;
|
|
|
|
for(i=0; i<npending; i++) {
|
|
|
|
j = pending[i];
|
|
|
|
if(buildcc(compiler(j->name), j->name, 0) < 0)
|
|
|
|
fail[nfail++] = j;
|
|
|
|
else{
|
2008-09-19 12:55:46 -06:00
|
|
|
if(chatty == 1)
|
2008-11-18 18:11:56 -07:00
|
|
|
fprint(2, "%s ", j->name);
|
|
|
|
success[nsuccess++] = j;
|
2008-09-19 12:55:46 -06:00
|
|
|
}
|
|
|
|
}
|
2008-11-18 18:11:56 -07:00
|
|
|
if(nsuccess == 0) {
|
|
|
|
// Nothing ran; give up.
|
|
|
|
for(i=0; i<nfail; i++) {
|
|
|
|
j = fail[i];
|
|
|
|
buildcc(compiler(j->name), j->name, 1);
|
|
|
|
}
|
2008-09-19 12:55:46 -06:00
|
|
|
exits("stalemate");
|
|
|
|
}
|
|
|
|
if(chatty == 1)
|
|
|
|
fprint(2, "\n");
|
|
|
|
|
2008-11-18 18:11:56 -07:00
|
|
|
// Update archives.
|
|
|
|
for(i=0; i<npkg; i++) {
|
|
|
|
narfiles = 0;
|
|
|
|
for(k=0; k<nsuccess; k++) {
|
|
|
|
j = success[k];
|
|
|
|
if(j->pkg == pkg[i])
|
|
|
|
arfiles[narfiles++] = goobj(j->name, thechar);
|
|
|
|
j->pass = pass;
|
2008-09-19 12:55:46 -06:00
|
|
|
}
|
2008-11-18 18:11:56 -07:00
|
|
|
if(narfiles > 0)
|
|
|
|
ar(pkg[i], arfiles, narfiles);
|
|
|
|
for(k=0; k<narfiles; k++)
|
|
|
|
unlink(arfiles[k]);
|
2008-09-19 12:55:46 -06:00
|
|
|
}
|
|
|
|
|
2008-11-18 18:11:56 -07:00
|
|
|
for(i=0; i<nfail; i++)
|
|
|
|
pending[i] = fail[i];
|
|
|
|
npending = nfail;
|
2008-09-19 12:55:46 -06:00
|
|
|
}
|
|
|
|
|
2008-11-18 18:11:56 -07:00
|
|
|
if(makefile)
|
|
|
|
writemakefile();
|
2008-09-19 12:55:46 -06:00
|
|
|
exits(0);
|
|
|
|
}
|