]> Cypherpunks.ru repositories - gostls13.git/commitdiff
go,cmd,internal: update to anticipate missing targets and .a files
authorMichael Matloob <matloob@golang.org>
Wed, 21 Sep 2022 19:51:27 +0000 (15:51 -0400)
committerMichael Matloob <matloob@golang.org>
Tue, 18 Oct 2022 20:41:45 +0000 (20:41 +0000)
go/build and cmd/go will stop returing Targets for stdlib .a files, and
stop producing the .a files is pkg/GOOS_GOARCH. update tests to
anticipate that and to pass in importcfgs instead of expecting the
compiler can find .a files in their old locations.

Adds code to determine locations of .a files to internal/goroot. Also
adds internal/goroot to dist's bootstrap directories and changes
internal/goroot to build with a bootstrap version of Go.

Change-Id: Ie81e51105bddb3f0e374cbf47e81c23edfb67fa5
Reviewed-on: https://go-review.googlesource.com/c/go/+/442303
Reviewed-by: Michael Matloob <matloob@golang.org>
TryBot-Result: Gopher Robot <gobot@golang.org>
Run-TryBot: Michael Matloob <matloob@golang.org>
Reviewed-by: Bryan Mills <bcmills@google.com>
17 files changed:
src/cmd/compile/internal/importer/gcimporter.go
src/cmd/compile/internal/importer/gcimporter_test.go
src/cmd/dist/buildtool.go
src/cmd/internal/archive/archive_test.go
src/cmd/link/link_test.go
src/cmd/objdump/objdump_test.go
src/cmd/pack/pack_test.go
src/go/build/deps_test.go
src/go/importer/importer_test.go
src/go/internal/gcimporter/gcimporter.go
src/go/internal/gcimporter/gcimporter_test.go
src/internal/abi/abi_test.go
src/internal/goroot/gc.go
src/internal/goroot/importcfg.go [new file with mode: 0644]
src/internal/testenv/testenv.go
src/internal/types/errors/codes_test.go
src/runtime/align_test.go

index f6ec6554a85b5ae30d8f3dcc7b2ece8e26bebb8f..0aa779441a7a3a364ed81aa689f752efce6bd6ee 100644 (file)
@@ -9,9 +9,11 @@ import (
        "bufio"
        "fmt"
        "go/build"
+       "internal/goroot"
        "internal/pkgbits"
        "io"
        "os"
+       "path"
        "path/filepath"
        "strings"
 
@@ -21,7 +23,26 @@ import (
 // debugging/development support
 const debug = false
 
-var pkgExts = [...]string{".a", ".o"}
+func lookupGorootExport(pkgpath, srcRoot, srcDir string) (string, bool) {
+       pkgpath = filepath.ToSlash(pkgpath)
+       m, err := goroot.PkgfileMap()
+       if err != nil {
+               return "", false
+       }
+       if export, ok := m[pkgpath]; ok {
+               return export, true
+       }
+       vendorPrefix := "vendor"
+       if strings.HasPrefix(srcDir, filepath.Join(srcRoot, "cmd")) {
+               vendorPrefix = path.Join("cmd", vendorPrefix)
+       }
+       pkgpath = path.Join(vendorPrefix, pkgpath)
+       fmt.Fprintln(os.Stderr, "looking up ", pkgpath)
+       export, ok := m[pkgpath]
+       return export, ok
+}
+
+var pkgExts = [...]string{".a", ".o"} // a file from the build cache will have no extension
 
 // FindPkg returns the filename and unique package id for an import
 // path based on package information provided by build.Import (using
@@ -43,11 +64,18 @@ func FindPkg(path, srcDir string) (filename, id string) {
                }
                bp, _ := build.Import(path, srcDir, build.FindOnly|build.AllowBinary)
                if bp.PkgObj == "" {
-                       id = path // make sure we have an id to print in error message
-                       return
+                       var ok bool
+                       if bp.Goroot {
+                               filename, ok = lookupGorootExport(path, bp.SrcRoot, srcDir)
+                       }
+                       if !ok {
+                               id = path // make sure we have an id to print in error message
+                               return
+                       }
+               } else {
+                       noext = strings.TrimSuffix(bp.PkgObj, ".a")
+                       id = bp.ImportPath
                }
-               noext = strings.TrimSuffix(bp.PkgObj, ".a")
-               id = bp.ImportPath
 
        case build.IsLocalImport(path):
                // "./x" -> "/this/directory/x.ext", "/this/directory/x"
@@ -68,6 +96,11 @@ func FindPkg(path, srcDir string) (filename, id string) {
                }
        }
 
+       if filename != "" {
+               if f, err := os.Stat(filename); err == nil && !f.IsDir() {
+                       return
+               }
+       }
        // try extensions
        for _, ext := range pkgExts {
                filename = noext + ext
index 2fbd3f00d24a73897dd3f6a881d9f0829a97d3b3..ac502e6e37e8d6a8c5eeea6b53263d2fb95df2e7 100644 (file)
@@ -13,6 +13,7 @@ import (
        "internal/testenv"
        "os"
        "os/exec"
+       "path"
        "path/filepath"
        "runtime"
        "strings"
@@ -37,14 +38,19 @@ func skipSpecialPlatforms(t *testing.T) {
 
 // compile runs the compiler on filename, with dirname as the working directory,
 // and writes the output file to outdirname.
-func compile(t *testing.T, dirname, filename, outdirname string) string {
+// compile gives the resulting package a packagepath of testdata/<filebasename>.
+func compile(t *testing.T, dirname, filename, outdirname string, packagefiles map[string]string) string {
        // filename must end with ".go"
-       if !strings.HasSuffix(filename, ".go") {
+       basename, ok := strings.CutSuffix(filepath.Base(filename), ".go")
+       if !ok {
                t.Fatalf("filename doesn't end in .go: %s", filename)
        }
-       basename := filepath.Base(filename)
-       outname := filepath.Join(outdirname, basename[:len(basename)-2]+"o")
-       cmd := exec.Command(testenv.GoToolPath(t), "tool", "compile", "-p", strings.TrimSuffix(outname, ".o"), "-o", outname, filename)
+       objname := basename + ".o"
+       outname := filepath.Join(outdirname, objname)
+       importcfgfile := filepath.Join(outdirname, basename) + ".importcfg"
+       testenv.WriteImportcfg(t, importcfgfile, packagefiles)
+       pkgpath := path.Join("testdata", basename)
+       cmd := exec.Command(testenv.GoToolPath(t), "tool", "compile", "-p", pkgpath, "-D", "testdata", "-importcfg", importcfgfile, "-o", outname, filename)
        cmd.Dir = dirname
        out, err := cmd.CombinedOutput()
        if err != nil {
@@ -129,7 +135,7 @@ func TestImportTestdata(t *testing.T) {
                tmpdir := mktmpdir(t)
                defer os.RemoveAll(tmpdir)
 
-               compile(t, "testdata", testfile, filepath.Join(tmpdir, "testdata"))
+               compile(t, "testdata", testfile, filepath.Join(tmpdir, "testdata"), nil)
                path := "./testdata/" + strings.TrimSuffix(testfile, ".go")
 
                if pkg := testPath(t, path, tmpdir); pkg != nil {
@@ -436,8 +442,8 @@ func TestIssue13566(t *testing.T) {
        if err != nil {
                t.Fatal(err)
        }
-       compile(t, "testdata", "a.go", testoutdir)
-       compile(t, testoutdir, bpath, testoutdir)
+       compile(t, "testdata", "a.go", testoutdir, nil)
+       compile(t, testoutdir, bpath, testoutdir, map[string]string{"testdata/a": filepath.Join(testoutdir, "a.o")})
 
        // import must succeed (test for issue at hand)
        pkg := importPkg(t, "./testdata/b", tmpdir)
@@ -513,7 +519,7 @@ func TestIssue15517(t *testing.T) {
        tmpdir := mktmpdir(t)
        defer os.RemoveAll(tmpdir)
 
-       compile(t, "testdata", "p.go", filepath.Join(tmpdir, "testdata"))
+       compile(t, "testdata", "p.go", filepath.Join(tmpdir, "testdata"), nil)
 
        // Multiple imports of p must succeed without redeclaration errors.
        // We use an import path that's not cleaned up so that the eventual
@@ -618,7 +624,7 @@ func importPkg(t *testing.T, path, srcDir string) *types2.Package {
 func compileAndImportPkg(t *testing.T, name string) *types2.Package {
        tmpdir := mktmpdir(t)
        defer os.RemoveAll(tmpdir)
-       compile(t, "testdata", name+".go", filepath.Join(tmpdir, "testdata"))
+       compile(t, "testdata", name+".go", filepath.Join(tmpdir, "testdata"), nil)
        return importPkg(t, "./testdata/"+name, tmpdir)
 }
 
index e2699f7656bfa428caef027bed841cfe22d4193a..2a4490b201a9f7fb9cce56934ce260e72424843a 100644 (file)
@@ -63,6 +63,7 @@ var bootstrapDirs = []string{
        "internal/coverage",
        "internal/buildcfg",
        "internal/goexperiment",
+       "internal/goroot",
        "internal/goversion",
        "internal/pkgbits",
        "internal/race",
index cca65af8ed01c547a33083731e94f8ad8f9fc412..f5315856c15f22c74552515d7bdebf9b2f3873f8 100644 (file)
@@ -113,11 +113,14 @@ func buildGoobj(t *testing.T) goobjPaths {
                        go1src := filepath.Join("testdata", "go1.go")
                        go2src := filepath.Join("testdata", "go2.go")
 
-                       out, err := exec.Command(gotool, "tool", "compile", "-p=p", "-o", go1obj, go1src).CombinedOutput()
+                       importcfgfile := filepath.Join(buildDir, "importcfg")
+                       testenv.WriteImportcfg(t, importcfgfile, nil)
+
+                       out, err := exec.Command(gotool, "tool", "compile", "-importcfg="+importcfgfile, "-p=p", "-o", go1obj, go1src).CombinedOutput()
                        if err != nil {
                                return fmt.Errorf("go tool compile -o %s %s: %v\n%s", go1obj, go1src, err, out)
                        }
-                       out, err = exec.Command(gotool, "tool", "compile", "-p=p", "-o", go2obj, go2src).CombinedOutput()
+                       out, err = exec.Command(gotool, "tool", "compile", "-importcfg="+importcfgfile, "-p=p", "-o", go2obj, go2src).CombinedOutput()
                        if err != nil {
                                return fmt.Errorf("go tool compile -o %s %s: %v\n%s", go2obj, go2src, err, out)
                        }
index 35babe61fc0ec93084c9a8c7260517c0244ef426..ce065721649d30baa25bc8bbbb30064f54ce98c0 100644 (file)
@@ -50,19 +50,22 @@ func main() {}
 
        tmpdir := t.TempDir()
 
+       importcfgfile := filepath.Join(tmpdir, "importcfg")
+       testenv.WriteImportcfg(t, importcfgfile, nil)
+
        err := os.WriteFile(filepath.Join(tmpdir, "main.go"), []byte(source), 0666)
        if err != nil {
                t.Fatalf("failed to write main.go: %v\n", err)
        }
 
-       cmd := exec.Command(testenv.GoToolPath(t), "tool", "compile", "-p=main", "main.go")
+       cmd := exec.Command(testenv.GoToolPath(t), "tool", "compile", "-importcfg="+importcfgfile, "-p=main", "main.go")
        cmd.Dir = tmpdir
        out, err := cmd.CombinedOutput()
        if err != nil {
                t.Fatalf("failed to compile main.go: %v, output: %s\n", err, out)
        }
 
-       cmd = exec.Command(testenv.GoToolPath(t), "tool", "link", "main.o")
+       cmd = exec.Command(testenv.GoToolPath(t), "tool", "link", "-importcfg="+importcfgfile, "main.o")
        cmd.Dir = tmpdir
        out, err = cmd.CombinedOutput()
        if err != nil {
@@ -98,9 +101,12 @@ func TestIssue28429(t *testing.T) {
                }
        }
 
+       importcfgfile := filepath.Join(tmpdir, "importcfg")
+       testenv.WriteImportcfg(t, importcfgfile, nil)
+
        // Compile a main package.
        write("main.go", "package main; func main() {}")
-       runGo("tool", "compile", "-p=main", "main.go")
+       runGo("tool", "compile", "-importcfg="+importcfgfile, "-p=main", "main.go")
        runGo("tool", "pack", "c", "main.a", "main.o")
 
        // Add an extra section with a short, non-.o name.
@@ -110,7 +116,7 @@ func TestIssue28429(t *testing.T) {
 
        // Verify that the linker does not attempt
        // to compile the extra section.
-       runGo("tool", "link", "main.a")
+       runGo("tool", "link", "-importcfg="+importcfgfile, "main.a")
 }
 
 func TestUnresolved(t *testing.T) {
@@ -236,15 +242,18 @@ void foo() {
        cc := strings.TrimSpace(runGo("env", "CC"))
        cflags := strings.Fields(runGo("env", "GOGCCFLAGS"))
 
+       importcfgfile := filepath.Join(tmpdir, "importcfg")
+       testenv.WriteImportcfg(t, importcfgfile, nil)
+
        // Compile, assemble and pack the Go and C code.
        runGo("tool", "asm", "-p=main", "-gensymabis", "-o", "symabis", "x.s")
-       runGo("tool", "compile", "-symabis", "symabis", "-p=main", "-o", "x1.o", "main.go")
+       runGo("tool", "compile", "-importcfg="+importcfgfile, "-symabis", "symabis", "-p=main", "-o", "x1.o", "main.go")
        runGo("tool", "asm", "-p=main", "-o", "x2.o", "x.s")
        run(cc, append(cflags, "-c", "-o", "x3.o", "x.c")...)
        runGo("tool", "pack", "c", "x.a", "x1.o", "x2.o", "x3.o")
 
        // Now attempt to link using the internal linker.
-       cmd := exec.Command(testenv.GoToolPath(t), "tool", "link", "-linkmode=internal", "x.a")
+       cmd := exec.Command(testenv.GoToolPath(t), "tool", "link", "-importcfg="+importcfgfile, "-linkmode=internal", "x.a")
        cmd.Dir = tmpdir
        out, err := cmd.CombinedOutput()
        if err == nil {
@@ -778,20 +787,25 @@ func TestIndexMismatch(t *testing.T) {
        mObj := filepath.Join(tmpdir, "main.o")
        exe := filepath.Join(tmpdir, "main.exe")
 
+       importcfgFile := filepath.Join(tmpdir, "stdlib.importcfg")
+       testenv.WriteImportcfg(t, importcfgFile, nil)
+       importcfgWithAFile := filepath.Join(tmpdir, "witha.importcfg")
+       testenv.WriteImportcfg(t, importcfgWithAFile, map[string]string{"a": aObj})
+
        // Build a program with main package importing package a.
-       cmd := exec.Command(testenv.GoToolPath(t), "tool", "compile", "-p=a", "-o", aObj, aSrc)
+       cmd := exec.Command(testenv.GoToolPath(t), "tool", "compile", "-importcfg="+importcfgFile, "-p=a", "-o", aObj, aSrc)
        t.Log(cmd)
        out, err := cmd.CombinedOutput()
        if err != nil {
                t.Fatalf("compiling a.go failed: %v\n%s", err, out)
        }
-       cmd = exec.Command(testenv.GoToolPath(t), "tool", "compile", "-p=main", "-I", tmpdir, "-o", mObj, mSrc)
+       cmd = exec.Command(testenv.GoToolPath(t), "tool", "compile", "-importcfg="+importcfgWithAFile, "-p=main", "-I", tmpdir, "-o", mObj, mSrc)
        t.Log(cmd)
        out, err = cmd.CombinedOutput()
        if err != nil {
                t.Fatalf("compiling main.go failed: %v\n%s", err, out)
        }
-       cmd = exec.Command(testenv.GoToolPath(t), "tool", "link", "-L", tmpdir, "-o", exe, mObj)
+       cmd = exec.Command(testenv.GoToolPath(t), "tool", "link", "-importcfg="+importcfgWithAFile, "-L", tmpdir, "-o", exe, mObj)
        t.Log(cmd)
        out, err = cmd.CombinedOutput()
        if err != nil {
@@ -800,13 +814,13 @@ func TestIndexMismatch(t *testing.T) {
 
        // Now, overwrite a.o with the object of b.go. This should
        // result in an index mismatch.
-       cmd = exec.Command(testenv.GoToolPath(t), "tool", "compile", "-p=a", "-o", aObj, bSrc)
+       cmd = exec.Command(testenv.GoToolPath(t), "tool", "compile", "-importcfg="+importcfgFile, "-p=a", "-o", aObj, bSrc)
        t.Log(cmd)
        out, err = cmd.CombinedOutput()
        if err != nil {
                t.Fatalf("compiling a.go failed: %v\n%s", err, out)
        }
-       cmd = exec.Command(testenv.GoToolPath(t), "tool", "link", "-L", tmpdir, "-o", exe, mObj)
+       cmd = exec.Command(testenv.GoToolPath(t), "tool", "link", "-importcfg="+importcfgWithAFile, "-L", tmpdir, "-o", exe, mObj)
        t.Log(cmd)
        out, err = cmd.CombinedOutput()
        if err == nil {
index bbf942503a24131ba8cf91fea8399b293ad6ce37..fa6a1b9a68cd8c3cca417ff14f1635e9e1e7b7c7 100644 (file)
@@ -297,8 +297,11 @@ func TestDisasmPIE(t *testing.T) {
 func TestDisasmGoobj(t *testing.T) {
        mustHaveDisasm(t)
 
+       importcfgfile := filepath.Join(tmp, "hello.importcfg")
+       testenv.WriteImportcfg(t, importcfgfile, nil)
+
        hello := filepath.Join(tmp, "hello.o")
-       args := []string{"tool", "compile", "-p=main", "-o", hello}
+       args := []string{"tool", "compile", "-p=main", "-importcfg=" + importcfgfile, "-o", hello}
        args = append(args, "testdata/fmthello.go")
        out, err := exec.Command(testenv.GoToolPath(t), args...).CombinedOutput()
        if err != nil {
index 146c27c00a401161d946083605ddbf027dd93fad..5f16abcb02eb7d89fa750aa223755f557472de65 100644 (file)
@@ -177,11 +177,14 @@ func TestHello(t *testing.T) {
                return doRun(t, dir, args...)
        }
 
+       importcfgfile := filepath.Join(dir, "hello.importcfg")
+       testenv.WriteImportcfg(t, importcfgfile, nil)
+
        goBin := testenv.GoToolPath(t)
        run(goBin, "build", "cmd/pack") // writes pack binary to dir
-       run(goBin, "tool", "compile", "-p=main", "hello.go")
+       run(goBin, "tool", "compile", "-importcfg="+importcfgfile, "-p=main", "hello.go")
        run("./pack", "grc", "hello.a", "hello.o")
-       run(goBin, "tool", "link", "-o", "a.out", "hello.a")
+       run(goBin, "tool", "link", "-importcfg="+importcfgfile, "-o", "a.out", "hello.a")
        out := run("./a.out")
        if out != "hello world\n" {
                t.Fatalf("incorrect output: %q, want %q", out, "hello world\n")
@@ -244,12 +247,16 @@ func TestLargeDefs(t *testing.T) {
                return doRun(t, dir, args...)
        }
 
+       importcfgfile := filepath.Join(dir, "hello.importcfg")
+       testenv.WriteImportcfg(t, importcfgfile, nil)
+
        goBin := testenv.GoToolPath(t)
        run(goBin, "build", "cmd/pack") // writes pack binary to dir
-       run(goBin, "tool", "compile", "-p=large", "large.go")
+       run(goBin, "tool", "compile", "-importcfg="+importcfgfile, "-p=large", "large.go")
        run("./pack", "grc", "large.a", "large.o")
-       run(goBin, "tool", "compile", "-p=main", "-I", ".", "main.go")
-       run(goBin, "tool", "link", "-L", ".", "-o", "a.out", "main.o")
+       testenv.WriteImportcfg(t, importcfgfile, map[string]string{"large": filepath.Join(dir, "large.o")})
+       run(goBin, "tool", "compile", "-importcfg="+importcfgfile, "-p=main", "main.go")
+       run(goBin, "tool", "link", "-importcfg="+importcfgfile, "-L", ".", "-o", "a.out", "main.o")
        out := run("./a.out")
        if out != "ok\n" {
                t.Fatalf("incorrect output: %q, want %q", out, "ok\n")
index eed5c462be20a1c875f949459f577f78bdd7b646..25556ac04c6c55735c42aaa3f9c5b9ec930e6a59 100644 (file)
@@ -535,7 +535,7 @@ var depsRules = `
        internal/fuzz, internal/testlog, runtime/pprof, regexp
        < testing/internal/testdeps;
 
-       OS, flag, testing, internal/cfg, internal/platform
+       OS, flag, testing, internal/cfg, internal/platform, internal/goroot
        < internal/testenv;
 
        OS, encoding/base64
index 1b8353e8fa63af863a63ec8ea200f291c0c2f24e..3c391380383228599cb24ed80f5f9b44da116260 100644 (file)
@@ -25,15 +25,12 @@ func TestForCompiler(t *testing.T) {
        testenv.MustHaveGoBuild(t)
 
        const thePackage = "math/big"
-       out, err := exec.Command(testenv.GoToolPath(t), "list", "-f={{context.Compiler}}:{{.Target}}", thePackage).CombinedOutput()
+       out, err := exec.Command(testenv.GoToolPath(t), "list", "-export", "-f={{context.Compiler}}:{{.Export}}", thePackage).CombinedOutput()
        if err != nil {
                t.Fatalf("go list %s: %v\n%s", thePackage, err, out)
        }
-       target := strings.TrimSpace(string(out))
-       compiler, target, _ := strings.Cut(target, ":")
-       if !strings.HasSuffix(target, ".a") {
-               t.Fatalf("unexpected package %s target %q (not *.a)", thePackage, target)
-       }
+       export := strings.TrimSpace(string(out))
+       compiler, target, _ := strings.Cut(export, ":")
 
        if compiler == "gccgo" {
                t.Skip("golang.org/issue/22500")
index 0b27a954041821d834e4f7082e85e44713d2ec00..0ec464056c0f7bd6eb05e91ab6071275b87b4f88 100644 (file)
@@ -11,9 +11,11 @@ import (
        "go/build"
        "go/token"
        "go/types"
+       "internal/goroot"
        "internal/pkgbits"
        "io"
        "os"
+       "path"
        "path/filepath"
        "strings"
 )
@@ -21,7 +23,25 @@ import (
 // debugging/development support
 const debug = false
 
-var pkgExts = [...]string{".a", ".o"}
+func lookupGorootExport(pkgpath, srcRoot, srcDir string) (string, bool) {
+       pkgpath = filepath.ToSlash(pkgpath)
+       m, err := goroot.PkgfileMap()
+       if err != nil {
+               return "", false
+       }
+       if export, ok := m[pkgpath]; ok {
+               return export, true
+       }
+       vendorPrefix := "vendor"
+       if strings.HasPrefix(srcDir, filepath.Join(srcRoot, "cmd")) {
+               vendorPrefix = path.Join("cmd", vendorPrefix)
+       }
+       pkgpath = path.Join(vendorPrefix, pkgpath)
+       export, ok := m[pkgpath]
+       return export, ok
+}
+
+var pkgExts = [...]string{".a", ".o"} // a file from the build cache will have no extension
 
 // FindPkg returns the filename and unique package id for an import
 // path based on package information provided by build.Import (using
@@ -43,11 +63,18 @@ func FindPkg(path, srcDir string) (filename, id string) {
                }
                bp, _ := build.Import(path, srcDir, build.FindOnly|build.AllowBinary)
                if bp.PkgObj == "" {
-                       id = path // make sure we have an id to print in error message
-                       return
+                       var ok bool
+                       if bp.Goroot {
+                               filename, ok = lookupGorootExport(path, bp.SrcRoot, srcDir)
+                       }
+                       if !ok {
+                               id = path // make sure we have an id to print in error message
+                               return
+                       }
+               } else {
+                       noext = strings.TrimSuffix(bp.PkgObj, ".a")
+                       id = bp.ImportPath
                }
-               noext = strings.TrimSuffix(bp.PkgObj, ".a")
-               id = bp.ImportPath
 
        case build.IsLocalImport(path):
                // "./x" -> "/this/directory/x.ext", "/this/directory/x"
@@ -68,6 +95,11 @@ func FindPkg(path, srcDir string) (filename, id string) {
                }
        }
 
+       if filename != "" {
+               if f, err := os.Stat(filename); err == nil && !f.IsDir() {
+                       return
+               }
+       }
        // try extensions
        for _, ext := range pkgExts {
                filename = noext + ext
index 275287d428a82acfac3f8457713edef4a9f37021..de6a791dc86fab48c42c08cbd10f84d36062c90d 100644 (file)
@@ -11,6 +11,7 @@ import (
        "internal/testenv"
        "os"
        "os/exec"
+       "path"
        "path/filepath"
        "runtime"
        "strings"
@@ -44,14 +45,19 @@ func skipSpecialPlatforms(t *testing.T) {
 
 // compile runs the compiler on filename, with dirname as the working directory,
 // and writes the output file to outdirname.
-func compile(t *testing.T, dirname, filename, outdirname string) string {
+// compile gives the resulting package a packagepath of testdata/<filebasename>.
+func compile(t *testing.T, dirname, filename, outdirname string, packagefiles map[string]string) string {
        // filename must end with ".go"
-       if !strings.HasSuffix(filename, ".go") {
+       basename, ok := strings.CutSuffix(filepath.Base(filename), ".go")
+       if !ok {
                t.Fatalf("filename doesn't end in .go: %s", filename)
        }
-       basename := filepath.Base(filename)
-       outname := filepath.Join(outdirname, basename[:len(basename)-2]+"o")
-       cmd := exec.Command(testenv.GoToolPath(t), "tool", "compile", "-p", strings.TrimSuffix(outname, ".o"), "-o", outname, filename)
+       objname := basename + ".o"
+       outname := filepath.Join(outdirname, objname)
+       importcfgfile := filepath.Join(outdirname, basename) + ".importcfg"
+       testenv.WriteImportcfg(t, importcfgfile, packagefiles)
+       pkgpath := path.Join("testdata", basename)
+       cmd := exec.Command(testenv.GoToolPath(t), "tool", "compile", "-p", pkgpath, "-D", "testdata", "-importcfg", importcfgfile, "-o", outname, filename)
        cmd.Dir = dirname
        out, err := cmd.CombinedOutput()
        if err != nil {
@@ -139,7 +145,7 @@ func TestImportTestdata(t *testing.T) {
                tmpdir := mktmpdir(t)
                defer os.RemoveAll(tmpdir)
 
-               compile(t, "testdata", testfile, filepath.Join(tmpdir, "testdata"))
+               compile(t, "testdata", testfile, filepath.Join(tmpdir, "testdata"), nil)
                path := "./testdata/" + strings.TrimSuffix(testfile, ".go")
 
                if pkg := testPath(t, path, tmpdir); pkg != nil {
@@ -209,7 +215,7 @@ func TestImportTypeparamTests(t *testing.T) {
 
                        // Compile and import, and compare the resulting package with the package
                        // that was type-checked directly.
-                       compile(t, rootDir, entry.Name(), filepath.Join(tmpdir, "testdata"))
+                       compile(t, rootDir, entry.Name(), filepath.Join(tmpdir, "testdata"), nil)
                        pkgName := strings.TrimSuffix(entry.Name(), ".go")
                        imported := importPkg(t, "./testdata/"+pkgName, tmpdir)
                        checked := checkFile(t, filename, src)
@@ -564,8 +570,8 @@ func TestIssue13566(t *testing.T) {
        if err != nil {
                t.Fatal(err)
        }
-       compile(t, "testdata", "a.go", testoutdir)
-       compile(t, testoutdir, bpath, testoutdir)
+       compile(t, "testdata", "a.go", testoutdir, nil)
+       compile(t, testoutdir, bpath, testoutdir, map[string]string{"testdata/a": filepath.Join(testoutdir, "a.o")})
 
        // import must succeed (test for issue at hand)
        pkg := importPkg(t, "./testdata/b", tmpdir)
@@ -596,7 +602,7 @@ func TestTypeNamingOrder(t *testing.T) {
        defer os.RemoveAll(tmpdir)
        testoutdir := filepath.Join(tmpdir, "testdata")
 
-       compile(t, "testdata", "g.go", testoutdir)
+       compile(t, "testdata", "g.go", testoutdir, nil)
 
        // import must succeed (test for issue at hand)
        _ = importPkg(t, "./testdata/g", tmpdir)
@@ -666,7 +672,7 @@ func TestIssue15517(t *testing.T) {
        tmpdir := mktmpdir(t)
        defer os.RemoveAll(tmpdir)
 
-       compile(t, "testdata", "p.go", filepath.Join(tmpdir, "testdata"))
+       compile(t, "testdata", "p.go", filepath.Join(tmpdir, "testdata"), nil)
 
        // Multiple imports of p must succeed without redeclaration errors.
        // We use an import path that's not cleaned up so that the eventual
@@ -773,7 +779,7 @@ func importPkg(t *testing.T, path, srcDir string) *types.Package {
 func compileAndImportPkg(t *testing.T, name string) *types.Package {
        tmpdir := mktmpdir(t)
        defer os.RemoveAll(tmpdir)
-       compile(t, "testdata", name+".go", filepath.Join(tmpdir, "testdata"))
+       compile(t, "testdata", name+".go", filepath.Join(tmpdir, "testdata"), nil)
        return importPkg(t, "./testdata/"+name, tmpdir)
 }
 
index 51d26f69aecae940313b34f900471849cb0f63dd..f0d8dceb3ec9c14b9970afc9389ccd800647d768 100644 (file)
@@ -42,6 +42,9 @@ func TestFuncPCCompileError(t *testing.T) {
        symabi := filepath.Join(tmpdir, "symabi")
        obj := filepath.Join(tmpdir, "x.o")
 
+       importcfgfile := filepath.Join(tmpdir, "hello.importcfg")
+       testenv.WriteImportcfg(t, importcfgfile, nil)
+
        // parse assembly code for symabi.
        cmd := exec.Command(testenv.GoToolPath(t), "tool", "asm", "-gensymabis", "-o", symabi, asmSrc)
        out, err := cmd.CombinedOutput()
@@ -50,7 +53,7 @@ func TestFuncPCCompileError(t *testing.T) {
        }
 
        // compile go code.
-       cmd = exec.Command(testenv.GoToolPath(t), "tool", "compile", "-p=p", "-symabis", symabi, "-o", obj, goSrc)
+       cmd = exec.Command(testenv.GoToolPath(t), "tool", "compile", "-importcfg="+importcfgfile, "-p=p", "-symabis", symabi, "-o", obj, goSrc)
        out, err = cmd.CombinedOutput()
        if err == nil {
                t.Fatalf("go tool compile did not fail")
index 5517598519c18ca1047a4b52b0305b2255cc80b9..79403d29fc02e55c30a929be3eee2478f02e6062 100644 (file)
@@ -69,8 +69,8 @@ func (gd *gccgoDirs) init() {
        const prefix = "libraries: ="
        var dirs []string
        for _, dirEntry := range dirsEntries {
-               if after, found := strings.CutPrefix(dirEntry, prefix); found {
-                       dirs = filepath.SplitList(after)
+               if strings.HasPrefix(dirEntry, prefix) {
+                       dirs = filepath.SplitList(strings.TrimPrefix(dirEntry, prefix))
                        break
                }
        }
diff --git a/src/internal/goroot/importcfg.go b/src/internal/goroot/importcfg.go
new file mode 100644 (file)
index 0000000..51d0d77
--- /dev/null
@@ -0,0 +1,66 @@
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package goroot
+
+import (
+       "bytes"
+       "fmt"
+       "os/exec"
+       "strings"
+       "sync"
+)
+
+// Importcfg returns an importcfg file to be passed to the
+// Go compiler that contains the cached paths for the .a files for the
+// standard library.
+func Importcfg() (string, error) {
+       var icfg bytes.Buffer
+
+       m, err := PkgfileMap()
+       if err != nil {
+               return "", err
+       }
+       fmt.Fprintf(&icfg, "# import config")
+       for importPath, export := range m {
+               if importPath != "unsafe" && export != "" { // unsafe
+                       fmt.Fprintf(&icfg, "\npackagefile %s=%s", importPath, export)
+               }
+       }
+       s := icfg.String()
+       return s, nil
+}
+
+var (
+       stdlibPkgfileMap map[string]string
+       stdlibPkgfileErr error
+       once             sync.Once
+)
+
+// PkgfileMap returns a map of package paths to the location on disk
+// of the .a file for the package.
+// The caller must not modify the map.
+func PkgfileMap() (map[string]string, error) {
+       once.Do(func() {
+               m := make(map[string]string)
+               output, err := exec.Command("go", "list", "-export", "-e", "-f", "{{.ImportPath}} {{.Export}}", "std", "cmd").Output()
+               if err != nil {
+                       stdlibPkgfileErr = err
+               }
+               for _, line := range strings.Split(string(output), "\n") {
+                       if line == "" {
+                               continue
+                       }
+                       sp := strings.SplitN(line, " ", 2)
+                       if len(sp) != 2 {
+                               err = fmt.Errorf("determining pkgfile map: invalid line in go list output: %q", line)
+                               return
+                       }
+                       importPath, export := sp[0], sp[1]
+                       m[importPath] = export
+               }
+               stdlibPkgfileMap = m
+       })
+       return stdlibPkgfileMap, stdlibPkgfileErr
+}
index fe34a92d9c9e6c44b7f58015cedef5ec0785875e..ae8413efb6ad46b5f7c88a4dfa3970f30a79d7fe 100644 (file)
@@ -16,6 +16,7 @@ import (
        "flag"
        "fmt"
        "internal/cfg"
+       "internal/goroot"
        "internal/platform"
        "os"
        "os/exec"
@@ -461,3 +462,20 @@ func RunWithTimeout(t testing.TB, cmd *exec.Cmd) ([]byte, error) {
 
        return b.Bytes(), err
 }
+
+// WriteImportcfg writes an importcfg file used by the compiler or linker to
+// dstPath containing entries for the packages in std and cmd in addition
+// to the package to package file mappings in additionalPackageFiles.
+func WriteImportcfg(t testing.TB, dstPath string, additionalPackageFiles map[string]string) {
+       importcfg, err := goroot.Importcfg()
+       for k, v := range additionalPackageFiles {
+               importcfg += fmt.Sprintf("\npackagefile %s=%s", k, v)
+       }
+       if err != nil {
+               t.Fatalf("preparing the importcfg failed: %s", err)
+       }
+       os.WriteFile(dstPath, []byte(importcfg), 0655)
+       if err != nil {
+               t.Fatalf("writing the importcfg failed: %s", err)
+       }
+}
index 6f671a94c6edc986ae4757faf3d0bf8b20399539..2490ade5c369754bb5a879f8cb21de186027d65c 100644 (file)
@@ -11,6 +11,7 @@ import (
        "go/importer"
        "go/parser"
        "go/token"
+       "internal/testenv"
        "reflect"
        "strings"
        "testing"
@@ -19,6 +20,8 @@ import (
 )
 
 func TestErrorCodeExamples(t *testing.T) {
+       testenv.MustHaveGoBuild(t) // go command needed to resolve std .a files for importer.Default().
+
        walkCodes(t, func(name string, value int, spec *ast.ValueSpec) {
                t.Run(name, func(t *testing.T) {
                        doc := spec.Doc.Text()
index d3bdf007dccf1e18b7cced5cb3f8ef311238f3c4..5f225d63c4c5a9ab5eb14967122a9adfd5d26029 100644 (file)
@@ -12,6 +12,7 @@ import (
        "go/printer"
        "go/token"
        "go/types"
+       "internal/testenv"
        "os"
        "regexp"
        "runtime"
@@ -22,6 +23,8 @@ import (
 // Check that 64-bit fields on which we apply atomic operations
 // are aligned to 8 bytes. This can be a problem on 32-bit systems.
 func TestAtomicAlignment(t *testing.T) {
+       testenv.MustHaveGoBuild(t) // go command needed to resolve std .a files for importer.Default().
+
        // Read the code making the tables above, to see which fields and
        // variables we are currently checking.
        checked := map[string]bool{}