cmd/compilebench: make it work without installed .a's

Currently compilebench relies on installed .a files for std and
cmd, as it runs the compiler and linker directly. For the upcoming
Go 1.20, compiled .a files will not be installed. Don't rely on
them. Instead, build importcfg file and pass it to the compiler
and the linker.

Verified that this approach still works with previous versions of
Go (1.19 and 1.18).

For golang/go#47257.

Change-Id: Ie0eb9541fb995649e5b68d4481a5acfbdfe8f2a7
Reviewed-on: https://go-review.googlesource.com/c/tools/+/448118
Reviewed-by: Michael Pratt <mpratt@google.com>
gopls-CI: kokoro <noreply+kokoro@google.com>
Reviewed-by: Michael Matloob <matloob@golang.org>
Reviewed-by: Than McIntosh <thanm@google.com>
Run-TryBot: Cherry Mui <cherryyz@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
This commit is contained in:
Cherry Mui 2022-11-04 19:53:19 -04:00
parent 502c634771
commit d56532ab0e
1 changed files with 71 additions and 6 deletions

View File

@ -335,10 +335,10 @@ type compile struct{ dir string }
func (compile) long() bool { return false }
func (c compile) run(name string, count int) error {
// Make sure dependencies needed by go tool compile are installed to GOROOT/pkg.
out, err := exec.Command(*flagGoCmd, "build", "-a", c.dir).CombinedOutput()
// Make sure dependencies needed by go tool compile are built.
out, err := exec.Command(*flagGoCmd, "build", c.dir).CombinedOutput()
if err != nil {
return fmt.Errorf("go build -a %s: %v\n%s", c.dir, err, out)
return fmt.Errorf("go build %s: %v\n%s", c.dir, err, out)
}
// Find dir and source file list.
@ -347,6 +347,11 @@ func (c compile) run(name string, count int) error {
return err
}
importcfg, err := genImportcfgFile(c.dir, false)
if err != nil {
return err
}
// If this package has assembly files, we'll need to pass a symabis
// file to the compiler; call a helper to invoke the assembler
// to do that.
@ -371,6 +376,10 @@ func (c compile) run(name string, count int) error {
if symAbisFile != "" {
args = append(args, "-symabis", symAbisFile)
}
if importcfg != "" {
args = append(args, "-importcfg", importcfg)
defer os.Remove(importcfg)
}
args = append(args, pkg.GoFiles...)
if err := runBuildCmd(name, count, pkg.Dir, compiler, args); err != nil {
return err
@ -406,18 +415,28 @@ func (r link) run(name string, count int) error {
}
// Build dependencies.
out, err := exec.Command(*flagGoCmd, "build", "-a", "-o", "/dev/null", r.dir).CombinedOutput()
out, err := exec.Command(*flagGoCmd, "build", "-o", "/dev/null", r.dir).CombinedOutput()
if err != nil {
return fmt.Errorf("go build -a %s: %v\n%s", r.dir, err, out)
}
importcfg, err := genImportcfgFile(r.dir, true)
if err != nil {
return err
}
defer os.Remove(importcfg)
// Build the main package.
pkg, err := goList(r.dir)
if err != nil {
return err
}
args := []string{"-o", "_compilebench_.o"}
args := []string{"-o", "_compilebench_.o", "-importcfg", importcfg}
args = append(args, pkg.GoFiles...)
if *flagTrace {
fmt.Fprintf(os.Stderr, "running: %s %+v\n",
compiler, args)
}
cmd := exec.Command(compiler, args...)
cmd.Dir = pkg.Dir
cmd.Stdout = os.Stderr
@ -429,7 +448,7 @@ func (r link) run(name string, count int) error {
defer os.Remove(pkg.Dir + "/_compilebench_.o")
// Link the main package.
args = []string{"-o", "_compilebench_.exe"}
args = []string{"-o", "_compilebench_.exe", "-importcfg", importcfg}
args = append(args, strings.Fields(*flagLinkerFlags)...)
args = append(args, strings.Fields(r.flags)...)
args = append(args, "_compilebench_.o")
@ -578,3 +597,49 @@ func genSymAbisFile(pkg *Pkg, symAbisFile, incdir string) error {
}
return nil
}
// genImportcfgFile generates an importcfg file for building package
// dir. Returns the generated importcfg file path (or empty string
// if the package has no dependency).
func genImportcfgFile(dir string, full bool) (string, error) {
need := "{{.Imports}}"
if full {
// for linking, we need transitive dependencies
need = "{{.Deps}}"
}
// find imported/dependent packages
cmd := exec.Command(*flagGoCmd, "list", "-f", need, dir)
cmd.Stderr = os.Stderr
out, err := cmd.Output()
if err != nil {
return "", fmt.Errorf("go list -f %s %s: %v", need, dir, err)
}
// trim [ ]\n
if len(out) < 3 || out[0] != '[' || out[len(out)-2] != ']' || out[len(out)-1] != '\n' {
return "", fmt.Errorf("unexpected output from go list -f %s %s: %s", need, dir, out)
}
out = out[1 : len(out)-2]
if len(out) == 0 {
return "", nil
}
// build importcfg for imported packages
cmd = exec.Command(*flagGoCmd, "list", "-export", "-f", "{{if .Export}}packagefile {{.ImportPath}}={{.Export}}{{end}}")
cmd.Args = append(cmd.Args, strings.Fields(string(out))...)
cmd.Stderr = os.Stderr
out, err = cmd.Output()
if err != nil {
return "", fmt.Errorf("generating importcfg for %s: %s: %v", dir, cmd, err)
}
f, err := os.CreateTemp("", "importcfg")
if err != nil {
return "", fmt.Errorf("creating tmp importcfg file failed: %v", err)
}
defer f.Close()
if _, err := f.Write(out); err != nil {
return "", fmt.Errorf("writing importcfg file %s failed: %v", f.Name(), err)
}
return f.Name(), nil
}