github.com/rohankumardubey/syslog-redirector-golang@v0.0.0-20140320174030-4859f03d829a/src/cmd/ld/go.c (about) 1 // Copyright 2009 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 // go-specific code shared across loaders (5l, 6l, 8l). 6 7 #include "l.h" 8 #include "../ld/lib.h" 9 10 // accumulate all type information from .6 files. 11 // check for inconsistencies. 12 13 // TODO: 14 // generate debugging section in binary. 15 // once the dust settles, try to move some code to 16 // libmach, so that other linkers and ar can share. 17 18 /* 19 * package import data 20 */ 21 typedef struct Import Import; 22 struct Import 23 { 24 Import *hash; // next in hash table 25 char *prefix; // "type", "var", "func", "const" 26 char *name; 27 char *def; 28 char *file; 29 }; 30 enum { 31 NIHASH = 1024 32 }; 33 static Import *ihash[NIHASH]; 34 static int nimport; 35 static void imported(char *pkg, char *import); 36 37 static int 38 hashstr(char *name) 39 { 40 uint32 h; 41 char *cp; 42 43 h = 0; 44 for(cp = name; *cp; h += *cp++) 45 h *= 1119; 46 h &= 0xffffff; 47 return h; 48 } 49 50 static Import * 51 ilookup(char *name) 52 { 53 int h; 54 Import *x; 55 56 h = hashstr(name) % NIHASH; 57 for(x=ihash[h]; x; x=x->hash) 58 if(x->name[0] == name[0] && strcmp(x->name, name) == 0) 59 return x; 60 x = mal(sizeof *x); 61 x->name = estrdup(name); 62 x->hash = ihash[h]; 63 ihash[h] = x; 64 nimport++; 65 return x; 66 } 67 68 static void loadpkgdata(char*, char*, char*, int); 69 static void loadcgo(char*, char*, char*, int); 70 static int parsemethod(char**, char*, char**); 71 static int parsepkgdata(char*, char*, char**, char*, char**, char**, char**); 72 73 void 74 ldpkg(Biobuf *f, char *pkg, int64 len, char *filename, int whence) 75 { 76 char *data, *p0, *p1, *name; 77 78 if(debug['g']) 79 return; 80 81 if((int)len != len) { 82 fprint(2, "%s: too much pkg data in %s\n", argv0, filename); 83 if(debug['u']) 84 errorexit(); 85 return; 86 } 87 data = mal(len+1); 88 if(Bread(f, data, len) != len) { 89 fprint(2, "%s: short pkg read %s\n", argv0, filename); 90 if(debug['u']) 91 errorexit(); 92 return; 93 } 94 data[len] = '\0'; 95 96 // first \n$$ marks beginning of exports - skip rest of line 97 p0 = strstr(data, "\n$$"); 98 if(p0 == nil) { 99 if(debug['u'] && whence != ArchiveObj) { 100 fprint(2, "%s: cannot find export data in %s\n", argv0, filename); 101 errorexit(); 102 } 103 return; 104 } 105 p0 += 3; 106 while(*p0 != '\n' && *p0 != '\0') 107 p0++; 108 109 // second marks end of exports / beginning of local data 110 p1 = strstr(p0, "\n$$"); 111 if(p1 == nil) { 112 fprint(2, "%s: cannot find end of exports in %s\n", argv0, filename); 113 if(debug['u']) 114 errorexit(); 115 return; 116 } 117 while(p0 < p1 && (*p0 == ' ' || *p0 == '\t' || *p0 == '\n')) 118 p0++; 119 if(p0 < p1) { 120 if(strncmp(p0, "package ", 8) != 0) { 121 fprint(2, "%s: bad package section in %s - %s\n", argv0, filename, p0); 122 if(debug['u']) 123 errorexit(); 124 return; 125 } 126 p0 += 8; 127 while(p0 < p1 && (*p0 == ' ' || *p0 == '\t' || *p0 == '\n')) 128 p0++; 129 name = p0; 130 while(p0 < p1 && *p0 != ' ' && *p0 != '\t' && *p0 != '\n') 131 p0++; 132 if(debug['u'] && whence != ArchiveObj && 133 (p0+6 > p1 || memcmp(p0, " safe\n", 6) != 0)) { 134 fprint(2, "%s: load of unsafe package %s\n", argv0, filename); 135 nerrors++; 136 errorexit(); 137 } 138 if(p0 < p1) { 139 if(*p0 == '\n') 140 *p0++ = '\0'; 141 else { 142 *p0++ = '\0'; 143 while(p0 < p1 && *p0++ != '\n') 144 ; 145 } 146 } 147 if(strcmp(pkg, "main") == 0 && strcmp(name, "main") != 0) { 148 fprint(2, "%s: %s: not package main (package %s)\n", argv0, filename, name); 149 nerrors++; 150 errorexit(); 151 } 152 loadpkgdata(filename, pkg, p0, p1 - p0); 153 } 154 155 // The __.PKGDEF archive summary has no local types. 156 if(whence == Pkgdef) 157 return; 158 159 // local types begin where exports end. 160 // skip rest of line after $$ we found above 161 p0 = p1 + 3; 162 while(*p0 != '\n' && *p0 != '\0') 163 p0++; 164 165 // local types end at next \n$$. 166 p1 = strstr(p0, "\n$$"); 167 if(p1 == nil) { 168 fprint(2, "%s: cannot find end of local types in %s\n", argv0, filename); 169 if(debug['u']) 170 errorexit(); 171 return; 172 } 173 174 loadpkgdata(filename, pkg, p0, p1 - p0); 175 176 // look for cgo section 177 p0 = strstr(p1, "\n$$ // cgo"); 178 if(p0 != nil) { 179 p0 = strchr(p0+1, '\n'); 180 if(p0 == nil) { 181 fprint(2, "%s: found $$ // cgo but no newline in %s\n", argv0, filename); 182 if(debug['u']) 183 errorexit(); 184 return; 185 } 186 p1 = strstr(p0, "\n$$"); 187 if(p1 == nil) 188 p1 = strstr(p0, "\n!\n"); 189 if(p1 == nil) { 190 fprint(2, "%s: cannot find end of // cgo section in %s\n", argv0, filename); 191 if(debug['u']) 192 errorexit(); 193 return; 194 } 195 loadcgo(filename, pkg, p0 + 1, p1 - (p0+1)); 196 } 197 } 198 199 static void 200 loadpkgdata(char *file, char *pkg, char *data, int len) 201 { 202 char *p, *ep, *prefix, *name, *def; 203 Import *x; 204 205 file = estrdup(file); 206 p = data; 207 ep = data + len; 208 while(parsepkgdata(file, pkg, &p, ep, &prefix, &name, &def) > 0) { 209 x = ilookup(name); 210 if(x->prefix == nil) { 211 x->prefix = prefix; 212 x->def = estrdup(def); 213 x->file = file; 214 } else if(strcmp(x->prefix, prefix) != 0) { 215 fprint(2, "%s: conflicting definitions for %s\n", argv0, name); 216 fprint(2, "%s:\t%s %s ...\n", x->file, x->prefix, name); 217 fprint(2, "%s:\t%s %s ...\n", file, prefix, name); 218 nerrors++; 219 } else if(strcmp(x->def, def) != 0) { 220 fprint(2, "%s: conflicting definitions for %s\n", argv0, name); 221 fprint(2, "%s:\t%s %s %s\n", x->file, x->prefix, name, x->def); 222 fprint(2, "%s:\t%s %s %s\n", file, prefix, name, def); 223 nerrors++; 224 } 225 free(name); 226 free(def); 227 } 228 free(file); 229 } 230 231 // replace all "". with pkg. 232 char* 233 expandpkg(char *t0, char *pkg) 234 { 235 int n; 236 char *p; 237 char *w, *w0, *t; 238 239 n = 0; 240 for(p=t0; (p=strstr(p, "\"\".")) != nil; p+=3) 241 n++; 242 243 if(n == 0) 244 return estrdup(t0); 245 246 // use malloc, not mal, so that caller can free 247 w0 = malloc(strlen(t0) + strlen(pkg)*n); 248 if(w0 == nil) { 249 diag("out of memory"); 250 errorexit(); 251 } 252 w = w0; 253 for(p=t=t0; (p=strstr(p, "\"\".")) != nil; p=t) { 254 memmove(w, t, p - t); 255 w += p-t; 256 strcpy(w, pkg); 257 w += strlen(pkg); 258 t = p+2; 259 } 260 strcpy(w, t); 261 return w0; 262 } 263 264 static int 265 parsepkgdata(char *file, char *pkg, char **pp, char *ep, char **prefixp, char **namep, char **defp) 266 { 267 char *p, *prefix, *name, *def, *edef, *meth; 268 int n, inquote; 269 270 // skip white space 271 p = *pp; 272 loop: 273 while(p < ep && (*p == ' ' || *p == '\t' || *p == '\n')) 274 p++; 275 if(p == ep || strncmp(p, "$$\n", 3) == 0) 276 return 0; 277 278 // prefix: (var|type|func|const) 279 prefix = p; 280 if(p + 7 > ep) 281 return -1; 282 if(strncmp(p, "var ", 4) == 0) 283 p += 4; 284 else if(strncmp(p, "type ", 5) == 0) 285 p += 5; 286 else if(strncmp(p, "func ", 5) == 0) 287 p += 5; 288 else if(strncmp(p, "const ", 6) == 0) 289 p += 6; 290 else if(strncmp(p, "import ", 7) == 0) { 291 p += 7; 292 while(p < ep && *p != ' ') 293 p++; 294 p++; 295 name = p; 296 while(p < ep && *p != '\n') 297 p++; 298 if(p >= ep) { 299 fprint(2, "%s: %s: confused in import line\n", argv0, file); 300 nerrors++; 301 return -1; 302 } 303 *p++ = '\0'; 304 imported(pkg, name); 305 goto loop; 306 } 307 else { 308 fprint(2, "%s: %s: confused in pkg data near <<%.40s>>\n", argv0, file, prefix); 309 nerrors++; 310 return -1; 311 } 312 p[-1] = '\0'; 313 314 // name: a.b followed by space 315 name = p; 316 inquote = 0; 317 while(p < ep) { 318 if (*p == ' ' && !inquote) 319 break; 320 321 if(*p == '\\') 322 p++; 323 else if(*p == '"') 324 inquote = !inquote; 325 326 p++; 327 } 328 329 if(p >= ep) 330 return -1; 331 *p++ = '\0'; 332 333 // def: free form to new line 334 def = p; 335 while(p < ep && *p != '\n') 336 p++; 337 if(p >= ep) 338 return -1; 339 edef = p; 340 *p++ = '\0'; 341 342 // include methods on successive lines in def of named type 343 while(parsemethod(&p, ep, &meth) > 0) { 344 *edef++ = '\n'; // overwrites '\0' 345 if(edef+1 > meth) { 346 // We want to indent methods with a single \t. 347 // 6g puts at least one char of indent before all method defs, 348 // so there will be room for the \t. If the method def wasn't 349 // indented we could do something more complicated, 350 // but for now just diagnose the problem and assume 351 // 6g will keep indenting for us. 352 fprint(2, "%s: %s: expected methods to be indented %p %p %.10s\n", argv0, 353 file, edef, meth, meth); 354 nerrors++; 355 return -1; 356 } 357 *edef++ = '\t'; 358 n = strlen(meth); 359 memmove(edef, meth, n); 360 edef += n; 361 } 362 363 name = expandpkg(name, pkg); 364 def = expandpkg(def, pkg); 365 366 // done 367 *pp = p; 368 *prefixp = prefix; 369 *namep = name; 370 *defp = def; 371 return 1; 372 } 373 374 static int 375 parsemethod(char **pp, char *ep, char **methp) 376 { 377 char *p; 378 379 // skip white space 380 p = *pp; 381 while(p < ep && (*p == ' ' || *p == '\t')) 382 p++; 383 if(p == ep) 384 return 0; 385 386 // might be a comment about the method 387 if(p + 2 < ep && strncmp(p, "//", 2) == 0) 388 goto useline; 389 390 // if it says "func (", it's a method 391 if(p + 6 < ep && strncmp(p, "func (", 6) == 0) 392 goto useline; 393 return 0; 394 395 useline: 396 // definition to end of line 397 *methp = p; 398 while(p < ep && *p != '\n') 399 p++; 400 if(p >= ep) { 401 fprint(2, "%s: lost end of line in method definition\n", argv0); 402 *pp = ep; 403 return -1; 404 } 405 *p++ = '\0'; 406 *pp = p; 407 return 1; 408 } 409 410 static void 411 loadcgo(char *file, char *pkg, char *p, int n) 412 { 413 char *pend, *next, *p0, *q; 414 char *f[10], *local, *remote, *lib; 415 int nf; 416 Sym *s; 417 418 USED(file); 419 pend = p + n; 420 p0 = nil; 421 for(; p<pend; p=next) { 422 next = strchr(p, '\n'); 423 if(next == nil) 424 next = ""; 425 else 426 *next++ = '\0'; 427 428 free(p0); 429 p0 = estrdup(p); // save for error message 430 nf = tokenize(p, f, nelem(f)); 431 432 if(strcmp(f[0], "cgo_import_dynamic") == 0) { 433 if(nf < 2 || nf > 4) 434 goto err; 435 436 local = f[1]; 437 remote = local; 438 if(nf > 2) 439 remote = f[2]; 440 lib = ""; 441 if(nf > 3) 442 lib = f[3]; 443 444 if(debug['d']) { 445 fprint(2, "%s: %s: cannot use dynamic imports with -d flag\n", argv0, file); 446 nerrors++; 447 return; 448 } 449 450 if(strcmp(local, "_") == 0 && strcmp(remote, "_") == 0) { 451 // allow #pragma dynimport _ _ "foo.so" 452 // to force a link of foo.so. 453 havedynamic = 1; 454 adddynlib(lib); 455 continue; 456 } 457 458 local = expandpkg(local, pkg); 459 q = strchr(remote, '#'); 460 if(q) 461 *q++ = '\0'; 462 s = lookup(local, 0); 463 if(local != f[1]) 464 free(local); 465 if(s->type == 0 || s->type == SXREF || s->type == SHOSTOBJ) { 466 s->dynimplib = lib; 467 s->extname = remote; 468 s->dynimpvers = q; 469 if(s->type != SHOSTOBJ) 470 s->type = SDYNIMPORT; 471 havedynamic = 1; 472 } 473 continue; 474 } 475 476 if(strcmp(f[0], "cgo_import_static") == 0) { 477 if(nf != 2) 478 goto err; 479 local = f[1]; 480 s = lookup(local, 0); 481 s->type = SHOSTOBJ; 482 s->size = 0; 483 continue; 484 } 485 486 if(strcmp(f[0], "cgo_export_static") == 0 || strcmp(f[0], "cgo_export_dynamic") == 0) { 487 // TODO: Remove once we know Windows is okay. 488 if(strcmp(f[0], "cgo_export_static") == 0 && HEADTYPE == Hwindows) 489 continue; 490 491 if(nf < 2 || nf > 3) 492 goto err; 493 local = f[1]; 494 if(nf > 2) 495 remote = f[2]; 496 else 497 remote = local; 498 local = expandpkg(local, pkg); 499 s = lookup(local, 0); 500 501 if(flag_shared && s == lookup("main", 0)) 502 continue; 503 504 // export overrides import, for openbsd/cgo. 505 // see issue 4878. 506 if(s->dynimplib != nil) { 507 s->dynimplib = nil; 508 s->extname = nil; 509 s->dynimpvers = nil; 510 s->type = 0; 511 } 512 513 if(s->cgoexport == 0) { 514 s->extname = remote; 515 if(ndynexp%32 == 0) 516 dynexp = erealloc(dynexp, (ndynexp+32)*sizeof dynexp[0]); 517 dynexp[ndynexp++] = s; 518 } else if(strcmp(s->extname, remote) != 0) { 519 fprint(2, "%s: conflicting cgo_export directives: %s as %s and %s\n", argv0, s->name, s->extname, remote); 520 nerrors++; 521 return; 522 } 523 if(strcmp(f[0], "cgo_export_static") == 0) 524 s->cgoexport |= CgoExportStatic; 525 else 526 s->cgoexport |= CgoExportDynamic; 527 if(local != f[1]) 528 free(local); 529 continue; 530 } 531 532 if(strcmp(f[0], "cgo_dynamic_linker") == 0) { 533 if(nf != 2) 534 goto err; 535 536 if(!debug['I']) { // not overridden by command line 537 if(interpreter != nil && strcmp(interpreter, f[1]) != 0) { 538 fprint(2, "%s: conflict dynlinker: %s and %s\n", argv0, interpreter, f[1]); 539 nerrors++; 540 return; 541 } 542 free(interpreter); 543 interpreter = estrdup(f[1]); 544 } 545 continue; 546 } 547 548 if(strcmp(f[0], "cgo_ldflag") == 0) { 549 if(nf != 2) 550 goto err; 551 if(nldflag%32 == 0) 552 ldflag = erealloc(ldflag, (nldflag+32)*sizeof ldflag[0]); 553 ldflag[nldflag++] = estrdup(f[1]); 554 continue; 555 } 556 } 557 free(p0); 558 return; 559 560 err: 561 fprint(2, "%s: %s: invalid dynimport line: %s\n", argv0, file, p0); 562 nerrors++; 563 } 564 565 static Sym *markq; 566 static Sym *emarkq; 567 568 static void 569 mark1(Sym *s, Sym *parent) 570 { 571 if(s == S || s->reachable) 572 return; 573 if(strncmp(s->name, "go.weak.", 8) == 0) 574 return; 575 s->reachable = 1; 576 s->reachparent = parent; 577 if(markq == nil) 578 markq = s; 579 else 580 emarkq->queue = s; 581 emarkq = s; 582 } 583 584 void 585 mark(Sym *s) 586 { 587 mark1(s, nil); 588 } 589 590 static void 591 markflood(void) 592 { 593 Auto *a; 594 Prog *p; 595 Sym *s; 596 int i; 597 598 for(s=markq; s!=S; s=s->queue) { 599 if(s->text) { 600 if(debug['v'] > 1) 601 Bprint(&bso, "marktext %s\n", s->name); 602 for(a=s->autom; a; a=a->link) 603 mark1(a->gotype, s); 604 for(p=s->text; p != P; p=p->link) { 605 mark1(p->from.sym, s); 606 mark1(p->to.sym, s); 607 } 608 } 609 for(i=0; i<s->nr; i++) 610 mark1(s->r[i].sym, s); 611 mark1(s->gotype, s); 612 mark1(s->sub, s); 613 mark1(s->outer, s); 614 } 615 } 616 617 static char* 618 markextra[] = 619 { 620 "runtime.morestack", 621 "runtime.morestackx", 622 623 "runtime.morestack00", 624 "runtime.morestack10", 625 "runtime.morestack01", 626 "runtime.morestack11", 627 628 "runtime.morestack8", 629 "runtime.morestack16", 630 "runtime.morestack24", 631 "runtime.morestack32", 632 "runtime.morestack40", 633 "runtime.morestack48", 634 635 // on arm, lock in the div/mod helpers too 636 "_div", 637 "_divu", 638 "_mod", 639 "_modu", 640 }; 641 642 static int 643 isz(Auto *a) 644 { 645 for(; a; a=a->link) 646 if(a->type == D_FILE || a->type == D_FILE1) 647 return 1; 648 return 0; 649 } 650 651 static void 652 addz(Sym *s, Auto *z) 653 { 654 Auto *a, *last; 655 656 // strip out non-z 657 last = nil; 658 for(a = z; a != nil; a = a->link) { 659 if(a->type == D_FILE || a->type == D_FILE1) { 660 if(last == nil) 661 z = a; 662 else 663 last->link = a; 664 last = a; 665 } 666 } 667 if(last) { 668 last->link = s->autom; 669 s->autom = z; 670 } 671 } 672 673 void 674 deadcode(void) 675 { 676 int i; 677 Sym *s, *last, *p; 678 Auto *z; 679 Fmt fmt; 680 681 if(debug['v']) 682 Bprint(&bso, "%5.2f deadcode\n", cputime()); 683 684 mark(lookup(INITENTRY, 0)); 685 for(i=0; i<nelem(markextra); i++) 686 mark(lookup(markextra[i], 0)); 687 688 for(i=0; i<ndynexp; i++) 689 mark(dynexp[i]); 690 691 markflood(); 692 693 // keep each beginning with 'typelink.' if the symbol it points at is being kept. 694 for(s = allsym; s != S; s = s->allsym) { 695 if(strncmp(s->name, "go.typelink.", 12) == 0) 696 s->reachable = s->nr==1 && s->r[0].sym->reachable; 697 } 698 699 // remove dead text but keep file information (z symbols). 700 last = nil; 701 z = nil; 702 for(s = textp; s != nil; s = s->next) { 703 if(!s->reachable) { 704 if(isz(s->autom)) 705 z = s->autom; 706 continue; 707 } 708 if(last == nil) 709 textp = s; 710 else 711 last->next = s; 712 last = s; 713 if(z != nil) { 714 if(!isz(s->autom)) 715 addz(s, z); 716 z = nil; 717 } 718 } 719 if(last == nil) 720 textp = nil; 721 else 722 last->next = nil; 723 724 for(s = allsym; s != S; s = s->allsym) 725 if(strncmp(s->name, "go.weak.", 8) == 0) { 726 s->special = 1; // do not lay out in data segment 727 s->reachable = 1; 728 s->hide = 1; 729 } 730 731 // record field tracking references 732 fmtstrinit(&fmt); 733 for(s = allsym; s != S; s = s->allsym) { 734 if(strncmp(s->name, "go.track.", 9) == 0) { 735 s->special = 1; // do not lay out in data segment 736 s->hide = 1; 737 if(s->reachable) { 738 fmtprint(&fmt, "%s", s->name+9); 739 for(p=s->reachparent; p; p=p->reachparent) 740 fmtprint(&fmt, "\t%s", p->name); 741 fmtprint(&fmt, "\n"); 742 } 743 s->type = SCONST; 744 s->value = 0; 745 } 746 } 747 if(tracksym == nil) 748 return; 749 s = lookup(tracksym, 0); 750 if(!s->reachable) 751 return; 752 addstrdata(tracksym, fmtstrflush(&fmt)); 753 } 754 755 void 756 doweak(void) 757 { 758 Sym *s, *t; 759 760 // resolve weak references only if 761 // target symbol will be in binary anyway. 762 for(s = allsym; s != S; s = s->allsym) { 763 if(strncmp(s->name, "go.weak.", 8) == 0) { 764 t = rlookup(s->name+8, s->version); 765 if(t && t->type != 0 && t->reachable) { 766 s->value = t->value; 767 s->type = t->type; 768 s->outer = t; 769 } else { 770 s->type = SCONST; 771 s->value = 0; 772 } 773 continue; 774 } 775 } 776 } 777 778 void 779 addexport(void) 780 { 781 int i; 782 783 if(HEADTYPE == Hdarwin) 784 return; 785 786 for(i=0; i<ndynexp; i++) 787 adddynsym(dynexp[i]); 788 } 789 790 /* %Z from gc, for quoting import paths */ 791 int 792 Zconv(Fmt *fp) 793 { 794 Rune r; 795 char *s, *se; 796 int n; 797 798 s = va_arg(fp->args, char*); 799 if(s == nil) 800 return fmtstrcpy(fp, "<nil>"); 801 802 se = s + strlen(s); 803 804 // NOTE: Keep in sync with ../gc/go.c:/^Zconv. 805 while(s < se) { 806 n = chartorune(&r, s); 807 s += n; 808 switch(r) { 809 case Runeerror: 810 if(n == 1) { 811 fmtprint(fp, "\\x%02x", (uchar)*(s-1)); 812 break; 813 } 814 // fall through 815 default: 816 if(r < ' ') { 817 fmtprint(fp, "\\x%02x", r); 818 break; 819 } 820 fmtrune(fp, r); 821 break; 822 case '\t': 823 fmtstrcpy(fp, "\\t"); 824 break; 825 case '\n': 826 fmtstrcpy(fp, "\\n"); 827 break; 828 case '\"': 829 case '\\': 830 fmtrune(fp, '\\'); 831 fmtrune(fp, r); 832 break; 833 case 0xFEFF: // BOM, basically disallowed in source code 834 fmtstrcpy(fp, "\\uFEFF"); 835 break; 836 } 837 } 838 return 0; 839 } 840 841 842 typedef struct Pkg Pkg; 843 struct Pkg 844 { 845 uchar mark; 846 uchar checked; 847 Pkg *next; 848 char *path; 849 Pkg **impby; 850 int nimpby; 851 int mimpby; 852 Pkg *all; 853 }; 854 855 static Pkg *phash[1024]; 856 static Pkg *pkgall; 857 858 static Pkg* 859 getpkg(char *path) 860 { 861 Pkg *p; 862 int h; 863 864 h = hashstr(path) % nelem(phash); 865 for(p=phash[h]; p; p=p->next) 866 if(strcmp(p->path, path) == 0) 867 return p; 868 p = mal(sizeof *p); 869 p->path = estrdup(path); 870 p->next = phash[h]; 871 phash[h] = p; 872 p->all = pkgall; 873 pkgall = p; 874 return p; 875 } 876 877 static void 878 imported(char *pkg, char *import) 879 { 880 Pkg *p, *i; 881 882 // everyone imports runtime, even runtime. 883 if(strcmp(import, "\"runtime\"") == 0) 884 return; 885 886 pkg = smprint("\"%Z\"", pkg); // turn pkg path into quoted form, freed below 887 p = getpkg(pkg); 888 i = getpkg(import); 889 if(i->nimpby >= i->mimpby) { 890 i->mimpby *= 2; 891 if(i->mimpby == 0) 892 i->mimpby = 16; 893 i->impby = erealloc(i->impby, i->mimpby*sizeof i->impby[0]); 894 } 895 i->impby[i->nimpby++] = p; 896 free(pkg); 897 } 898 899 static Pkg* 900 cycle(Pkg *p) 901 { 902 int i; 903 Pkg *bad; 904 905 if(p->checked) 906 return 0; 907 908 if(p->mark) { 909 nerrors++; 910 print("import cycle:\n"); 911 print("\t%s\n", p->path); 912 return p; 913 } 914 p->mark = 1; 915 for(i=0; i<p->nimpby; i++) { 916 if((bad = cycle(p->impby[i])) != nil) { 917 p->mark = 0; 918 p->checked = 1; 919 print("\timports %s\n", p->path); 920 if(bad == p) 921 return nil; 922 return bad; 923 } 924 } 925 p->checked = 1; 926 p->mark = 0; 927 return 0; 928 } 929 930 void 931 importcycles(void) 932 { 933 Pkg *p; 934 935 for(p=pkgall; p; p=p->all) 936 cycle(p); 937 } 938 939 void 940 setlinkmode(char *arg) 941 { 942 if(strcmp(arg, "internal") == 0) 943 linkmode = LinkInternal; 944 else if(strcmp(arg, "external") == 0) 945 linkmode = LinkExternal; 946 else if(strcmp(arg, "auto") == 0) 947 linkmode = LinkAuto; 948 else { 949 fprint(2, "unknown link mode -linkmode %s\n", arg); 950 errorexit(); 951 } 952 }