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)