Source file src/go/internal/gcimporter/gcimporter.go

     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  	"internal/saferio"
    16  	"io"
    17  	"os"
    18  	"strings"
    19  )
    20  
    21  // Import imports a gc-generated package given its import path and srcDir, adds
    22  // the corresponding package object to the packages map, and returns the object.
    23  // The packages map must contain all packages already imported.
    24  func Import(fset *token.FileSet, packages map[string]*types.Package, path, srcDir string, lookup func(path string) (io.ReadCloser, error)) (pkg *types.Package, err error) {
    25  	var rc io.ReadCloser
    26  	var id string
    27  	if lookup != nil {
    28  		// With custom lookup specified, assume that caller has
    29  		// converted path to a canonical import path for use in the map.
    30  		if path == "unsafe" {
    31  			return types.Unsafe, nil
    32  		}
    33  		id = path
    34  
    35  		// No need to re-import if the package was imported completely before.
    36  		if pkg = packages[id]; pkg != nil && pkg.Complete() {
    37  			return
    38  		}
    39  		f, err := lookup(path)
    40  		if err != nil {
    41  			return nil, err
    42  		}
    43  		rc = f
    44  	} else {
    45  		var filename string
    46  		filename, id, err = exportdata.FindPkg(path, srcDir)
    47  		if filename == "" {
    48  			if path == "unsafe" {
    49  				return types.Unsafe, nil
    50  			}
    51  			return nil, err
    52  		}
    53  
    54  		// no need to re-import if the package was imported completely before
    55  		if pkg = packages[id]; pkg != nil && pkg.Complete() {
    56  			return
    57  		}
    58  
    59  		// open file
    60  		f, err := os.Open(filename)
    61  		if err != nil {
    62  			return nil, err
    63  		}
    64  		defer func() {
    65  			if err != nil {
    66  				// add file name to error
    67  				err = fmt.Errorf("%s: %v", filename, err)
    68  			}
    69  		}()
    70  		rc = f
    71  	}
    72  	defer rc.Close()
    73  
    74  	buf := bufio.NewReader(rc)
    75  	hdr, size, err := exportdata.FindExportData(buf)
    76  	if err != nil {
    77  		return
    78  	}
    79  
    80  	switch hdr {
    81  	case "$$\n":
    82  		err = fmt.Errorf("import %q: old textual export format no longer supported (recompile package)", path)
    83  
    84  	case "$$B\n":
    85  		var exportFormat byte
    86  		if exportFormat, err = buf.ReadByte(); err != nil {
    87  			return
    88  		}
    89  		size--
    90  
    91  		// The unified export format starts with a 'u'; the indexed export
    92  		// format starts with an 'i'; and the older binary export format
    93  		// starts with a 'c', 'd', or 'v' (from "version"). Select
    94  		// appropriate importer.
    95  		switch exportFormat {
    96  		case 'u':
    97  			var data []byte
    98  			var r io.Reader = buf
    99  			if size >= 0 {
   100  				if data, err = saferio.ReadData(r, uint64(size)); err != nil {
   101  					return
   102  				}
   103  			} else if data, err = io.ReadAll(r); err != nil {
   104  				return
   105  			}
   106  			s := string(data)
   107  			s = s[:strings.LastIndex(s, "\n$$\n")]
   108  
   109  			input := pkgbits.NewPkgDecoder(id, s)
   110  			pkg = readUnifiedPackage(fset, nil, packages, input)
   111  		default:
   112  			err = fmt.Errorf("import %q: binary export format %q is no longer supported (recompile package)", path, exportFormat)
   113  		}
   114  
   115  	default:
   116  		err = fmt.Errorf("import %q: unknown export data header: %q", path, hdr)
   117  	}
   118  
   119  	return
   120  }
   121  

View as plain text