1 // Copyright 2013 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.
5 // Package gccgoimporter implements Import for gccgo-generated object files.
6 package gccgoimporter
// import "go/internal/gccgoimporter"
22 // A PackageInit describes an imported package that needs initialization.
23 type PackageInit
struct {
24 Name
string // short package name
25 InitFunc
string // name of init function
26 Priority
int // priority of init function, see InitData.Priority
29 // The gccgo-specific init data for a package.
30 type InitData
struct {
31 // Initialization priority of this package relative to other packages.
32 // This is based on the maximum depth of the package's dependency graph;
33 // it is guaranteed to be greater than that of its dependencies.
36 // The list of packages which this package depends on to be initialized,
37 // including itself if needed. This is the subset of the transitive closure of
38 // the package's dependencies that need initialization.
42 // Locate the file from which to read export data.
43 // This is intended to replicate the logic in gofrontend.
44 func findExportFile(searchpaths
[]string, pkgpath
string) (string, error
) {
45 for _
, spath
:= range searchpaths
{
46 pkgfullpath
:= filepath
.Join(spath
, pkgpath
)
47 pkgdir
, name
:= filepath
.Split(pkgfullpath
)
49 for _
, filepath
:= range [...]string{
52 pkgdir
+ "lib" + name
+ ".so",
53 pkgdir
+ "lib" + name
+ ".a",
56 fi
, err
:= os
.Stat(filepath
)
57 if err
== nil && !fi
.IsDir() {
63 return "", fmt
.Errorf("%s: could not find export data (tried %s)", pkgpath
, strings
.Join(searchpaths
, ":"))
67 gccgov1Magic
= "v1;\n"
68 gccgov2Magic
= "v2;\n"
69 goimporterMagic
= "\n$$ "
71 aixbigafMagic
= "<big"
74 // Opens the export data file at the given path. If this is an object file,
75 // searches for and opens the .go_export section. If this is an archive,
76 // reads the export data from the first member, which is assumed to be an object file.
77 // This is intended to replicate the logic in gofrontend.
78 func openExportFile(fpath
string) (reader io
.ReadSeeker
, closer io
.Closer
, err error
) {
79 f
, err
:= os
.Open(fpath
)
85 if err
!= nil && closer
!= nil {
91 _
, err
= f
.ReadAt(magic
[:], 0)
96 var objreader io
.ReaderAt
97 switch string(magic
[:]) {
98 case gccgov1Magic
, gccgov2Magic
, goimporterMagic
:
103 case archiveMagic
, aixbigafMagic
:
104 // TODO(pcc): Read the archive directly instead of using "ar".
109 if runtime
.GOOS
== "aix" && runtime
.GOARCH
== "ppc64" {
110 // AIX puts both 32-bit and 64-bit objects in the same archive.
111 // Tell the AIX "ar" command to only care about 64-bit objects.
112 cmd
= exec
.Command("ar", "-X64", "p", fpath
)
114 cmd
= exec
.Command("ar", "p", fpath
)
117 out
, err
= cmd
.Output()
122 objreader
= bytes
.NewReader(out
)
128 ef
, err
:= elf
.NewFile(objreader
)
130 sec
:= ef
.Section(".go_export")
132 err
= fmt
.Errorf("%s: .go_export section not found", fpath
)
139 xf
, err
:= xcoff
.NewFile(objreader
)
141 sdat
:= xf
.CSect(".go_export")
143 err
= fmt
.Errorf("%s: .go_export section not found", fpath
)
146 reader
= bytes
.NewReader(sdat
)
153 // An Importer resolves import paths to Packages. The imports map records
154 // packages already known, indexed by package path.
155 // An importer must determine the canonical package path and check imports
156 // to see if it is already present in the map. If so, the Importer can return
157 // the map entry. Otherwise, the importer must load the package data for the
158 // given path into a new *Package, record it in imports map, and return the
160 type Importer
func(imports
map[string]*types
.Package
, path
, srcDir
string, lookup
func(string) (io
.ReadCloser
, error
)) (*types
.Package
, error
)
162 func GetImporter(searchpaths
[]string, initmap
map[*types
.Package
]InitData
) Importer
{
163 return func(imports
map[string]*types
.Package
, pkgpath
, srcDir
string, lookup
func(string) (io
.ReadCloser
, error
)) (pkg
*types
.Package
, err error
) {
164 // TODO(gri): Use srcDir.
165 // Or not. It's possible that srcDir will fade in importance as
166 // the go command and other tools provide a translation table
167 // for relative imports (like ./foo or vendored imports).
168 if pkgpath
== "unsafe" {
169 return types
.Unsafe
, nil
172 var reader io
.ReadSeeker
175 if p
:= imports
[pkgpath
]; p
!= nil && p
.Complete() {
178 rc
, err
:= lookup(pkgpath
)
179 if err
== nil && rc
!= nil {
181 rs
, ok
:= rc
.(io
.ReadSeeker
)
183 return nil, fmt
.Errorf("gccgo importer requires lookup to return an io.ReadSeeker, have %T", rc
)
186 fpath
= "<lookup " + pkgpath
+ ">"
187 // Take name from Name method (like on os.File) if present.
188 if n
, ok
:= rc
.(interface{ Name() string }); ok
{
194 fpath
, err
= findExportFile(searchpaths
, pkgpath
)
199 r
, closer
, err
:= openExportFile(fpath
)
210 _
, err
= reader
.Read(magic
[:])
214 _
, err
= reader
.Seek(0, io
.SeekStart
)
219 switch string(magic
[:]) {
220 case gccgov1Magic
, gccgov2Magic
:
222 p
.init(fpath
, reader
, imports
)
223 pkg
= p
.parsePackage()
225 initmap
[pkg
] = p
.initdata
228 // Excluded for now: Standard gccgo doesn't support this import format currently.
229 // case goimporterMagic:
231 // data, err = ioutil.ReadAll(reader)
236 // n, pkg, err = importer.ImportData(imports, data)
241 // if initmap != nil {
242 // suffixreader := bytes.NewReader(data[n:])
244 // p.init(fpath, suffixreader, nil)
246 // initmap[pkg] = p.initdata
250 err
= fmt
.Errorf("unrecognized magic string: %q", string(magic
[:]))