Go import path is corresponding to one directory in filesystem. For example, import "fmt"
is resolved to /usr/local/opt/go/libexec/src/fmt
(opt
is a symlink to directory of the latest Go installation by Homebrew) in my environment.
I needed to resolve the import paths in Go.
At first, I tried go/ast
and go/types
packages. They both have ast.Package
, ast.ImportSpec
and types.Package
structs. But none of them has the directory path of package. They only have its path (e.g. "fmt"
).
- https://golang.org/pkg/go/ast/#Package
- https://golang.org/pkg/go/ast/#ImportSpec
- https://golang.org/pkg/go/types/#Package
But Go compiler resolves each import paths. To know how it does, I explored Go sources. Type checker needs to resolve import paths to know types of symbols from external package. So it must resolve import paths.
Actually resolving paths is done in Importer
interface value in type checking. There are three types of importers provided by Go standard library; gc
, gccgo
and source
, where gc
is for a standard Go compiler, gccgo
is for cgo, and source
is for static analysis tools.
source
seemed to match to my use case.
Implementation of source
importer is in go/internal
package.
And I found how it resolves import paths.
bp, err := p.ctxt.Import(path, srcDir, 0)
where ctxt
is instance of go/build.Context
. It utilizes go/build.Context.Import
method.
Let's see if it gives what I want:
package main
import (
"fmt"
"go/build"
)
func main() {
// Use default context
ctx := build.Default
for _, importPath := range []string{
"fmt",
"github.com/pkg/errors",
} {
pkg, err := ctx.Import(importPath, ".", build.FindOnly)
if err != nil {
panic(err)
}
fmt.Println(importPath, "->", pkg.Dir)
}
}
Output:
fmt -> /usr/local/Cellar/go/1.11.2/libexec/src/fmt
github.com/pkg/errors -> /Users/rhysd/.go/src/github.com/pkg/errors
Yay! I finally could resolve import paths into directory paths.
Setting build.FindOnly
flag is better to avoid cost to collect the entire package information.
Note: Go version is 1.11.2
Top comments (0)