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

View as plain text