mirror of
https://github.com/golang/go
synced 2024-11-25 05:57:57 -07:00
ld: detect all import cycles
Fixes #2052. R=r CC=golang-dev https://golang.org/cl/4812053
This commit is contained in:
parent
07c103f6e6
commit
b9b204d55d
161
src/cmd/ld/go.c
161
src/cmd/ld/go.c
@ -32,6 +32,7 @@ enum {
|
|||||||
};
|
};
|
||||||
static Import *ihash[NIHASH];
|
static Import *ihash[NIHASH];
|
||||||
static int nimport;
|
static int nimport;
|
||||||
|
static void imported(char *pkg, char *import);
|
||||||
|
|
||||||
static int
|
static int
|
||||||
hashstr(char *name)
|
hashstr(char *name)
|
||||||
@ -308,12 +309,23 @@ loop:
|
|||||||
p += 6;
|
p += 6;
|
||||||
else if(strncmp(p, "import ", 7) == 0) {
|
else if(strncmp(p, "import ", 7) == 0) {
|
||||||
p += 7;
|
p += 7;
|
||||||
|
while(p < ep && *p != ' ')
|
||||||
|
p++;
|
||||||
|
p++;
|
||||||
|
name = p;
|
||||||
while(p < ep && *p != '\n')
|
while(p < ep && *p != '\n')
|
||||||
p++;
|
p++;
|
||||||
|
if(p >= ep) {
|
||||||
|
fprint(2, "%s: %s: confused in import line\n", argv0, file);
|
||||||
|
nerrors++;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
*p++ = '\0';
|
||||||
|
imported(pkg, name);
|
||||||
goto loop;
|
goto loop;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
fprint(2, "%s: confused in pkg data near <<%.40s>>\n", argv0, prefix);
|
fprint(2, "%s: %s: confused in pkg data near <<%.40s>>\n", argv0, file, prefix);
|
||||||
nerrors++;
|
nerrors++;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -708,3 +720,150 @@ addexport(void)
|
|||||||
for(i=0; i<ndynexp; i++)
|
for(i=0; i<ndynexp; i++)
|
||||||
adddynsym(dynexp[i]);
|
adddynsym(dynexp[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* %Z from gc, for quoting import paths */
|
||||||
|
int
|
||||||
|
Zconv(Fmt *fp)
|
||||||
|
{
|
||||||
|
Rune r;
|
||||||
|
char *s, *se;
|
||||||
|
int n;
|
||||||
|
|
||||||
|
s = va_arg(fp->args, char*);
|
||||||
|
if(s == nil)
|
||||||
|
return fmtstrcpy(fp, "<nil>");
|
||||||
|
|
||||||
|
se = s + strlen(s);
|
||||||
|
while(s < se) {
|
||||||
|
n = chartorune(&r, s);
|
||||||
|
s += n;
|
||||||
|
switch(r) {
|
||||||
|
case Runeerror:
|
||||||
|
if(n == 1) {
|
||||||
|
fmtprint(fp, "\\x%02x", (uchar)*(s-1));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// fall through
|
||||||
|
default:
|
||||||
|
if(r < ' ') {
|
||||||
|
fmtprint(fp, "\\x%02x", r);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
fmtrune(fp, r);
|
||||||
|
break;
|
||||||
|
case '\t':
|
||||||
|
fmtstrcpy(fp, "\\t");
|
||||||
|
break;
|
||||||
|
case '\n':
|
||||||
|
fmtstrcpy(fp, "\\n");
|
||||||
|
break;
|
||||||
|
case '\"':
|
||||||
|
case '\\':
|
||||||
|
fmtrune(fp, '\\');
|
||||||
|
fmtrune(fp, r);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct Pkg Pkg;
|
||||||
|
struct Pkg
|
||||||
|
{
|
||||||
|
uchar mark;
|
||||||
|
uchar checked;
|
||||||
|
Pkg *next;
|
||||||
|
char *path;
|
||||||
|
Pkg **impby;
|
||||||
|
int nimpby;
|
||||||
|
int mimpby;
|
||||||
|
Pkg *all;
|
||||||
|
};
|
||||||
|
|
||||||
|
static Pkg *phash[1024];
|
||||||
|
static Pkg *pkgall;
|
||||||
|
|
||||||
|
static Pkg*
|
||||||
|
getpkg(char *path)
|
||||||
|
{
|
||||||
|
Pkg *p;
|
||||||
|
int h;
|
||||||
|
|
||||||
|
h = hashstr(path) % nelem(phash);
|
||||||
|
for(p=phash[h]; p; p=p->next)
|
||||||
|
if(strcmp(p->path, path) == 0)
|
||||||
|
return p;
|
||||||
|
p = mal(sizeof *p);
|
||||||
|
p->path = strdup(path);
|
||||||
|
p->next = phash[h];
|
||||||
|
phash[h] = p;
|
||||||
|
p->all = pkgall;
|
||||||
|
pkgall = p;
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
imported(char *pkg, char *import)
|
||||||
|
{
|
||||||
|
Pkg *p, *i;
|
||||||
|
|
||||||
|
// everyone imports runtime, even runtime.
|
||||||
|
if(strcmp(import, "\"runtime\"") == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
pkg = smprint("\"%Z\"", pkg); // turn pkg path into quoted form, freed below
|
||||||
|
p = getpkg(pkg);
|
||||||
|
i = getpkg(import);
|
||||||
|
if(i->nimpby >= i->mimpby) {
|
||||||
|
i->mimpby *= 2;
|
||||||
|
if(i->mimpby == 0)
|
||||||
|
i->mimpby = 16;
|
||||||
|
i->impby = realloc(i->impby, i->mimpby*sizeof i->impby[0]);
|
||||||
|
}
|
||||||
|
i->impby[i->nimpby++] = p;
|
||||||
|
free(pkg);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Pkg*
|
||||||
|
cycle(Pkg *p)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
Pkg *bad;
|
||||||
|
|
||||||
|
if(p->checked)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if(p->mark) {
|
||||||
|
nerrors++;
|
||||||
|
print("import cycle:\n");
|
||||||
|
print("\t%s\n", p->path);
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
p->mark = 1;
|
||||||
|
for(i=0; i<p->nimpby; i++) {
|
||||||
|
if((bad = cycle(p->impby[i])) != nil) {
|
||||||
|
p->mark = 0;
|
||||||
|
p->checked = 1;
|
||||||
|
print("\timports %s\n", p->path);
|
||||||
|
if(bad == p)
|
||||||
|
return nil;
|
||||||
|
return bad;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
p->checked = 1;
|
||||||
|
p->mark = 0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
importcycles(void)
|
||||||
|
{
|
||||||
|
Pkg *p;
|
||||||
|
|
||||||
|
for(p=pkgall; p; p=p->all)
|
||||||
|
cycle(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -62,6 +62,7 @@ libinit(void)
|
|||||||
{
|
{
|
||||||
fmtinstall('i', iconv);
|
fmtinstall('i', iconv);
|
||||||
fmtinstall('Y', Yconv);
|
fmtinstall('Y', Yconv);
|
||||||
|
fmtinstall('Z', Zconv);
|
||||||
mywhatsys(); // get goroot, goarch, goos
|
mywhatsys(); // get goroot, goarch, goos
|
||||||
if(strcmp(goarch, thestring) != 0)
|
if(strcmp(goarch, thestring) != 0)
|
||||||
print("goarch is not known: %s\n", goarch);
|
print("goarch is not known: %s\n", goarch);
|
||||||
@ -281,6 +282,8 @@ loadlib(void)
|
|||||||
// binaries, so leave it enabled on OS X (Mach-O) binaries.
|
// binaries, so leave it enabled on OS X (Mach-O) binaries.
|
||||||
if(!havedynamic && HEADTYPE != Hdarwin)
|
if(!havedynamic && HEADTYPE != Hdarwin)
|
||||||
debug['d'] = 1;
|
debug['d'] = 1;
|
||||||
|
|
||||||
|
importcycles();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -302,3 +302,5 @@ vlong cpos(void);
|
|||||||
void cseek(vlong);
|
void cseek(vlong);
|
||||||
void cseekend(void);
|
void cseekend(void);
|
||||||
void cwrite(void*, int);
|
void cwrite(void*, int);
|
||||||
|
void importcycles(void);
|
||||||
|
int Zconv(Fmt*);
|
||||||
|
Loading…
Reference in New Issue
Block a user