Source file src/go/internal/gcimporter/gcimporter.go
1
2
3
4
5
6 package gcimporter
7
8 import (
9 "bufio"
10 "fmt"
11 "go/build"
12 "go/token"
13 "go/types"
14 "io"
15 "io/ioutil"
16 "os"
17 "path/filepath"
18 "strings"
19 )
20
21
22 const debug = false
23
24 var pkgExts = [...]string{".a", ".o"}
25
26
27
28
29
30
31
32 func FindPkg(path, srcDir string) (filename, id string) {
33 if path == "" {
34 return
35 }
36
37 var noext string
38 switch {
39 default:
40
41
42 if abs, err := filepath.Abs(srcDir); err == nil {
43 srcDir = abs
44 }
45 bp, _ := build.Import(path, srcDir, build.FindOnly|build.AllowBinary)
46 if bp.PkgObj == "" {
47 id = path
48 return
49 }
50 noext = strings.TrimSuffix(bp.PkgObj, ".a")
51 id = bp.ImportPath
52
53 case build.IsLocalImport(path):
54
55 noext = filepath.Join(srcDir, path)
56 id = noext
57
58 case filepath.IsAbs(path):
59
60
61
62 noext = path
63 id = path
64 }
65
66 if false {
67 if path != id {
68 fmt.Printf("%s -> %s\n", path, id)
69 }
70 }
71
72
73 for _, ext := range pkgExts {
74 filename = noext + ext
75 if f, err := os.Stat(filename); err == nil && !f.IsDir() {
76 return
77 }
78 }
79
80 filename = ""
81 return
82 }
83
84
85
86
87
88 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) {
89 var rc io.ReadCloser
90 var id string
91 if lookup != nil {
92
93
94 if path == "unsafe" {
95 return types.Unsafe, nil
96 }
97 id = path
98
99
100 if pkg = packages[id]; pkg != nil && pkg.Complete() {
101 return
102 }
103 f, err := lookup(path)
104 if err != nil {
105 return nil, err
106 }
107 rc = f
108 } else {
109 var filename string
110 filename, id = FindPkg(path, srcDir)
111 if filename == "" {
112 if path == "unsafe" {
113 return types.Unsafe, nil
114 }
115 return nil, fmt.Errorf("can't find import: %q", id)
116 }
117
118
119 if pkg = packages[id]; pkg != nil && pkg.Complete() {
120 return
121 }
122
123
124 f, err := os.Open(filename)
125 if err != nil {
126 return nil, err
127 }
128 defer func() {
129 if err != nil {
130
131 err = fmt.Errorf("%s: %v", filename, err)
132 }
133 }()
134 rc = f
135 }
136 defer rc.Close()
137
138 var hdr string
139 buf := bufio.NewReader(rc)
140 if hdr, err = FindExportData(buf); err != nil {
141 return
142 }
143
144 switch hdr {
145 case "$$\n":
146 err = fmt.Errorf("import %q: old export format no longer supported (recompile library)", path)
147
148 case "$$B\n":
149 var data []byte
150 data, err = ioutil.ReadAll(buf)
151 if err != nil {
152 break
153 }
154
155
156
157
158 if len(data) > 0 && data[0] == 'i' {
159 _, pkg, err = iImportData(fset, packages, data[1:], id)
160 } else {
161 _, pkg, err = BImportData(fset, packages, data, id)
162 }
163
164 default:
165 err = fmt.Errorf("unknown export data header: %q", hdr)
166 }
167
168 return
169 }
170
171 func deref(typ types.Type) types.Type {
172 if p, _ := typ.(*types.Pointer); p != nil {
173 return p.Elem()
174 }
175 return typ
176 }
177
178 type byPath []*types.Package
179
180 func (a byPath) Len() int { return len(a) }
181 func (a byPath) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
182 func (a byPath) Less(i, j int) bool { return a[i].Path() < a[j].Path() }
183
View as plain text