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