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