DEV Community

Linda_pp
Linda_pp

Posted on

TIL: How to Resolve Go Import Paths in Go

#go

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").

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)