1 // Copyright 2011 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.
16 // Path is a validated list of Trees derived from $GOROOT and $GOPATH at init.
19 // Tree describes a Go source tree, either $GOROOT or one from $GOPATH.
25 func newTree(p string) (*Tree, error) {
26 if !filepath.IsAbs(p) {
27 return nil, errors.New("must be absolute")
29 ep, err := filepath.EvalSymlinks(p)
33 return &Tree{Path: ep}, nil
36 // SrcDir returns the tree's package source directory.
37 func (t *Tree) SrcDir() string {
39 return filepath.Join(t.Path, "src", "pkg")
41 return filepath.Join(t.Path, "src")
44 // PkgDir returns the tree's package object directory.
45 func (t *Tree) PkgDir() string {
46 goos, goarch := runtime.GOOS, runtime.GOARCH
47 if e := os.Getenv("GOOS"); e != "" {
50 if e := os.Getenv("GOARCH"); e != "" {
53 return filepath.Join(t.Path, "pkg", goos+"_"+goarch)
56 // BinDir returns the tree's binary executable directory.
57 func (t *Tree) BinDir() string {
59 if gobin := os.Getenv("GOBIN"); gobin != "" {
63 return filepath.Join(t.Path, "bin")
66 // HasSrc returns whether the given package's
67 // source can be found inside this Tree.
68 func (t *Tree) HasSrc(pkg string) bool {
69 fi, err := os.Stat(filepath.Join(t.SrcDir(), pkg))
76 // HasPkg returns whether the given package's
77 // object file can be found inside this Tree.
78 func (t *Tree) HasPkg(pkg string) bool {
79 fi, err := os.Stat(filepath.Join(t.PkgDir(), pkg+".a"))
84 // TODO(adg): check object version is consistent
88 ErrNotFound = errors.New("go/build: package could not be found locally")
89 ErrTreeNotFound = errors.New("go/build: no valid GOROOT or GOPATH could be found")
92 // FindTree takes an import or filesystem path and returns the
93 // tree where the package source should be and the package import path.
94 func FindTree(path string) (tree *Tree, pkg string, err error) {
95 if isLocalPath(path) {
96 if path, err = filepath.Abs(path); err != nil {
99 if path, err = filepath.EvalSymlinks(path); err != nil {
102 for _, t := range Path {
103 tpath := t.SrcDir() + string(filepath.Separator)
104 if !filepath.HasPrefix(path, tpath) {
108 pkg = path[len(tpath):]
111 err = fmt.Errorf("path %q not inside a GOPATH", path)
116 for _, t := range Path {
123 err = ErrTreeNotFound
130 // isLocalPath returns whether the given path is local (/foo ./foo ../foo . ..)
131 // Windows paths that starts with drive letter (c:\foo c:foo) are considered local.
132 func isLocalPath(s string) bool {
133 const sep = string(filepath.Separator)
134 return s == "." || s == ".." ||
135 filepath.HasPrefix(s, sep) ||
136 filepath.HasPrefix(s, "."+sep) || filepath.HasPrefix(s, ".."+sep) ||
137 filepath.VolumeName(s) != ""
141 // argument lists used by the build's gc and ld methods
142 gcImportArgs []string
143 ldImportArgs []string
145 // default tree for remote packages
149 // set up Path: parse and validate GOROOT and GOPATH variables
151 root := runtime.GOROOT()
152 t, err := newTree(root)
154 log.Printf("go/build: invalid GOROOT %q: %v", root, err)
160 for _, p := range filepath.SplitList(os.Getenv("GOPATH")) {
166 log.Printf("go/build: invalid GOPATH %q: %v", p, err)
169 Path = append(Path, t)
170 gcImportArgs = append(gcImportArgs, "-I", t.PkgDir())
171 ldImportArgs = append(ldImportArgs, "-L", t.PkgDir())
173 // select first GOPATH entry as default
174 if defaultTree == nil {
179 // use GOROOT if no valid GOPATH specified
180 if defaultTree == nil && len(Path) > 0 {
181 defaultTree = Path[0]