github.com/dannin/go@v0.0.0-20161031215817-d35dfd405eaa/src/cmd/compile/internal/gc/main.go (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:generate go run mkbuiltin.go 6 7 package gc 8 9 import ( 10 "bufio" 11 "bytes" 12 "cmd/compile/internal/ssa" 13 "cmd/internal/obj" 14 "cmd/internal/sys" 15 "flag" 16 "fmt" 17 "io" 18 "log" 19 "os" 20 "path" 21 "runtime" 22 "strconv" 23 "strings" 24 ) 25 26 var imported_unsafe bool 27 28 var ( 29 buildid string 30 ) 31 32 var ( 33 Debug_append int 34 Debug_closure int 35 Debug_panic int 36 Debug_slice int 37 Debug_wb int 38 ) 39 40 // Debug arguments. 41 // These can be specified with the -d flag, as in "-d nil" 42 // to set the debug_checknil variable. In general the list passed 43 // to -d can be comma-separated. 44 var debugtab = []struct { 45 name string 46 val *int 47 }{ 48 {"append", &Debug_append}, // print information about append compilation 49 {"closure", &Debug_closure}, // print information about closure compilation 50 {"disablenil", &disable_checknil}, // disable nil checks 51 {"gcprog", &Debug_gcprog}, // print dump of GC programs 52 {"nil", &Debug_checknil}, // print information about nil checks 53 {"panic", &Debug_panic}, // do not hide any compiler panic 54 {"slice", &Debug_slice}, // print information about slice compilation 55 {"typeassert", &Debug_typeassert}, // print information about type assertion inlining 56 {"wb", &Debug_wb}, // print information about write barriers 57 {"export", &Debug_export}, // print export data 58 } 59 60 func usage() { 61 fmt.Printf("usage: compile [options] file.go...\n") 62 obj.Flagprint(1) 63 Exit(2) 64 } 65 66 func hidePanic() { 67 if Debug_panic == 0 && nsavederrors+nerrors > 0 { 68 // If we've already complained about things 69 // in the program, don't bother complaining 70 // about a panic too; let the user clean up 71 // the code and try again. 72 if err := recover(); err != nil { 73 errorexit() 74 } 75 } 76 } 77 78 func doversion() { 79 p := obj.Expstring() 80 if p == "X:none" { 81 p = "" 82 } 83 sep := "" 84 if p != "" { 85 sep = " " 86 } 87 fmt.Printf("compile version %s%s%s\n", obj.Version, sep, p) 88 os.Exit(0) 89 } 90 91 // supportsDynlink reports whether or not the code generator for the given 92 // architecture supports the -shared and -dynlink flags. 93 func supportsDynlink(arch *sys.Arch) bool { 94 return arch.InFamily(sys.AMD64, sys.ARM, sys.ARM64, sys.I386, sys.PPC64, sys.S390X) 95 } 96 97 // timing data for compiler phases 98 var timings Timings 99 var benchfile string 100 101 func Main() { 102 timings.Start("fe", "init") 103 104 defer hidePanic() 105 106 Ctxt = obj.Linknew(Thearch.LinkArch) 107 Ctxt.DiagFunc = yyerror 108 Ctxt.Bso = bufio.NewWriter(os.Stdout) 109 110 localpkg = mkpkg("") 111 localpkg.Prefix = "\"\"" 112 113 // pseudo-package, for scoping 114 builtinpkg = mkpkg("go.builtin") 115 builtinpkg.Prefix = "go.builtin" // not go%2ebuiltin 116 117 // pseudo-package, accessed by import "unsafe" 118 unsafepkg = mkpkg("unsafe") 119 unsafepkg.Name = "unsafe" 120 121 // real package, referred to by generated runtime calls 122 Runtimepkg = mkpkg("runtime") 123 Runtimepkg.Name = "runtime" 124 125 // pseudo-packages used in symbol tables 126 itabpkg = mkpkg("go.itab") 127 itabpkg.Name = "go.itab" 128 itabpkg.Prefix = "go.itab" // not go%2eitab 129 130 itablinkpkg = mkpkg("go.itablink") 131 itablinkpkg.Name = "go.itablink" 132 itablinkpkg.Prefix = "go.itablink" // not go%2eitablink 133 134 trackpkg = mkpkg("go.track") 135 trackpkg.Name = "go.track" 136 trackpkg.Prefix = "go.track" // not go%2etrack 137 138 typepkg = mkpkg("type") 139 typepkg.Name = "type" 140 141 // pseudo-package used for map zero values 142 mappkg = mkpkg("go.map") 143 mappkg.Name = "go.map" 144 mappkg.Prefix = "go.map" 145 146 Nacl = obj.GOOS == "nacl" 147 if Nacl { 148 flag_largemodel = true 149 } 150 151 flag.BoolVar(&compiling_runtime, "+", false, "compiling runtime") 152 obj.Flagcount("%", "debug non-static initializers", &Debug['%']) 153 obj.Flagcount("B", "disable bounds checking", &Debug['B']) 154 flag.StringVar(&localimport, "D", "", "set relative `path` for local imports") 155 obj.Flagcount("E", "debug symbol export", &Debug['E']) 156 obj.Flagfn1("I", "add `directory` to import search path", addidir) 157 obj.Flagcount("K", "debug missing line numbers", &Debug['K']) 158 obj.Flagcount("N", "disable optimizations", &Debug['N']) 159 obj.Flagcount("S", "print assembly listing", &Debug['S']) 160 obj.Flagfn0("V", "print compiler version", doversion) 161 obj.Flagcount("W", "debug parse tree after type checking", &Debug['W']) 162 flag.StringVar(&asmhdr, "asmhdr", "", "write assembly header to `file`") 163 flag.StringVar(&buildid, "buildid", "", "record `id` as the build id in the export metadata") 164 flag.BoolVar(&pure_go, "complete", false, "compiling complete package (no C or assembly)") 165 flag.StringVar(&debugstr, "d", "", "print debug information about items in `list`") 166 obj.Flagcount("e", "no limit on number of errors reported", &Debug['e']) 167 obj.Flagcount("f", "debug stack frames", &Debug['f']) 168 obj.Flagcount("h", "halt on error", &Debug['h']) 169 obj.Flagcount("i", "debug line number stack", &Debug['i']) 170 obj.Flagfn1("importmap", "add `definition` of the form source=actual to import map", addImportMap) 171 flag.StringVar(&flag_installsuffix, "installsuffix", "", "set pkg directory `suffix`") 172 obj.Flagcount("j", "debug runtime-initialized variables", &Debug['j']) 173 obj.Flagcount("l", "disable inlining", &Debug['l']) 174 flag.StringVar(&linkobj, "linkobj", "", "write linker-specific object to `file`") 175 obj.Flagcount("live", "debug liveness analysis", &debuglive) 176 obj.Flagcount("m", "print optimization decisions", &Debug['m']) 177 flag.BoolVar(&flag_msan, "msan", false, "build code compatible with C/C++ memory sanitizer") 178 flag.BoolVar(&nolocalimports, "nolocalimports", false, "reject local (relative) imports") 179 flag.StringVar(&outfile, "o", "", "write output to `file`") 180 flag.StringVar(&myimportpath, "p", "", "set expected package import `path`") 181 flag.BoolVar(&writearchive, "pack", false, "write package file instead of object file") 182 obj.Flagcount("r", "debug generated wrappers", &Debug['r']) 183 flag.BoolVar(&flag_race, "race", false, "enable race detector") 184 obj.Flagcount("s", "warn about composite literals that can be simplified", &Debug['s']) 185 flag.StringVar(&Ctxt.LineHist.TrimPathPrefix, "trimpath", "", "remove `prefix` from recorded source file paths") 186 flag.BoolVar(&safemode, "u", false, "reject unsafe code") 187 obj.Flagcount("v", "increase debug verbosity", &Debug['v']) 188 obj.Flagcount("w", "debug type checking", &Debug['w']) 189 flag.BoolVar(&use_writebarrier, "wb", true, "enable write barrier") 190 var flag_shared bool 191 var flag_dynlink bool 192 if supportsDynlink(Thearch.LinkArch.Arch) { 193 flag.BoolVar(&flag_shared, "shared", false, "generate code that can be linked into a shared library") 194 flag.BoolVar(&flag_dynlink, "dynlink", false, "support references to Go symbols defined in other shared libraries") 195 } 196 if Thearch.LinkArch.Family == sys.AMD64 { 197 flag.BoolVar(&flag_largemodel, "largemodel", false, "generate code that assumes a large memory model") 198 } 199 flag.StringVar(&cpuprofile, "cpuprofile", "", "write cpu profile to `file`") 200 flag.StringVar(&memprofile, "memprofile", "", "write memory profile to `file`") 201 flag.Int64Var(&memprofilerate, "memprofilerate", 0, "set runtime.MemProfileRate to `rate`") 202 flag.StringVar(&traceprofile, "traceprofile", "", "write an execution trace to `file`") 203 flag.StringVar(&benchfile, "bench", "", "append benchmark times to `file`") 204 obj.Flagparse(usage) 205 206 Ctxt.Flag_shared = flag_dynlink || flag_shared 207 Ctxt.Flag_dynlink = flag_dynlink 208 Ctxt.Flag_optimize = Debug['N'] == 0 209 210 Ctxt.Debugasm = int32(Debug['S']) 211 Ctxt.Debugvlog = int32(Debug['v']) 212 213 if flag.NArg() < 1 { 214 usage() 215 } 216 217 startProfile() 218 219 if flag_race { 220 racepkg = mkpkg("runtime/race") 221 racepkg.Name = "race" 222 } 223 if flag_msan { 224 msanpkg = mkpkg("runtime/msan") 225 msanpkg.Name = "msan" 226 } 227 if flag_race && flag_msan { 228 log.Fatal("cannot use both -race and -msan") 229 } else if flag_race || flag_msan { 230 instrumenting = true 231 } 232 233 // parse -d argument 234 if debugstr != "" { 235 Split: 236 for _, name := range strings.Split(debugstr, ",") { 237 if name == "" { 238 continue 239 } 240 val := 1 241 valstring := "" 242 if i := strings.Index(name, "="); i >= 0 { 243 var err error 244 val, err = strconv.Atoi(name[i+1:]) 245 if err != nil { 246 log.Fatalf("invalid debug value %v", name) 247 } 248 name = name[:i] 249 } else if i := strings.Index(name, ":"); i >= 0 { 250 valstring = name[i+1:] 251 name = name[:i] 252 } 253 for _, t := range debugtab { 254 if t.name == name { 255 if t.val != nil { 256 *t.val = val 257 continue Split 258 } 259 } 260 } 261 // special case for ssa for now 262 if strings.HasPrefix(name, "ssa/") { 263 // expect form ssa/phase/flag 264 // e.g. -d=ssa/generic_cse/time 265 // _ in phase name also matches space 266 phase := name[4:] 267 flag := "debug" // default flag is debug 268 if i := strings.Index(phase, "/"); i >= 0 { 269 flag = phase[i+1:] 270 phase = phase[:i] 271 } 272 err := ssa.PhaseOption(phase, flag, val, valstring) 273 if err != "" { 274 log.Fatalf(err) 275 } 276 continue Split 277 } 278 log.Fatalf("unknown debug key -d %s\n", name) 279 } 280 } 281 282 // enable inlining. for now: 283 // default: inlining on. (debug['l'] == 1) 284 // -l: inlining off (debug['l'] == 0) 285 // -ll, -lll: inlining on again, with extra debugging (debug['l'] > 1) 286 if Debug['l'] <= 1 { 287 Debug['l'] = 1 - Debug['l'] 288 } 289 290 Widthint = Thearch.LinkArch.IntSize 291 Widthptr = Thearch.LinkArch.PtrSize 292 Widthreg = Thearch.LinkArch.RegSize 293 294 initUniverse() 295 296 blockgen = 1 297 dclcontext = PEXTERN 298 nerrors = 0 299 lexlineno = 1 300 301 timings.Start("fe", "loadsys") 302 loadsys() 303 304 timings.Start("fe", "parse") 305 lexlineno0 := lexlineno 306 for _, infile = range flag.Args() { 307 linehistpush(infile) 308 block = 1 309 iota_ = -1000000 310 imported_unsafe = false 311 parseFile(infile) 312 if nsyntaxerrors != 0 { 313 errorexit() 314 } 315 316 // Instead of converting EOF into '\n' in getc and count it as an extra line 317 // for the line history to work, and which then has to be corrected elsewhere, 318 // just add a line here. 319 lexlineno++ 320 linehistpop() 321 } 322 timings.Stop() 323 timings.AddEvent(int64(lexlineno-lexlineno0), "lines") 324 325 testdclstack() 326 mkpackage(localpkg.Name) // final import not used checks 327 finishUniverse() 328 329 typecheckok = true 330 if Debug['f'] != 0 { 331 frame(1) 332 } 333 334 // Process top-level declarations in phases. 335 336 // Phase 1: const, type, and names and types of funcs. 337 // This will gather all the information about types 338 // and methods but doesn't depend on any of it. 339 defercheckwidth() 340 341 // Don't use range--typecheck can add closures to xtop. 342 timings.Start("fe", "typecheck", "top1") 343 for i := 0; i < len(xtop); i++ { 344 if xtop[i].Op != ODCL && xtop[i].Op != OAS && xtop[i].Op != OAS2 { 345 xtop[i] = typecheck(xtop[i], Etop) 346 } 347 } 348 349 // Phase 2: Variable assignments. 350 // To check interface assignments, depends on phase 1. 351 352 // Don't use range--typecheck can add closures to xtop. 353 timings.Start("fe", "typecheck", "top2") 354 for i := 0; i < len(xtop); i++ { 355 if xtop[i].Op == ODCL || xtop[i].Op == OAS || xtop[i].Op == OAS2 { 356 xtop[i] = typecheck(xtop[i], Etop) 357 } 358 } 359 resumecheckwidth() 360 361 // Phase 3: Type check function bodies. 362 // Don't use range--typecheck can add closures to xtop. 363 timings.Start("fe", "typecheck", "func") 364 var fcount int64 365 for i := 0; i < len(xtop); i++ { 366 if xtop[i].Op == ODCLFUNC || xtop[i].Op == OCLOSURE { 367 Curfn = xtop[i] 368 decldepth = 1 369 saveerrors() 370 typecheckslice(Curfn.Nbody.Slice(), Etop) 371 checkreturn(Curfn) 372 if nerrors != 0 { 373 Curfn.Nbody.Set(nil) // type errors; do not compile 374 } 375 fcount++ 376 } 377 } 378 timings.AddEvent(fcount, "funcs") 379 380 // Phase 4: Decide how to capture closed variables. 381 // This needs to run before escape analysis, 382 // because variables captured by value do not escape. 383 timings.Start("fe", "capturevars") 384 for _, n := range xtop { 385 if n.Op == ODCLFUNC && n.Func.Closure != nil { 386 Curfn = n 387 capturevars(n) 388 } 389 } 390 391 Curfn = nil 392 393 if nsavederrors+nerrors != 0 { 394 errorexit() 395 } 396 397 // Phase 5: Inlining 398 timings.Start("fe", "inlining") 399 if Debug['l'] > 1 { 400 // Typecheck imported function bodies if debug['l'] > 1, 401 // otherwise lazily when used or re-exported. 402 for _, n := range importlist { 403 if n.Func.Inl.Len() != 0 { 404 saveerrors() 405 typecheckinl(n) 406 } 407 } 408 409 if nsavederrors+nerrors != 0 { 410 errorexit() 411 } 412 } 413 414 if Debug['l'] != 0 { 415 // Find functions that can be inlined and clone them before walk expands them. 416 visitBottomUp(xtop, func(list []*Node, recursive bool) { 417 for _, n := range list { 418 if !recursive { 419 caninl(n) 420 } else { 421 if Debug['m'] > 1 { 422 fmt.Printf("%v: cannot inline %v: recursive\n", n.Line(), n.Func.Nname) 423 } 424 } 425 inlcalls(n) 426 } 427 }) 428 } 429 430 // Phase 6: Escape analysis. 431 // Required for moving heap allocations onto stack, 432 // which in turn is required by the closure implementation, 433 // which stores the addresses of stack variables into the closure. 434 // If the closure does not escape, it needs to be on the stack 435 // or else the stack copier will not update it. 436 // Large values are also moved off stack in escape analysis; 437 // because large values may contain pointers, it must happen early. 438 timings.Start("fe", "escapes") 439 escapes(xtop) 440 441 // Phase 7: Transform closure bodies to properly reference captured variables. 442 // This needs to happen before walk, because closures must be transformed 443 // before walk reaches a call of a closure. 444 timings.Start("fe", "xclosures") 445 for _, n := range xtop { 446 if n.Op == ODCLFUNC && n.Func.Closure != nil { 447 Curfn = n 448 transformclosure(n) 449 } 450 } 451 452 Curfn = nil 453 454 // Phase 8: Compile top level functions. 455 // Don't use range--walk can add functions to xtop. 456 timings.Start("be", "compilefuncs") 457 fcount = 0 458 for i := 0; i < len(xtop); i++ { 459 if xtop[i].Op == ODCLFUNC { 460 funccompile(xtop[i]) 461 fcount++ 462 } 463 } 464 timings.AddEvent(fcount, "funcs") 465 466 if nsavederrors+nerrors == 0 { 467 fninit(xtop) 468 } 469 470 if compiling_runtime { 471 checknowritebarrierrec() 472 } 473 474 // Phase 9: Check external declarations. 475 timings.Start("be", "externaldcls") 476 for i, n := range externdcl { 477 if n.Op == ONAME { 478 externdcl[i] = typecheck(externdcl[i], Erv) 479 } 480 } 481 482 if nerrors+nsavederrors != 0 { 483 errorexit() 484 } 485 486 timings.Start("be", "dumpobj") 487 dumpobj() 488 if asmhdr != "" { 489 dumpasmhdr() 490 } 491 492 if nerrors+nsavederrors != 0 { 493 errorexit() 494 } 495 496 flusherrors() 497 timings.Stop() 498 499 if benchfile != "" { 500 if err := writebench(benchfile); err != nil { 501 log.Fatalf("cannot write benchmark data: %v", err) 502 } 503 } 504 } 505 506 func writebench(filename string) error { 507 f, err := os.OpenFile(filename, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0666) 508 if err != nil { 509 return err 510 } 511 512 var buf bytes.Buffer 513 fmt.Fprintln(&buf, "commit:", obj.Version) 514 fmt.Fprintln(&buf, "goos:", runtime.GOOS) 515 fmt.Fprintln(&buf, "goarch:", runtime.GOARCH) 516 timings.Write(&buf, "BenchmarkCompile:"+myimportpath+":") 517 518 n, err := f.Write(buf.Bytes()) 519 if err != nil { 520 return err 521 } 522 if n != buf.Len() { 523 panic("bad writer") 524 } 525 526 return f.Close() 527 } 528 529 var importMap = map[string]string{} 530 531 func addImportMap(s string) { 532 if strings.Count(s, "=") != 1 { 533 log.Fatal("-importmap argument must be of the form source=actual") 534 } 535 i := strings.Index(s, "=") 536 source, actual := s[:i], s[i+1:] 537 if source == "" || actual == "" { 538 log.Fatal("-importmap argument must be of the form source=actual; source and actual must be non-empty") 539 } 540 importMap[source] = actual 541 } 542 543 func saveerrors() { 544 nsavederrors += nerrors 545 nerrors = 0 546 } 547 548 func arsize(b *bufio.Reader, name string) int { 549 var buf [ArhdrSize]byte 550 if _, err := io.ReadFull(b, buf[:]); err != nil { 551 return -1 552 } 553 aname := strings.Trim(string(buf[0:16]), " ") 554 if !strings.HasPrefix(aname, name) { 555 return -1 556 } 557 asize := strings.Trim(string(buf[48:58]), " ") 558 i, _ := strconv.Atoi(asize) 559 return i 560 } 561 562 func skiptopkgdef(b *bufio.Reader) bool { 563 // archive header 564 p, err := b.ReadString('\n') 565 if err != nil { 566 log.Fatalf("reading input: %v", err) 567 } 568 if p != "!<arch>\n" { 569 return false 570 } 571 572 // package export block should be first 573 sz := arsize(b, "__.PKGDEF") 574 return sz > 0 575 } 576 577 var idirs []string 578 579 func addidir(dir string) { 580 if dir != "" { 581 idirs = append(idirs, dir) 582 } 583 } 584 585 func isDriveLetter(b byte) bool { 586 return 'a' <= b && b <= 'z' || 'A' <= b && b <= 'Z' 587 } 588 589 // is this path a local name? begins with ./ or ../ or / 590 func islocalname(name string) bool { 591 return strings.HasPrefix(name, "/") || 592 runtime.GOOS == "windows" && len(name) >= 3 && isDriveLetter(name[0]) && name[1] == ':' && name[2] == '/' || 593 strings.HasPrefix(name, "./") || name == "." || 594 strings.HasPrefix(name, "../") || name == ".." 595 } 596 597 func findpkg(name string) (file string, ok bool) { 598 if islocalname(name) { 599 if safemode || nolocalimports { 600 return "", false 601 } 602 603 // try .a before .6. important for building libraries: 604 // if there is an array.6 in the array.a library, 605 // want to find all of array.a, not just array.6. 606 file = fmt.Sprintf("%s.a", name) 607 if _, err := os.Stat(file); err == nil { 608 return file, true 609 } 610 file = fmt.Sprintf("%s.o", name) 611 if _, err := os.Stat(file); err == nil { 612 return file, true 613 } 614 return "", false 615 } 616 617 // local imports should be canonicalized already. 618 // don't want to see "encoding/../encoding/base64" 619 // as different from "encoding/base64". 620 if q := path.Clean(name); q != name { 621 yyerror("non-canonical import path %q (should be %q)", name, q) 622 return "", false 623 } 624 625 for _, dir := range idirs { 626 file = fmt.Sprintf("%s/%s.a", dir, name) 627 if _, err := os.Stat(file); err == nil { 628 return file, true 629 } 630 file = fmt.Sprintf("%s/%s.o", dir, name) 631 if _, err := os.Stat(file); err == nil { 632 return file, true 633 } 634 } 635 636 if obj.GOROOT != "" { 637 suffix := "" 638 suffixsep := "" 639 if flag_installsuffix != "" { 640 suffixsep = "_" 641 suffix = flag_installsuffix 642 } else if flag_race { 643 suffixsep = "_" 644 suffix = "race" 645 } else if flag_msan { 646 suffixsep = "_" 647 suffix = "msan" 648 } 649 650 file = fmt.Sprintf("%s/pkg/%s_%s%s%s/%s.a", obj.GOROOT, obj.GOOS, obj.GOARCH, suffixsep, suffix, name) 651 if _, err := os.Stat(file); err == nil { 652 return file, true 653 } 654 file = fmt.Sprintf("%s/pkg/%s_%s%s%s/%s.o", obj.GOROOT, obj.GOOS, obj.GOARCH, suffixsep, suffix, name) 655 if _, err := os.Stat(file); err == nil { 656 return file, true 657 } 658 } 659 660 return "", false 661 } 662 663 // loadsys loads the definitions for the low-level runtime functions, 664 // so that the compiler can generate calls to them, 665 // but does not make them visible to user code. 666 func loadsys() { 667 block = 1 668 iota_ = -1000000 669 670 importpkg = Runtimepkg 671 typecheckok = true 672 defercheckwidth() 673 674 typs := runtimeTypes() 675 for _, d := range runtimeDecls { 676 sym := Pkglookup(d.name, importpkg) 677 typ := typs[d.typ] 678 switch d.tag { 679 case funcTag: 680 importsym(sym, ONAME) 681 n := newfuncname(sym) 682 n.Type = typ 683 declare(n, PFUNC) 684 case varTag: 685 importvar(sym, typ) 686 default: 687 Fatalf("unhandled declaration tag %v", d.tag) 688 } 689 } 690 691 typecheckok = false 692 resumecheckwidth() 693 importpkg = nil 694 } 695 696 func importfile(f *Val, indent []byte) { 697 if importpkg != nil { 698 Fatalf("importpkg not nil") 699 } 700 701 path_, ok := f.U.(string) 702 if !ok { 703 yyerror("import statement not a string") 704 return 705 } 706 707 if len(path_) == 0 { 708 yyerror("import path is empty") 709 return 710 } 711 712 if isbadimport(path_) { 713 return 714 } 715 716 // The package name main is no longer reserved, 717 // but we reserve the import path "main" to identify 718 // the main package, just as we reserve the import 719 // path "math" to identify the standard math package. 720 if path_ == "main" { 721 yyerror("cannot import \"main\"") 722 errorexit() 723 } 724 725 if myimportpath != "" && path_ == myimportpath { 726 yyerror("import %q while compiling that package (import cycle)", path_) 727 errorexit() 728 } 729 730 if mapped, ok := importMap[path_]; ok { 731 path_ = mapped 732 } 733 734 if path_ == "unsafe" { 735 if safemode { 736 yyerror("cannot import package unsafe") 737 errorexit() 738 } 739 740 importpkg = unsafepkg 741 imported_unsafe = true 742 return 743 } 744 745 if islocalname(path_) { 746 if path_[0] == '/' { 747 yyerror("import path cannot be absolute path") 748 return 749 } 750 751 prefix := Ctxt.Pathname 752 if localimport != "" { 753 prefix = localimport 754 } 755 path_ = path.Join(prefix, path_) 756 757 if isbadimport(path_) { 758 return 759 } 760 } 761 762 file, found := findpkg(path_) 763 if !found { 764 yyerror("can't find import: %q", path_) 765 errorexit() 766 } 767 768 importpkg = mkpkg(path_) 769 770 if importpkg.Imported { 771 return 772 } 773 774 importpkg.Imported = true 775 776 impf, err := os.Open(file) 777 if err != nil { 778 yyerror("can't open import: %q: %v", path_, err) 779 errorexit() 780 } 781 defer impf.Close() 782 imp := bufio.NewReader(impf) 783 784 if strings.HasSuffix(file, ".a") { 785 if !skiptopkgdef(imp) { 786 yyerror("import %s: not a package file", file) 787 errorexit() 788 } 789 } 790 791 // check object header 792 p, err := imp.ReadString('\n') 793 if err != nil { 794 log.Fatalf("reading input: %v", err) 795 } 796 if len(p) > 0 { 797 p = p[:len(p)-1] 798 } 799 800 if p != "empty archive" { 801 if !strings.HasPrefix(p, "go object ") { 802 yyerror("import %s: not a go object file: %s", file, p) 803 errorexit() 804 } 805 806 q := fmt.Sprintf("%s %s %s %s", obj.GOOS, obj.GOARCH, obj.Version, obj.Expstring()) 807 if p[10:] != q { 808 yyerror("import %s: object is [%s] expected [%s]", file, p[10:], q) 809 errorexit() 810 } 811 } 812 813 // process header lines 814 safe := false 815 for { 816 p, err = imp.ReadString('\n') 817 if err != nil { 818 log.Fatalf("reading input: %v", err) 819 } 820 if p == "\n" { 821 break // header ends with blank line 822 } 823 if strings.HasPrefix(p, "safe") { 824 safe = true 825 break // ok to ignore rest 826 } 827 } 828 if safemode && !safe { 829 yyerror("cannot import unsafe package %q", importpkg.Path) 830 } 831 832 // assume files move (get installed) 833 // so don't record the full path. 834 linehistpragma(file[len(file)-len(path_)-2:]) // acts as #pragma lib 835 836 // In the importfile, if we find: 837 // $$\n (textual format): not supported anymore 838 // $$B\n (binary format) : import directly, then feed the lexer a dummy statement 839 840 // look for $$ 841 var c byte 842 for { 843 c, err = imp.ReadByte() 844 if err != nil { 845 break 846 } 847 if c == '$' { 848 c, err = imp.ReadByte() 849 if c == '$' || err != nil { 850 break 851 } 852 } 853 } 854 855 // get character after $$ 856 if err == nil { 857 c, _ = imp.ReadByte() 858 } 859 860 switch c { 861 case '\n': 862 yyerror("cannot import %s: old export format no longer supported (recompile library)", path_) 863 864 case 'B': 865 if Debug_export != 0 { 866 fmt.Printf("importing %s (%s)\n", path_, file) 867 } 868 imp.ReadByte() // skip \n after $$B 869 Import(imp) 870 871 default: 872 yyerror("no import in %q", path_) 873 errorexit() 874 } 875 } 876 877 func pkgnotused(lineno int32, path string, name string) { 878 // If the package was imported with a name other than the final 879 // import path element, show it explicitly in the error message. 880 // Note that this handles both renamed imports and imports of 881 // packages containing unconventional package declarations. 882 // Note that this uses / always, even on Windows, because Go import 883 // paths always use forward slashes. 884 elem := path 885 if i := strings.LastIndex(elem, "/"); i >= 0 { 886 elem = elem[i+1:] 887 } 888 if name == "" || elem == name { 889 yyerrorl(lineno, "imported and not used: %q", path) 890 } else { 891 yyerrorl(lineno, "imported and not used: %q as %s", path, name) 892 } 893 } 894 895 func mkpackage(pkgname string) { 896 if localpkg.Name == "" { 897 if pkgname == "_" { 898 yyerror("invalid package name _") 899 } 900 localpkg.Name = pkgname 901 } else { 902 if pkgname != localpkg.Name { 903 yyerror("package %s; expected %s", pkgname, localpkg.Name) 904 } 905 for _, s := range localpkg.Syms { 906 if s.Def == nil { 907 continue 908 } 909 if s.Def.Op == OPACK { 910 // throw away top-level package name leftover 911 // from previous file. 912 // leave s->block set to cause redeclaration 913 // errors if a conflicting top-level name is 914 // introduced by a different file. 915 if !s.Def.Used && nsyntaxerrors == 0 { 916 pkgnotused(s.Def.Lineno, s.Def.Name.Pkg.Path, s.Name) 917 } 918 s.Def = nil 919 continue 920 } 921 922 if s.Def.Sym != s && s.Flags&SymAlias == 0 { 923 // throw away top-level name left over 924 // from previous import . "x" 925 if s.Def.Name != nil && s.Def.Name.Pack != nil && !s.Def.Name.Pack.Used && nsyntaxerrors == 0 { 926 pkgnotused(s.Def.Name.Pack.Lineno, s.Def.Name.Pack.Name.Pkg.Path, "") 927 s.Def.Name.Pack.Used = true 928 } 929 930 s.Def = nil 931 continue 932 } 933 } 934 } 935 936 if outfile == "" { 937 p := infile 938 if i := strings.LastIndex(p, "/"); i >= 0 { 939 p = p[i+1:] 940 } 941 if runtime.GOOS == "windows" { 942 if i := strings.LastIndex(p, `\`); i >= 0 { 943 p = p[i+1:] 944 } 945 } 946 if i := strings.LastIndex(p, "."); i >= 0 { 947 p = p[:i] 948 } 949 suffix := ".o" 950 if writearchive { 951 suffix = ".a" 952 } 953 outfile = p + suffix 954 } 955 }