1 // Copyright 2015 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
5 // Build toolchain using Go 1.4.
7 // The general strategy is to copy the source files we need into
8 // a new GOPATH workspace, adjust import paths appropriately,
9 // invoke the Go 1.4 go command to build those sources,
10 // and then copy the binaries back.
23 // bootstrapDirs is a list of directories holding code that must be
24 // compiled with a Go 1.4 toolchain to produce the bootstrapTargets.
25 // All directories in this list are relative to and must be below $GOROOT/src.
27 // The list has two kinds of entries: names beginning with cmd/ with
28 // no other slashes, which are commands, and other paths, which are packages
29 // supporting the commands. Packages in the standard library can be listed
30 // if a newer copy needs to be substituted for the Go 1.4 copy when used
31 // by the command packages. Paths ending with /... automatically
32 // include all packages within subdirectories as well.
33 // These will be imported during bootstrap as bootstrap/name, like bootstrap/math/big.
34 var bootstrapDirs = []string{
36 "cmd/asm/internal/...",
39 "cmd/compile/internal/...",
40 "cmd/internal/archive",
42 "cmd/internal/codesign",
45 "cmd/internal/gcprog",
47 "cmd/internal/obj/...",
48 "cmd/internal/objabi",
49 "cmd/internal/pkgpath",
50 "cmd/internal/quoted",
54 "cmd/link/internal/...",
64 "internal/goexperiment",
67 "internal/unsafeheader",
75 // File prefixes that are ignored by go/build anyway, and cause
76 // problems with editor generated temporary files (#18931).
77 var ignorePrefixes = []string{
83 // File suffixes that use build tags introduced since Go 1.4.
84 // These must not be copied into the bootstrap build directory.
85 // Also ignore test files.
86 var ignoreSuffixes = []string{
97 var tryDirs = []string{
102 func bootstrapBuildTools() {
103 goroot_bootstrap := os.Getenv("GOROOT_BOOTSTRAP")
104 if goroot_bootstrap == "" {
105 home := os.Getenv("HOME")
106 goroot_bootstrap = pathf("%s/go1.4", home)
107 for _, d := range tryDirs {
108 if p := pathf("%s/%s", home, d); isdir(p) {
113 xprintf("Building Go toolchain1 using %s.\n", goroot_bootstrap)
115 mkbuildcfg(pathf("%s/src/internal/buildcfg/zbootstrap.go", goroot))
116 mkobjabi(pathf("%s/src/cmd/internal/objabi/zbootstrap.go", goroot))
118 // Use $GOROOT/pkg/bootstrap as the bootstrap workspace root.
119 // We use a subdirectory of $GOROOT/pkg because that's the
120 // space within $GOROOT where we store all generated objects.
121 // We could use a temporary directory outside $GOROOT instead,
122 // but it is easier to debug on failure if the files are in a known location.
123 workspace := pathf("%s/pkg/bootstrap", goroot)
124 xremoveall(workspace)
125 xatexit(func() { xremoveall(workspace) })
126 base := pathf("%s/src/bootstrap", workspace)
129 // Copy source code into $GOROOT/pkg/bootstrap and rewrite import paths.
130 writefile("module bootstrap\n", pathf("%s/%s", base, "go.mod"), 0)
131 for _, dir := range bootstrapDirs {
132 recurse := strings.HasSuffix(dir, "/...")
133 dir = strings.TrimSuffix(dir, "/...")
134 filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
136 fatalf("walking bootstrap dirs failed: %v: %v", path, err)
139 name := filepath.Base(path)
140 src := pathf("%s/src/%s", goroot, path)
141 dst := pathf("%s/%s", base, path)
144 if !recurse && path != dir || name == "testdata" {
145 return filepath.SkipDir
149 if path == "cmd/cgo" {
150 // Write to src because we need the file both for bootstrap
151 // and for later in the main build.
152 mkzdefaultcc("", pathf("%s/zdefaultcc.go", src))
153 mkzdefaultcc("", pathf("%s/zdefaultcc.go", dst))
158 for _, pre := range ignorePrefixes {
159 if strings.HasPrefix(name, pre) {
163 for _, suf := range ignoreSuffixes {
164 if strings.HasSuffix(name, suf) {
169 text := bootstrapRewriteFile(src)
170 writefile(text, dst, 0)
175 // Set up environment for invoking Go 1.4 go command.
176 // GOROOT points at Go 1.4 GOROOT,
177 // GOPATH points at our bootstrap workspace,
178 // GOBIN is empty, so that binaries are installed to GOPATH/bin,
179 // and GOOS, GOHOSTOS, GOARCH, and GOHOSTOS are empty,
180 // so that Go 1.4 builds whatever kind of binary it knows how to build.
181 // Restore GOROOT, GOPATH, and GOBIN when done.
182 // Don't bother with GOOS, GOHOSTOS, GOARCH, and GOHOSTARCH,
183 // because setup will take care of those when bootstrapBuildTools returns.
185 defer os.Setenv("GOROOT", os.Getenv("GOROOT"))
186 os.Setenv("GOROOT", goroot_bootstrap)
188 defer os.Setenv("GOPATH", os.Getenv("GOPATH"))
189 os.Setenv("GOPATH", workspace)
191 defer os.Setenv("GOBIN", os.Getenv("GOBIN"))
192 os.Setenv("GOBIN", "")
194 os.Setenv("GOOS", "")
195 os.Setenv("GOHOSTOS", "")
196 os.Setenv("GOARCH", "")
197 os.Setenv("GOHOSTARCH", "")
199 // Run Go 1.4 to build binaries. Use -gcflags=-l to disable inlining to
200 // workaround bugs in Go 1.4's compiler. See discussion thread:
201 // https://groups.google.com/d/msg/golang-dev/Ss7mCKsvk8w/Gsq7VYI0AwAJ
202 // Use the math_big_pure_go build tag to disable the assembly in math/big
203 // which may contain unsupported instructions.
204 // Note that if we are using Go 1.10 or later as bootstrap, the -gcflags=-l
205 // only applies to the final cmd/go binary, but that's OK: if this is Go 1.10
206 // or later we don't need to disable inlining to work around bugs in the Go 1.4 compiler.
208 pathf("%s/bin/go", goroot_bootstrap),
211 "-tags=math_big_pure_go compiler_bootstrap",
214 cmd = append(cmd, "-v")
216 if tool := os.Getenv("GOBOOTSTRAP_TOOLEXEC"); tool != "" {
217 cmd = append(cmd, "-toolexec="+tool)
219 cmd = append(cmd, "bootstrap/cmd/...")
220 run(base, ShowOutput|CheckExit, cmd...)
222 // Copy binaries into tool binary directory.
223 for _, name := range bootstrapDirs {
224 if !strings.HasPrefix(name, "cmd/") {
227 name = name[len("cmd/"):]
228 if !strings.Contains(name, "/") {
229 copyfile(pathf("%s/%s%s", tooldir, name, exe), pathf("%s/bin/%s%s", workspace, name, exe), writeExec)
238 var ssaRewriteFileSubstring = filepath.FromSlash("src/cmd/compile/internal/ssa/rewrite")
240 // isUnneededSSARewriteFile reports whether srcFile is a
241 // src/cmd/compile/internal/ssa/rewriteARCHNAME.go file for an
242 // architecture that isn't for the current runtime.GOARCH.
244 // When unneeded is true archCaps is the rewrite base filename without
245 // the "rewrite" prefix or ".go" suffix: AMD64, 386, ARM, ARM64, etc.
246 func isUnneededSSARewriteFile(srcFile string) (archCaps string, unneeded bool) {
247 if !strings.Contains(srcFile, ssaRewriteFileSubstring) {
250 fileArch := strings.TrimSuffix(strings.TrimPrefix(filepath.Base(srcFile), "rewrite"), ".go")
255 if b == '_' || ('a' <= b && b <= 'z') {
259 fileArch = strings.ToLower(fileArch)
260 fileArch = strings.TrimSuffix(fileArch, "splitload")
261 if fileArch == os.Getenv("GOHOSTARCH") {
264 if fileArch == strings.TrimSuffix(runtime.GOARCH, "le") {
267 if fileArch == strings.TrimSuffix(os.Getenv("GOARCH"), "le") {
270 return archCaps, true
273 func bootstrapRewriteFile(srcFile string) string {
274 // During bootstrap, generate dummy rewrite files for
275 // irrelevant architectures. We only need to build a bootstrap
276 // binary that works for the current runtime.GOARCH.
277 // This saves 6+ seconds of bootstrap.
278 if archCaps, ok := isUnneededSSARewriteFile(srcFile); ok {
279 return fmt.Sprintf(`// Code generated by go tool dist; DO NOT EDIT.
283 func rewriteValue%s(v *Value) bool { panic("unused during bootstrap") }
284 func rewriteBlock%s(b *Block) bool { panic("unused during bootstrap") }
285 `, archCaps, archCaps)
288 return bootstrapFixImports(srcFile)
291 func bootstrapFixImports(srcFile string) string {
292 text := readfile(srcFile)
293 if !strings.Contains(srcFile, "/cmd/") && !strings.Contains(srcFile, `\cmd\`) {
294 text = regexp.MustCompile(`\bany\b`).ReplaceAllString(text, "interface{}")
296 lines := strings.SplitAfter(text, "\n")
298 for i, line := range lines {
299 if strings.HasPrefix(line, "import (") {
303 if inBlock && strings.HasPrefix(line, ")") {
307 if strings.HasPrefix(line, `import "`) || strings.HasPrefix(line, `import . "`) ||
308 inBlock && (strings.HasPrefix(line, "\t\"") || strings.HasPrefix(line, "\t. \"") || strings.HasPrefix(line, "\texec \"")) {
309 line = strings.Replace(line, `"cmd/`, `"bootstrap/cmd/`, -1)
310 // During bootstrap, must use plain os/exec.
311 line = strings.Replace(line, `exec "internal/execabs"`, `"os/exec"`, -1)
312 for _, dir := range bootstrapDirs {
313 if strings.HasPrefix(dir, "cmd/") {
316 line = strings.Replace(line, `"`+dir+`"`, `"bootstrap/`+dir+`"`, -1)
322 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]
324 return strings.Join(lines, "")