typedef struct Arsymref
{
char *name;
+ char *file;
int type;
int len;
vlong offset;
typedef struct Hashchain
{
char *name;
+ char *file;
struct Hashchain *next;
} Hashchain;
void arstream(int, Arfile*);
int arwrite(int, Armember*);
int bamatch(char*, char*);
-int duplicate(char*);
+int duplicate(char*, char**);
Armember *getdir(Biobuf*);
void getpkgdef(char**, int*);
int getspace(void);
int n;
Arsymref *as;
Arfile *ap;
+ char *ofile;
if (s->type != 'T' && s->type != 'D')
return;
as = armalloc(sizeof(Arsymref));
as->offset = ap->size;
as->name = arstrdup(s->name);
- if(s->type == 'T' && duplicate(as->name)) {
+ as->file = arstrdup(file);
+ if(s->type == 'T' && duplicate(as->name, &ofile)) {
dupfound = 1;
- fprint(2, "duplicate text symbol: %s\n", as->name);
+ fprint(2, "duplicate text symbol: %s and %s: %s\n", as->file, ofile, as->name);
free(as->name);
free(as);
return;
}
int
-duplicate(char *name)
+duplicate(char *name, char **ofile)
{
Hashchain *p;
int h;
h = hashstr(name) % NHASH;
for(p = hash[h]; p; p = p->next)
- if(strcmp(p->name, name) == 0)
+ if(strcmp(p->name, name) == 0) {
+ *ofile = p->file;
return 1;
+ }
p = armalloc(sizeof(Hashchain));
p->next = hash[h];
p->name = name;
+ p->file = file;
hash[h] = p;
+ *ofile = nil;
return 0;
}
while(*--cp==' ')
;
cp[1] = '\0';
- file = name;
+ file = arstrdup(name);
bp->date = strtol(bp->hdr.date, 0, 0);
bp->size = strtol(bp->hdr.size, 0, 0);
return bp;
char *p, *ep, *prefix, *name, *def;
Import *x;
- file = arstrdup(file);
p = data;
ep = data + len;
while(parsepkgdata(&p, ep, &export, &prefix, &name, &def) > 0) {
"sort";
"strings";
"template";
+ "unicode";
+ "utf8";
)
type Pkg struct
f := new(File);
f.Name = filename;
if path.Ext(filename) == ".go" {
+ rune, _ := utf8.DecodeRuneInString(filename);
+ if rune != '_' && !unicode.IsLetter(rune) && !unicode.IsDecimalDigit(rune) {
+ // Ignore files with funny leading letters,
+ // to avoid editor files like .foo.go and ~foo.go.
+ continue;
+ }
+
pkgname, imp, err := PackageImports(filename);
if err != nil {
- fatal("parsing", filename, err.String());
+ fatal("parsing %s: %s", filename, err);
}
if pkgname == "main" {
continue;
// non-Go file: fill in package name.
// Must only be a single package in this directory.
if len(z.Pkgmap) != 1 {
- fatal("cannot determine package for ", f.Name);
+ fatal("cannot determine package for %s", f.Name);
}
f.Pkg = pkg;
}
fail = fail[0:0];
success = success[0:0];
for _, f := range pending {
- if !Build(Compiler(f.Name), f.Name, false) {
+ if !Build(Compiler(f.Name), f.Name, 0) {
PushFile(&fail, f);
} else {
if *verbose {
if len(success) == 0 {
// Nothing ran; give up.
for _, f := range fail {
- Build(Compiler(f.Name), f.Name, true);
+ Build(Compiler(f.Name), f.Name, ShowErrors | ForceDisplay);
}
fatal("stalemate");
}
var err os.Error;
filenames, err= SourceFiles(".");
if err != nil {
- fatal("reading .: ", err.String());
+ fatal("reading .: %s", err.String());
}
}
if *writeMakefile {
t, err := template.Parse(makefileTemplate, makefileMap);
if err != nil {
- fatal("template.Parse: ", err.String());
+ fatal("template.Parse: %s", err.String());
}
err = t.Execute(state, os.Stdout);
if err != nil {
- fatal("template.Expand: ", err.String());
+ fatal("template.Expand: %s", err.String());
}
}
}
package gobuild
import (
+ "bufio";
"exec";
"fmt";
+ "io";
"go/ast";
"go/parser";
"os";
"strings";
)
+const (
+ ShowErrors = 1<<iota;
+ ForceDisplay;
+)
+
var (
theChar string;
goarch string;
const ObjDir = "_obj"
-func fatal(args ...) {
- fmt.Fprintf(os.Stderr, "gobuild: %s\n", fmt.Sprint(args));
+func fatal(format string, args ...) {
+ fmt.Fprintf(os.Stderr, "gobuild: %s\n", fmt.Sprintf(format, args));
os.Exit(1);
}
var ok bool;
theChar, ok = theChars[goarch];
if !ok {
- fatal("unknown $GOARCH: ", goarch);
+ fatal("unknown $GOARCH: %s", goarch);
}
var binaries = []string{
for i, v := range binaries {
var s string;
if s, err = exec.LookPath(v); err != nil {
- fatal("cannot find binary ", v);
+ fatal("cannot find binary %s", v);
}
bin[v] = s;
}
}
-func run(argv []string, display bool) (ok bool) {
+func run(argv []string, flag int) (ok bool) {
argv0 := bin[argv[0]];
- output := exec.DevNull;
- if display {
- output = exec.PassThrough;
+ null, err := os.Open("/dev/null", os.O_RDWR, 0);
+ if err != nil {
+ fatal("open /dev/null: %s", err);
}
- p, err1 := exec.Run(argv0, argv, os.Environ(), exec.DevNull, output, output);
- if err1 != nil {
- return false;
+ defer null.Close();
+ r, w, err := os.Pipe();
+ if err != nil {
+ fatal("pipe: %s", err);
}
- w, err2 := p.Wait(0);
- if err2 != nil {
+ pid, err := os.ForkExec(argv0, argv, os.Environ(), "", []*os.File{null, w, w});
+ defer r.Close();
+ w.Close();
+ if err != nil {
return false;
}
- return w.Exited() && w.ExitStatus() == 0;
-}
-func Build(cmd []string, file string, display bool) (ok bool) {
- if display {
+ // Read the first line of output, if any. Discard the rest.
+ // If there is output and ShowErrors is set, show it,
+ // preceded by a shell command line.
+ // If ForceDisplay is set, we show the command even
+ // if there's no output; this gets set if we're just trying
+ // to keep the user informed.
+ b := bufio.NewReader(r);
+ line, err := b.ReadLineString('\n', true);
+ if flag & ShowErrors != 0 && line != "" || flag & ForceDisplay != 0 {
fmt.Fprint(os.Stderr, "$ ");
- for i, s := range cmd {
+ for i, s := range argv {
fmt.Fprint(os.Stderr, s, " ");
}
- fmt.Fprint(os.Stderr, file, "\n");
+ fmt.Fprint(os.Stderr, "\n");
+ fmt.Fprint(os.Stderr, " ", line);
+ io.Copy(r, null); // don't let process block on pipe
+ }
+ waitmsg, err := os.Wait(pid, 0);
+ if err != nil {
+ return false;
}
+ return waitmsg.Exited() && waitmsg.ExitStatus() == 0;
+}
+func Build(cmd []string, file string, flag int) (ok bool) {
var argv []string;
for i, c := range cmd {
PushString(&argv, c);
}
PushString(&argv, file);
- return run(argv, display);
+ return run(argv, flag);
}
func Archive(pkg string, files []string) {
for i, file := range files {
PushString(&argv, file);
}
- if !run(argv, true) {
+ if !run(argv, ShowErrors) {
fatal("archive failed");
}
}
case strings.HasSuffix(file, ".s"):
return []string{ theChar + "a" };
}
- fatal("don't know how to compile ", file);
+ fatal("don't know how to compile %s", file);
return nil;
}