diff options
Diffstat (limited to 'src/cmd/dist/buildtool.go')
-rw-r--r-- | src/cmd/dist/buildtool.go | 325 |
1 files changed, 325 insertions, 0 deletions
diff --git a/src/cmd/dist/buildtool.go b/src/cmd/dist/buildtool.go new file mode 100644 index 0000000..cf85f2a --- /dev/null +++ b/src/cmd/dist/buildtool.go @@ -0,0 +1,325 @@ +// Copyright 2015 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. + +// Build toolchain using Go 1.4. +// +// The general strategy is to copy the source files we need into +// a new GOPATH workspace, adjust import paths appropriately, +// invoke the Go 1.4 go command to build those sources, +// and then copy the binaries back. + +package main + +import ( + "fmt" + "os" + "path/filepath" + "runtime" + "strings" +) + +// bootstrapDirs is a list of directories holding code that must be +// compiled with a Go 1.4 toolchain to produce the bootstrapTargets. +// All directories in this list are relative to and must be below $GOROOT/src. +// +// The list has have two kinds of entries: names beginning with cmd/ with +// no other slashes, which are commands, and other paths, which are packages +// supporting the commands. Packages in the standard library can be listed +// if a newer copy needs to be substituted for the Go 1.4 copy when used +// by the command packages. +// These will be imported during bootstrap as bootstrap/name, like bootstrap/math/big. +var bootstrapDirs = []string{ + "cmd/asm", + "cmd/asm/internal/arch", + "cmd/asm/internal/asm", + "cmd/asm/internal/flags", + "cmd/asm/internal/lex", + "cmd/cgo", + "cmd/compile", + "cmd/compile/internal/amd64", + "cmd/compile/internal/arm", + "cmd/compile/internal/arm64", + "cmd/compile/internal/gc", + "cmd/compile/internal/logopt", + "cmd/compile/internal/mips", + "cmd/compile/internal/mips64", + "cmd/compile/internal/ppc64", + "cmd/compile/internal/riscv64", + "cmd/compile/internal/s390x", + "cmd/compile/internal/ssa", + "cmd/compile/internal/syntax", + "cmd/compile/internal/types", + "cmd/compile/internal/x86", + "cmd/compile/internal/wasm", + "cmd/internal/bio", + "cmd/internal/codesign", + "cmd/internal/gcprog", + "cmd/internal/dwarf", + "cmd/internal/edit", + "cmd/internal/goobj", + "cmd/internal/objabi", + "cmd/internal/obj", + "cmd/internal/obj/arm", + "cmd/internal/obj/arm64", + "cmd/internal/obj/mips", + "cmd/internal/obj/ppc64", + "cmd/internal/obj/riscv", + "cmd/internal/obj/s390x", + "cmd/internal/obj/x86", + "cmd/internal/obj/wasm", + "cmd/internal/pkgpath", + "cmd/internal/src", + "cmd/internal/sys", + "cmd/link", + "cmd/link/internal/amd64", + "cmd/link/internal/arm", + "cmd/link/internal/arm64", + "cmd/link/internal/benchmark", + "cmd/link/internal/ld", + "cmd/link/internal/loadelf", + "cmd/link/internal/loader", + "cmd/link/internal/loadmacho", + "cmd/link/internal/loadpe", + "cmd/link/internal/loadxcoff", + "cmd/link/internal/mips", + "cmd/link/internal/mips64", + "cmd/link/internal/ppc64", + "cmd/link/internal/riscv64", + "cmd/link/internal/s390x", + "cmd/link/internal/sym", + "cmd/link/internal/x86", + "compress/flate", + "compress/zlib", + "cmd/link/internal/wasm", + "container/heap", + "debug/dwarf", + "debug/elf", + "debug/macho", + "debug/pe", + "internal/goversion", + "internal/race", + "internal/unsafeheader", + "internal/xcoff", + "math/big", + "math/bits", + "sort", +} + +// File prefixes that are ignored by go/build anyway, and cause +// problems with editor generated temporary files (#18931). +var ignorePrefixes = []string{ + ".", + "_", +} + +// File suffixes that use build tags introduced since Go 1.4. +// These must not be copied into the bootstrap build directory. +// Also ignore test files. +var ignoreSuffixes = []string{ + "_arm64.s", + "_arm64.go", + "_riscv64.s", + "_riscv64.go", + "_wasm.s", + "_wasm.go", + "_test.s", +} + +func bootstrapBuildTools() { + goroot_bootstrap := os.Getenv("GOROOT_BOOTSTRAP") + if goroot_bootstrap == "" { + goroot_bootstrap = pathf("%s/go1.4", os.Getenv("HOME")) + } + xprintf("Building Go toolchain1 using %s.\n", goroot_bootstrap) + + mkzbootstrap(pathf("%s/src/cmd/internal/objabi/zbootstrap.go", goroot)) + + // Use $GOROOT/pkg/bootstrap as the bootstrap workspace root. + // We use a subdirectory of $GOROOT/pkg because that's the + // space within $GOROOT where we store all generated objects. + // We could use a temporary directory outside $GOROOT instead, + // but it is easier to debug on failure if the files are in a known location. + workspace := pathf("%s/pkg/bootstrap", goroot) + xremoveall(workspace) + xatexit(func() { xremoveall(workspace) }) + base := pathf("%s/src/bootstrap", workspace) + xmkdirall(base) + + // Copy source code into $GOROOT/pkg/bootstrap and rewrite import paths. + writefile("module bootstrap\n", pathf("%s/%s", base, "go.mod"), 0) + for _, dir := range bootstrapDirs { + src := pathf("%s/src/%s", goroot, dir) + dst := pathf("%s/%s", base, dir) + xmkdirall(dst) + if dir == "cmd/cgo" { + // Write to src because we need the file both for bootstrap + // and for later in the main build. + mkzdefaultcc("", pathf("%s/zdefaultcc.go", src)) + } + Dir: + for _, name := range xreaddirfiles(src) { + for _, pre := range ignorePrefixes { + if strings.HasPrefix(name, pre) { + continue Dir + } + } + for _, suf := range ignoreSuffixes { + if strings.HasSuffix(name, suf) { + continue Dir + } + } + srcFile := pathf("%s/%s", src, name) + dstFile := pathf("%s/%s", dst, name) + text := bootstrapRewriteFile(srcFile) + writefile(text, dstFile, 0) + } + } + + // Set up environment for invoking Go 1.4 go command. + // GOROOT points at Go 1.4 GOROOT, + // GOPATH points at our bootstrap workspace, + // GOBIN is empty, so that binaries are installed to GOPATH/bin, + // and GOOS, GOHOSTOS, GOARCH, and GOHOSTOS are empty, + // so that Go 1.4 builds whatever kind of binary it knows how to build. + // Restore GOROOT, GOPATH, and GOBIN when done. + // Don't bother with GOOS, GOHOSTOS, GOARCH, and GOHOSTARCH, + // because setup will take care of those when bootstrapBuildTools returns. + + defer os.Setenv("GOROOT", os.Getenv("GOROOT")) + os.Setenv("GOROOT", goroot_bootstrap) + + defer os.Setenv("GOPATH", os.Getenv("GOPATH")) + os.Setenv("GOPATH", workspace) + + defer os.Setenv("GOBIN", os.Getenv("GOBIN")) + os.Setenv("GOBIN", "") + + os.Setenv("GOOS", "") + os.Setenv("GOHOSTOS", "") + os.Setenv("GOARCH", "") + os.Setenv("GOHOSTARCH", "") + + // Run Go 1.4 to build binaries. Use -gcflags=-l to disable inlining to + // workaround bugs in Go 1.4's compiler. See discussion thread: + // https://groups.google.com/d/msg/golang-dev/Ss7mCKsvk8w/Gsq7VYI0AwAJ + // Use the math_big_pure_go build tag to disable the assembly in math/big + // which may contain unsupported instructions. + // Note that if we are using Go 1.10 or later as bootstrap, the -gcflags=-l + // only applies to the final cmd/go binary, but that's OK: if this is Go 1.10 + // or later we don't need to disable inlining to work around bugs in the Go 1.4 compiler. + cmd := []string{ + pathf("%s/bin/go", goroot_bootstrap), + "install", + "-gcflags=-l", + "-tags=math_big_pure_go compiler_bootstrap", + } + if vflag > 0 { + cmd = append(cmd, "-v") + } + if tool := os.Getenv("GOBOOTSTRAP_TOOLEXEC"); tool != "" { + cmd = append(cmd, "-toolexec="+tool) + } + cmd = append(cmd, "bootstrap/cmd/...") + run(base, ShowOutput|CheckExit, cmd...) + + // Copy binaries into tool binary directory. + for _, name := range bootstrapDirs { + if !strings.HasPrefix(name, "cmd/") { + continue + } + name = name[len("cmd/"):] + if !strings.Contains(name, "/") { + copyfile(pathf("%s/%s%s", tooldir, name, exe), pathf("%s/bin/%s%s", workspace, name, exe), writeExec) + } + } + + if vflag > 0 { + xprintf("\n") + } +} + +var ssaRewriteFileSubstring = filepath.FromSlash("src/cmd/compile/internal/ssa/rewrite") + +// isUnneededSSARewriteFile reports whether srcFile is a +// src/cmd/compile/internal/ssa/rewriteARCHNAME.go file for an +// architecture that isn't for the current runtime.GOARCH. +// +// When unneeded is true archCaps is the rewrite base filename without +// the "rewrite" prefix or ".go" suffix: AMD64, 386, ARM, ARM64, etc. +func isUnneededSSARewriteFile(srcFile string) (archCaps string, unneeded bool) { + if !strings.Contains(srcFile, ssaRewriteFileSubstring) { + return "", false + } + fileArch := strings.TrimSuffix(strings.TrimPrefix(filepath.Base(srcFile), "rewrite"), ".go") + if fileArch == "" { + return "", false + } + b := fileArch[0] + if b == '_' || ('a' <= b && b <= 'z') { + return "", false + } + archCaps = fileArch + fileArch = strings.ToLower(fileArch) + fileArch = strings.TrimSuffix(fileArch, "splitload") + if fileArch == os.Getenv("GOHOSTARCH") { + return "", false + } + if fileArch == strings.TrimSuffix(runtime.GOARCH, "le") { + return "", false + } + if fileArch == strings.TrimSuffix(os.Getenv("GOARCH"), "le") { + return "", false + } + return archCaps, true +} + +func bootstrapRewriteFile(srcFile string) string { + // During bootstrap, generate dummy rewrite files for + // irrelevant architectures. We only need to build a bootstrap + // binary that works for the current runtime.GOARCH. + // This saves 6+ seconds of bootstrap. + if archCaps, ok := isUnneededSSARewriteFile(srcFile); ok { + return fmt.Sprintf(`// Code generated by go tool dist; DO NOT EDIT. + +package ssa + +func rewriteValue%s(v *Value) bool { panic("unused during bootstrap") } +func rewriteBlock%s(b *Block) bool { panic("unused during bootstrap") } +`, archCaps, archCaps) + } + + return bootstrapFixImports(srcFile) +} + +func bootstrapFixImports(srcFile string) string { + lines := strings.SplitAfter(readfile(srcFile), "\n") + inBlock := false + for i, line := range lines { + if strings.HasPrefix(line, "import (") { + inBlock = true + continue + } + if inBlock && strings.HasPrefix(line, ")") { + inBlock = false + continue + } + if strings.HasPrefix(line, `import "`) || strings.HasPrefix(line, `import . "`) || + inBlock && (strings.HasPrefix(line, "\t\"") || strings.HasPrefix(line, "\t. \"") || strings.HasPrefix(line, "\texec \"")) { + line = strings.Replace(line, `"cmd/`, `"bootstrap/cmd/`, -1) + // During bootstrap, must use plain os/exec. + line = strings.Replace(line, `exec "internal/execabs"`, `"os/exec"`, -1) + for _, dir := range bootstrapDirs { + if strings.HasPrefix(dir, "cmd/") { + continue + } + line = strings.Replace(line, `"`+dir+`"`, `"bootstrap/`+dir+`"`, -1) + } + lines[i] = line + } + } + + lines[0] = "// Code generated by go tool dist; DO NOT EDIT.\n// This is a bootstrap copy of " + srcFile + "\n\n//line " + srcFile + ":1\n" + lines[0] + + return strings.Join(lines, "") +} |