|  | // 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/gcprog", | 
|  | "cmd/internal/dwarf", | 
|  | "cmd/internal/edit", | 
|  | "cmd/internal/goobj2", | 
|  | "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/src", | 
|  | "cmd/internal/sys", | 
|  | "cmd/link", | 
|  | "cmd/link/internal/amd64", | 
|  | "cmd/link/internal/arm", | 
|  | "cmd/link/internal/arm64", | 
|  | "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/objfile", | 
|  | "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/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. | 
|  | var ignoreSuffixes = []string{ | 
|  | "_arm64.s", | 
|  | "_arm64.go", | 
|  | "_wasm.s", | 
|  | "_wasm.go", | 
|  | } | 
|  |  | 
|  | 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. \"")) { | 
|  | line = strings.Replace(line, `"cmd/`, `"bootstrap/cmd/`, -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, "") | 
|  | } |