1
0
mirror of https://github.com/golang/go synced 2024-10-03 17:21:21 -06:00
go/src/cmd/gc/export.c
Russ Cox e6f3aa6c36 gc: include all dependencies in export metadata
This change records more metadata about what
influenced the creation of the object file.
Specifically, if a package imports, say, "fmt" but does not
need to describe any fmt types in its own export data,
that package's object file did not mention the dependency
on "fmt" before.  Now it does.

Listing the import is purely informational.
It has no effect on which files are opened or consulted
when importing a package.

Import lines are marked indirect when they are needed
to explain the API but were not imported directly.
For example http imports crypto/tls and exports
a struct with a field of type tls.ConnectionState,
which contains an x509.Certificate.  Since http does
not import x509 but needs to explain the x509.Certificate
type in its export data, the import of x509 is marked
as indirect.  These import lines were always present;
marking them with the indirect comment makes clear
which were imported directly and which are incidental.

R=ken2
CC=golang-dev
https://golang.org/cl/4295048
2011-03-14 13:22:34 -04:00

429 lines
7.2 KiB
C

// 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.
#include "go.h"
#include "y.tab.h"
static void dumpsym(Sym*);
static void dumpexporttype(Sym*);
static void dumpexportvar(Sym*);
static void dumpexportconst(Sym*);
void
exportsym(Node *n)
{
if(n == N || n->sym == S)
return;
if(n->sym->flags & (SymExport|SymPackage)) {
if(n->sym->flags & SymPackage)
yyerror("export/package mismatch: %S", n->sym);
return;
}
n->sym->flags |= SymExport;
exportlist = list(exportlist, n);
}
static void
packagesym(Node *n)
{
if(n == N || n->sym == S)
return;
if(n->sym->flags & (SymExport|SymPackage)) {
if(n->sym->flags & SymExport)
yyerror("export/package mismatch: %S", n->sym);
return;
}
n->sym->flags |= SymPackage;
exportlist = list(exportlist, n);
}
int
exportname(char *s)
{
Rune r;
if((uchar)s[0] < Runeself)
return 'A' <= s[0] && s[0] <= 'Z';
chartorune(&r, s);
return isupperrune(r);
}
static int
initname(char *s)
{
return strcmp(s, "init") == 0;
}
void
autoexport(Node *n, int ctxt)
{
if(n == N || n->sym == S)
return;
if((ctxt != PEXTERN && ctxt != PFUNC) || dclcontext != PEXTERN)
return;
if(n->ntype && n->ntype->op == OTFUNC && n->ntype->left) // method
return;
if(exportname(n->sym->name) || initname(n->sym->name))
exportsym(n);
else
packagesym(n);
}
static void
dumppkg(Pkg *p)
{
char *suffix;
if(p == nil || p == localpkg || p->exported)
return;
p->exported = 1;
suffix = "";
if(!p->direct)
suffix = " // indirect";
Bprint(bout, "\timport %s \"%Z\"%s\n", p->name, p->path, suffix);
}
static void
dumpprereq(Type *t)
{
if(t == T)
return;
if(t->printed || t == types[t->etype])
return;
t->printed = 1;
if(t->sym != S) {
dumppkg(t->sym->pkg);
if(t->etype != TFIELD)
dumpsym(t->sym);
}
dumpprereq(t->type);
dumpprereq(t->down);
}
static void
dumpexportconst(Sym *s)
{
Node *n;
Type *t;
n = s->def;
typecheck(&n, Erv);
if(n == N || n->op != OLITERAL)
fatal("dumpexportconst: oconst nil: %S", s);
t = n->type; // may or may not be specified
if(t != T)
dumpprereq(t);
Bprint(bout, "\t");
Bprint(bout, "const %#S", s);
if(t != T && !isideal(t))
Bprint(bout, " %#T", t);
Bprint(bout, " = ");
switch(n->val.ctype) {
default:
fatal("dumpexportconst: unknown ctype: %S %d", s, n->val.ctype);
case CTINT:
Bprint(bout, "%B\n", n->val.u.xval);
break;
case CTBOOL:
if(n->val.u.bval)
Bprint(bout, "true\n");
else
Bprint(bout, "false\n");
break;
case CTFLT:
Bprint(bout, "%F\n", n->val.u.fval);
break;
case CTCPLX:
Bprint(bout, "(%F+%F)\n", &n->val.u.cval->real, &n->val.u.cval->imag);
break;
case CTSTR:
Bprint(bout, "\"%Z\"\n", n->val.u.sval);
break;
}
}
static void
dumpexportvar(Sym *s)
{
Node *n;
Type *t;
n = s->def;
typecheck(&n, Erv);
if(n == N || n->type == T) {
yyerror("variable exported but not defined: %S", s);
return;
}
t = n->type;
dumpprereq(t);
Bprint(bout, "\t");
if(t->etype == TFUNC && n->class == PFUNC)
Bprint(bout, "func %#S %#hhT", s, t);
else
Bprint(bout, "var %#S %#T", s, t);
Bprint(bout, "\n");
}
static void
dumpexporttype(Sym *s)
{
Type *t;
t = s->def->type;
dumpprereq(t);
Bprint(bout, "\t");
switch (t->etype) {
case TFORW:
yyerror("export of incomplete type %T", t);
return;
}
if(Bprint(bout, "type %#T %l#T\n", t, t) < 0)
fatal("Bprint failed for %T", t);
}
static int
methcmp(const void *va, const void *vb)
{
Type *a, *b;
a = *(Type**)va;
b = *(Type**)vb;
return strcmp(a->sym->name, b->sym->name);
}
static void
dumpsym(Sym *s)
{
Type *f, *t;
Type **m;
int i, n;
if(s->flags & SymExported)
return;
s->flags |= SymExported;
if(s->def == N) {
yyerror("unknown export symbol: %S", s);
return;
}
dumppkg(s->pkg);
switch(s->def->op) {
default:
yyerror("unexpected export symbol: %O %S", s->def->op, s);
break;
case OLITERAL:
dumpexportconst(s);
break;
case OTYPE:
t = s->def->type;
n = 0;
for(f=t->method; f!=T; f=f->down) {
dumpprereq(f);
n++;
}
m = mal(n*sizeof m[0]);
i = 0;
for(f=t->method; f!=T; f=f->down)
m[i++] = f;
qsort(m, n, sizeof m[0], methcmp);
dumpexporttype(s);
for(i=0; i<n; i++) {
f = m[i];
Bprint(bout, "\tfunc (%#T) %hS %#hhT\n",
f->type->type->type, f->sym, f->type);
}
break;
case ONAME:
dumpexportvar(s);
break;
}
}
static void
dumptype(Type *t)
{
// no need to re-dump type if already exported
if(t->printed)
return;
// no need to dump type if it's not ours (was imported)
if(t->sym != S && t->sym->def == typenod(t) && !t->local)
return;
Bprint(bout, "type %#T %l#T\n", t, t);
}
void
dumpexport(void)
{
NodeList *l;
int32 i, lno;
Pkg *p;
lno = lineno;
packagequotes = 1;
Bprint(bout, "\n$$ // exports\n");
Bprint(bout, " package %s", localpkg->name);
if(safemode)
Bprint(bout, " safe");
Bprint(bout, "\n");
for(i=0; i<nelem(phash); i++)
for(p=phash[i]; p; p=p->link)
if(p->direct)
dumppkg(p);
for(l=exportlist; l; l=l->next) {
lineno = l->n->lineno;
dumpsym(l->n->sym);
}
Bprint(bout, "\n$$ // local types\n");
for(l=typelist; l; l=l->next) {
lineno = l->n->lineno;
dumptype(l->n->type);
}
Bprint(bout, "\n$$\n");
packagequotes = 0;
lineno = lno;
}
/*
* import
*/
/*
* return the sym for ss, which should match lexical
*/
Sym*
importsym(Sym *s, int op)
{
if(s->def != N && s->def->op != op)
redeclare(s, "during import");
// mark the symbol so it is not reexported
if(s->def == N) {
if(exportname(s->name) || initname(s->name))
s->flags |= SymExport;
else
s->flags |= SymPackage; // package scope
}
return s;
}
/*
* return the type pkg.name, forward declaring if needed
*/
Type*
pkgtype(Sym *s)
{
Type *t;
importsym(s, OTYPE);
if(s->def == N || s->def->op != OTYPE) {
t = typ(TFORW);
t->sym = s;
s->def = typenod(t);
}
if(s->def->type == T)
yyerror("pkgtype %lS", s);
return s->def->type;
}
static int
mypackage(Sym *s)
{
// we import all definitions for runtime.
// lowercase ones can only be used by the compiler.
return s->pkg == localpkg || s->pkg == runtimepkg;
}
void
importconst(Sym *s, Type *t, Node *n)
{
Node *n1;
if(!exportname(s->name) && !mypackage(s))
return;
importsym(s, OLITERAL);
convlit(&n, t);
if(s->def != N) {
// TODO: check if already the same.
return;
}
if(n->op != OLITERAL) {
yyerror("expression must be a constant");
return;
}
if(n->sym != S) {
n1 = nod(OXXX, N, N);
*n1 = *n;
n = n1;
}
n->sym = s;
declare(n, PEXTERN);
if(debug['E'])
print("import const %S\n", s);
}
void
importvar(Sym *s, Type *t, int ctxt)
{
Node *n;
if(!exportname(s->name) && !initname(s->name) && !mypackage(s))
return;
importsym(s, ONAME);
if(s->def != N && s->def->op == ONAME) {
if(eqtype(t, s->def->type))
return;
yyerror("inconsistent definition for var %S during import\n\t%T\n\t%T",
s, s->def->type, t);
}
n = newname(s);
n->type = t;
declare(n, ctxt);
if(debug['E'])
print("import var %S %lT\n", s, t);
}
void
importtype(Type *pt, Type *t)
{
if(pt != T && t != T)
typedcl2(pt, t);
if(debug['E'])
print("import type %T %lT\n", pt, t);
}
void
importmethod(Sym *s, Type *t)
{
checkwidth(t);
addmethod(s, t, 0);
}