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