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