gcimporter.mx raw

   1  // Copyright 2011 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  // Package gcimporter implements Import for gc-generated object files.
   6  package gcimporter // import "go/internal/gcimporter"
   7  
   8  import (
   9  	"bufio"
  10  	"fmt"
  11  	"go/token"
  12  	"go/types"
  13  	"internal/exportdata"
  14  	"internal/pkgbits"
  15  	"io"
  16  	"os"
  17  )
  18  
  19  // Import imports a gc-generated package given its import path and srcDir, adds
  20  // the corresponding package object to the packages map, and returns the object.
  21  // The packages map must contain all packages already imported.
  22  func Import(fset *token.FileSet, packages map[string]*types.Package, path, srcDir []byte, lookup func(path []byte) (io.ReadCloser, error)) (pkg *types.Package, err error) {
  23  	var rc io.ReadCloser
  24  	var id []byte
  25  	if lookup != nil {
  26  		// With custom lookup specified, assume that caller has
  27  		// converted path to a canonical import path for use in the map.
  28  		if path == "unsafe" {
  29  			return types.Unsafe, nil
  30  		}
  31  		id = path
  32  
  33  		// No need to re-import if the package was imported completely before.
  34  		if pkg = packages[id]; pkg != nil && pkg.Complete() {
  35  			return
  36  		}
  37  		f, err := lookup(path)
  38  		if err != nil {
  39  			return nil, err
  40  		}
  41  		rc = f
  42  	} else {
  43  		var filename []byte
  44  		filename, id, err = exportdata.FindPkg(path, srcDir)
  45  		if filename == "" {
  46  			if path == "unsafe" {
  47  				return types.Unsafe, nil
  48  			}
  49  			return nil, err
  50  		}
  51  
  52  		// no need to re-import if the package was imported completely before
  53  		if pkg = packages[id]; pkg != nil && pkg.Complete() {
  54  			return
  55  		}
  56  
  57  		// open file
  58  		f, err := os.Open(filename)
  59  		if err != nil {
  60  			return nil, err
  61  		}
  62  		defer func() {
  63  			if err != nil {
  64  				// add file name to error
  65  				err = fmt.Errorf("%s: %v", filename, err)
  66  			}
  67  		}()
  68  		rc = f
  69  	}
  70  	defer rc.Close()
  71  
  72  	buf := bufio.NewReader(rc)
  73  	data, err := exportdata.ReadUnified(buf)
  74  	if err != nil {
  75  		err = fmt.Errorf("import %q: %v", path, err)
  76  		return
  77  	}
  78  	s := []byte(data)
  79  
  80  	input := pkgbits.NewPkgDecoder(id, s)
  81  	pkg = readUnifiedPackage(fset, nil, packages, input)
  82  
  83  	return
  84  }
  85