bp, err := ctxt.ImportDir(dir, 0)
pkg := new(Package)
pkg.load(&stk, bp, err)
+ pkg.localPrefix = dirToImportPath(dir)
+ pkg.ImportPath = "command-line-arguments"
- pkg.ImportPath = "command-line arguments"
if *buildO == "" {
if pkg.Name == "main" {
_, elem := filepath.Split(gofiles[0])
return a
}
- prefix := "obj"
- if p.target == "" && p.Dir == p.ImportPath {
+ if p.local {
// Imported via local path. No permanent target.
mode = modeBuild
- prefix = "local"
}
- a.objdir = filepath.Join(b.work, prefix, a.p.ImportPath, "_obj") + string(filepath.Separator)
- a.objpkg = buildToolchain.pkgpath(b.work+"/"+prefix, a.p)
+ a.objdir = filepath.Join(b.work, a.p.ImportPath, "_obj") + string(filepath.Separator)
+ a.objpkg = buildToolchain.pkgpath(b.work, a.p)
a.link = p.Name == "main"
switch mode {
// Prepare Go import path list.
inc := b.includeArgs("-I", a.deps)
- // In what directory shall we run the Go compiler?
- // We only pass absolute paths, so most of the time it doesn't matter.
- // Default to the root directory.
- // However, if the package contains local imports (./ or ../)
- // then we need to run the compiler in a directory in the parallel
- // tree of local package objects, so that those imports resolve to the
- // compiled package objects.
- gcdir := filepath.Clean("/")
- for _, imp := range a.p.Imports {
- if build.IsLocalImport(imp) {
- dir := a.p.Dir
- if filepath.Separator == '\\' {
- // Avoid use of : on Windows.
- dir = strings.Replace(dir, ":", "_", -1)
- }
- gcdir = filepath.Join(b.work, "local", dir)
- if err := b.mkdir(gcdir); err != nil {
- return err
- }
- break
- }
- }
-
// Compile Go.
if len(gofiles) > 0 {
- if out, err := buildToolchain.gc(b, a.p, obj, gcdir, inc, gofiles); err != nil {
+ if out, err := buildToolchain.gc(b, a.p, obj, inc, gofiles); err != nil {
return err
} else {
objects = append(objects, out)
func (b *builder) includeArgs(flag string, all []*action) []string {
inc := []string{}
incMap := map[string]bool{
- b.work + "/obj": true, // handled later
- gorootPkg: true,
- "": true, // ignore empty strings
+ b.work: true, // handled later
+ gorootPkg: true,
+ "": true, // ignore empty strings
}
// Look in the temporary space for results of test-specific actions.
// Also look in $WORK for any non-test packages that have
// been built but not installed.
- inc = append(inc, flag, b.work+"/obj")
+ inc = append(inc, flag, b.work)
// Finally, look in the installed package directories for each action.
for _, a1 := range all {
// run runs the command given by cmdline in the directory dir.
// If the command fails, run prints information about the failure
// and returns a non-nil error.
-func (b *builder) run(dir, shortenDir string, desc string, cmdargs ...interface{}) error {
+func (b *builder) run(dir string, desc string, cmdargs ...interface{}) error {
out, err := b.runOut(dir, desc, cmdargs...)
if len(out) > 0 {
if out[len(out)-1] != '\n' {
if desc == "" {
desc = b.fmtcmd(dir, "%s", strings.Join(stringList(cmdargs...), " "))
}
- b.showOutput(shortenDir, desc, string(out))
+ b.showOutput(dir, desc, string(out))
if err != nil {
err = errPrintedOutput
}
// gc runs the compiler in a specific directory on a set of files
// and returns the name of the generated output file.
// The compiler runs in the directory dir.
- gc(b *builder, p *Package, obj, dir string, importArgs []string, gofiles []string) (ofile string, err error)
+ gc(b *builder, p *Package, obj string, importArgs []string, gofiles []string) (ofile string, err error)
// cc runs the toolchain's C compiler in a directory on a C file
// to produce an output file.
cc(b *builder, p *Package, objdir, ofile, cfile string) error
return tool(archChar + "l")
}
-func (goToolchain) gc(b *builder, p *Package, obj, dir string, importArgs []string, gofiles []string) (ofile string, err error) {
+func (goToolchain) gc(b *builder, p *Package, obj string, importArgs []string, gofiles []string) (ofile string, err error) {
out := "_go_." + archChar
ofile = obj + out
gcargs := []string{"-p", p.ImportPath}
gcargs = append(gcargs, "-+")
}
- args := stringList(tool(archChar+"g"), "-o", ofile, buildGcflags, gcargs, importArgs)
+ args := stringList(tool(archChar+"g"), "-o", ofile, buildGcflags, gcargs, "-D", p.localPrefix, importArgs)
for _, f := range gofiles {
args = append(args, mkAbs(p.Dir, f))
}
- return ofile, b.run(dir, p.Dir, p.ImportPath, args)
+ return ofile, b.run(p.Dir, p.ImportPath, args)
}
func (goToolchain) asm(b *builder, p *Package, obj, ofile, sfile string) error {
sfile = mkAbs(p.Dir, sfile)
- return b.run(p.Dir, p.Dir, p.ImportPath, tool(archChar+"a"), "-I", obj, "-o", ofile, "-DGOOS_"+goos, "-DGOARCH_"+goarch, sfile)
+ return b.run(p.Dir, p.ImportPath, tool(archChar+"a"), "-I", obj, "-o", ofile, "-DGOOS_"+goos, "-DGOARCH_"+goarch, sfile)
}
func (goToolchain) pkgpath(basedir string, p *Package) string {
for _, f := range ofiles {
absOfiles = append(absOfiles, mkAbs(objDir, f))
}
- return b.run(p.Dir, p.Dir, p.ImportPath, tool("pack"), "grc", mkAbs(objDir, afile), absOfiles)
+ return b.run(p.Dir, p.ImportPath, tool("pack"), "grc", mkAbs(objDir, afile), absOfiles)
}
func (goToolchain) ld(b *builder, p *Package, out string, allactions []*action, mainpkg string, ofiles []string) error {
importArgs := b.includeArgs("-L", allactions)
- return b.run(p.Dir, p.Dir, p.ImportPath, tool(archChar+"l"), "-o", out, importArgs, buildLdflags, mainpkg)
+ return b.run(p.Dir, p.ImportPath, tool(archChar+"l"), "-o", out, importArgs, buildLdflags, mainpkg)
}
func (goToolchain) cc(b *builder, p *Package, objdir, ofile, cfile string) error {
inc := filepath.Join(goroot, "pkg", fmt.Sprintf("%s_%s", goos, goarch))
cfile = mkAbs(p.Dir, cfile)
- return b.run(p.Dir, p.Dir, p.ImportPath, tool(archChar+"c"), "-FVw",
+ return b.run(p.Dir, p.ImportPath, tool(archChar+"c"), "-FVw",
"-I", objdir, "-I", inc, "-o", ofile,
"-DGOOS_"+goos, "-DGOARCH_"+goarch, cfile)
}
return gccgoBin
}
-func (gccgoToolchain) gc(b *builder, p *Package, obj, dir string, importArgs []string, gofiles []string) (ofile string, err error) {
+func (gccgoToolchain) gc(b *builder, p *Package, obj string, importArgs []string, gofiles []string) (ofile string, err error) {
out := p.Name + ".o"
ofile = obj + out
gcargs := []string{"-g"}
for _, f := range gofiles {
args = append(args, mkAbs(p.Dir, f))
}
- return ofile, b.run(dir, p.Dir, p.ImportPath, args)
+ return ofile, b.run(p.Dir, p.ImportPath, args)
}
func (gccgoToolchain) asm(b *builder, p *Package, obj, ofile, sfile string) error {
sfile = mkAbs(p.Dir, sfile)
- return b.run(p.Dir, p.Dir, p.ImportPath, "gccgo", "-I", obj, "-o", ofile, "-DGOOS_"+goos, "-DGOARCH_"+goarch, sfile)
+ return b.run(p.Dir, p.ImportPath, "gccgo", "-I", obj, "-o", ofile, "-DGOOS_"+goos, "-DGOARCH_"+goarch, sfile)
}
func (gccgoToolchain) pkgpath(basedir string, p *Package) string {
for _, f := range ofiles {
absOfiles = append(absOfiles, mkAbs(objDir, f))
}
- return b.run(p.Dir, p.Dir, p.ImportPath, "ar", "cru", mkAbs(objDir, afile), absOfiles)
+ return b.run(p.Dir, p.ImportPath, "ar", "cru", mkAbs(objDir, afile), absOfiles)
}
func (tools gccgoToolchain) ld(b *builder, p *Package, out string, allactions []*action, mainpkg string, ofiles []string) error {
ldflags = append(ldflags, afile)
}
ldflags = append(ldflags, cgoldflags...)
- return b.run(p.Dir, p.Dir, p.ImportPath, "gccgo", "-o", out, buildGccgoflags, ofiles, "-Wl,-(", ldflags, "-Wl,-)")
+ return b.run(p.Dir, p.ImportPath, "gccgo", "-o", out, buildGccgoflags, ofiles, "-Wl,-(", ldflags, "-Wl,-)")
}
func (gccgoToolchain) cc(b *builder, p *Package, objdir, ofile, cfile string) error {
inc := filepath.Join(goroot, "pkg", fmt.Sprintf("%s_%s", goos, goarch))
cfile = mkAbs(p.Dir, cfile)
- return b.run(p.Dir, p.Dir, p.ImportPath, "gcc", "-Wall", "-g",
+ return b.run(p.Dir, p.ImportPath, "gcc", "-Wall", "-g",
"-I", objdir, "-I", inc, "-o", ofile,
"-DGOOS_"+goos, "-DGOARCH_"+goarch, "-c", cfile)
}
// gcc runs the gcc C compiler to create an object from a single C file.
func (b *builder) gcc(p *Package, out string, flags []string, cfile string) error {
cfile = mkAbs(p.Dir, cfile)
- return b.run(p.Dir, p.Dir, p.ImportPath, b.gccCmd(p.Dir), flags, "-o", out, "-c", cfile)
+ return b.run(p.Dir, p.ImportPath, b.gccCmd(p.Dir), flags, "-o", out, "-c", cfile)
}
// gccld runs the gcc linker to create an executable from a set of object files
func (b *builder) gccld(p *Package, out string, flags []string, obj []string) error {
- return b.run(p.Dir, p.Dir, p.ImportPath, b.gccCmd(p.Dir), "-o", out, obj, flags)
+ return b.run(p.Dir, p.ImportPath, b.gccCmd(p.Dir), "-o", out, obj, flags)
}
// gccCmd returns a gcc command line prefix
if _, ok := buildToolchain.(gccgoToolchain); ok {
cgoflags = append(cgoflags, "-gccgo")
}
- if err := b.run(p.Dir, p.Dir, p.ImportPath, cgoExe, "-objdir", obj, cgoflags, "--", cgoCFLAGS, p.CgoFiles); err != nil {
+ if err := b.run(p.Dir, p.ImportPath, cgoExe, "-objdir", obj, cgoflags, "--", cgoCFLAGS, p.CgoFiles); err != nil {
return nil, nil, err
}
outGo = append(outGo, gofiles...)
// cgo -dynimport
importC := obj + "_cgo_import.c"
- if err := b.run(p.Dir, p.Dir, p.ImportPath, cgoExe, "-objdir", obj, "-dynimport", dynobj, "-dynout", importC); err != nil {
+ if err := b.run(p.Dir, p.ImportPath, cgoExe, "-objdir", obj, "-dynimport", dynobj, "-dynout", importC); err != nil {
return nil, nil, err
}
"go/scanner"
"go/token"
"os"
+ pathpkg "path"
"path/filepath"
"sort"
"strings"
XTestImports []string `json:",omitempty"` // imports from XTestGoFiles
// Unexported fields are not part of the public API.
- build *build.Package
- pkgdir string // overrides build.PkgDir
- imports []*Package
- deps []*Package
- gofiles []string // GoFiles+CgoFiles+TestGoFiles+XTestGoFiles files, absolute paths
- target string // installed file for this package (may be executable)
- fake bool // synthesized package
- forceBuild bool // this package must be rebuilt
- local bool // imported via local path (./ or ../)
+ build *build.Package
+ pkgdir string // overrides build.PkgDir
+ imports []*Package
+ deps []*Package
+ gofiles []string // GoFiles+CgoFiles+TestGoFiles+XTestGoFiles files, absolute paths
+ target string // installed file for this package (may be executable)
+ fake bool // synthesized package
+ forceBuild bool // this package must be rebuilt
+ local bool // imported via local path (./ or ../)
+ localPrefix string // interpret ./ and ../ imports relative to this prefix
}
func (p *Package) copyBuild(pp *build.Package) {
return loadPackage(arg, stk)
}
+// dirToImportPath returns the pseudo-import path we use for a package
+// outside the Go path. It begins with _/ and then contains the full path
+// to the directory. If the package lives in c:\home\gopher\my\pkg then
+// the pseudo-import path is _/c_/home/gopher/my/pkg.
+// Using a pseudo-import path like this makes the ./ imports no longer
+// a special case, so that all the code to deal with ordinary imports works
+// automatically.
+func dirToImportPath(dir string) string {
+ return pathpkg.Join("_", strings.Replace(filepath.ToSlash(dir), ":", "_", -1))
+}
+
// loadImport scans the directory named by path, which must be an import path,
// but possibly a local import path (an absolute file system path or one beginning
// with ./ or ../). A local relative path is interpreted relative to srcDir.
defer stk.pop()
// Determine canonical identifier for this package.
- // For a local path (./ or ../) the identifier is the full
- // directory name. Otherwise it is the import path.
- pkgid := path
+ // For a local import the identifier is the pseudo-import path
+ // we create from the full directory to the package.
+ // Otherwise it is the usual import path.
+ importPath := path
isLocal := build.IsLocalImport(path)
if isLocal {
- pkgid = filepath.Join(srcDir, path)
+ importPath = dirToImportPath(filepath.Join(srcDir, path))
}
- if p := packageCache[pkgid]; p != nil {
+ if p := packageCache[importPath]; p != nil {
return reusePackage(p, stk)
}
p := new(Package)
- packageCache[pkgid] = p
+ p.local = isLocal
+ p.ImportPath = importPath
+ packageCache[importPath] = p
// Load package.
// Import always returns bp != nil, even if an error occurs,
// in order to return partial information.
bp, err := buildContext.Import(path, srcDir, build.AllowBinary)
+ bp.ImportPath = importPath
p.load(stk, bp, err)
if p.Error != nil && len(importPos) > 0 {
pos := importPos[0]
ImportStack: stk.copy(),
Err: "import loop",
}
- panic("loop")
}
p.Incomplete = true
}
// be the result of calling build.Context.Import.
func (p *Package) load(stk *importStack, bp *build.Package, err error) *Package {
p.copyBuild(bp)
- p.local = build.IsLocalImport(p.ImportPath)
- if p.local {
- // The correct import for this package depends on which
- // directory you are in. Instead, record the full directory path.
- // That can't be used as an import path at all, but at least
- // it uniquely identifies the package.
- p.ImportPath = p.Dir
- }
+
+ // The localPrefix is the path we interpret ./ imports relative to.
+ // Now that we've fixed the import path, it's just the import path.
+ // Synthesized main packages sometimes override this.
+ p.localPrefix = p.ImportPath
+
if err != nil {
p.Incomplete = true
err = expandScanner(err)
}
p1 := loadImport(path, p.Dir, stk, p.build.ImportPos[path])
if p1.local {
- path = p1.Dir
+ path = p1.ImportPath
importPaths[i] = path
}
deps[path] = true