buildtool.go 9.18 KB
Newer Older
1
// Copyright 2015 The Go Authors. All rights reserved.
2 3 4 5 6 7 8 9 10 11 12 13 14
// 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 (
15
	"fmt"
16
	"os"
17 18
	"path/filepath"
	"runtime"
19 20 21 22 23
	"strings"
)

// bootstrapDirs is a list of directories holding code that must be
// compiled with a Go 1.4 toolchain to produce the bootstrapTargets.
24 25 26 27 28 29 30 31
// 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.
32
var bootstrapDirs = []string{
33 34 35 36 37
	"cmd/asm",
	"cmd/asm/internal/arch",
	"cmd/asm/internal/asm",
	"cmd/asm/internal/flags",
	"cmd/asm/internal/lex",
38
	"cmd/cgo",
39 40 41 42 43
	"cmd/compile",
	"cmd/compile/internal/amd64",
	"cmd/compile/internal/arm",
	"cmd/compile/internal/arm64",
	"cmd/compile/internal/gc",
44
	"cmd/compile/internal/mips",
45 46
	"cmd/compile/internal/mips64",
	"cmd/compile/internal/ppc64",
47
	"cmd/compile/internal/types",
48 49 50 51
	"cmd/compile/internal/s390x",
	"cmd/compile/internal/ssa",
	"cmd/compile/internal/syntax",
	"cmd/compile/internal/x86",
52
	"cmd/compile/internal/wasm",
53 54 55
	"cmd/internal/bio",
	"cmd/internal/gcprog",
	"cmd/internal/dwarf",
56
	"cmd/internal/edit",
57
	"cmd/internal/objabi",
58 59 60 61 62 63 64
	"cmd/internal/obj",
	"cmd/internal/obj/arm",
	"cmd/internal/obj/arm64",
	"cmd/internal/obj/mips",
	"cmd/internal/obj/ppc64",
	"cmd/internal/obj/s390x",
	"cmd/internal/obj/x86",
65
	"cmd/internal/obj/wasm",
66
	"cmd/internal/src",
67
	"cmd/internal/sys",
68
	"cmd/internal/xcoff",
69 70 71 72 73
	"cmd/link",
	"cmd/link/internal/amd64",
	"cmd/link/internal/arm",
	"cmd/link/internal/arm64",
	"cmd/link/internal/ld",
74
	"cmd/link/internal/loadelf",
75 76
	"cmd/link/internal/loadmacho",
	"cmd/link/internal/loadpe",
77
	"cmd/link/internal/mips",
78
	"cmd/link/internal/mips64",
79
	"cmd/link/internal/objfile",
80 81
	"cmd/link/internal/ppc64",
	"cmd/link/internal/s390x",
82
	"cmd/link/internal/sym",
83
	"cmd/link/internal/x86",
84 85
	"compress/flate",
	"compress/zlib",
86
	"cmd/link/internal/wasm",
87
	"container/heap",
88 89 90
	"debug/dwarf",
	"debug/elf",
	"debug/macho",
91
	"debug/pe",
92
	"math/big",
93
	"math/bits",
94
	"sort",
95 96
}

97 98 99 100 101 102 103
// File prefixes that are ignored by go/build anyway, and cause
// problems with editor generated temporary files (#18931).
var ignorePrefixes = []string{
	".",
	"_",
}

104 105 106 107 108
// 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",
109 110
	"_wasm.s",
	"_wasm.go",
111 112 113 114 115 116 117
}

func bootstrapBuildTools() {
	goroot_bootstrap := os.Getenv("GOROOT_BOOTSTRAP")
	if goroot_bootstrap == "" {
		goroot_bootstrap = pathf("%s/go1.4", os.Getenv("HOME"))
	}
118
	xprintf("Building Go toolchain1 using %s.\n", goroot_bootstrap)
119

120
	mkzbootstrap(pathf("%s/src/cmd/internal/objabi/zbootstrap.go", goroot))
121

122 123 124 125 126 127 128 129 130 131 132 133
	// 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)
	base := pathf("%s/src/bootstrap", workspace)
	xmkdirall(base)

	// Copy source code into $GOROOT/pkg/bootstrap and rewrite import paths.
	for _, dir := range bootstrapDirs {
134
		src := pathf("%s/src/%s", goroot, dir)
135 136
		dst := pathf("%s/%s", base, dir)
		xmkdirall(dst)
137 138 139 140 141
		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))
		}
142
	Dir:
143
		for _, name := range xreaddirfiles(src) {
144 145 146 147 148
			for _, pre := range ignorePrefixes {
				if strings.HasPrefix(name, pre) {
					continue Dir
				}
			}
149 150 151 152 153
			for _, suf := range ignoreSuffixes {
				if strings.HasSuffix(name, suf) {
					continue Dir
				}
			}
154
			srcFile := pathf("%s/%s", src, name)
155
			dstFile := pathf("%s/%s", dst, name)
156
			text := bootstrapRewriteFile(srcFile)
157
			writefile(text, dstFile, 0)
158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184
		}
	}

	// 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", "")

185 186 187
	// 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
188 189
	// Use the math_big_pure_go build tag to disable the assembly in math/big
	// which may contain unsupported instructions.
190 191 192
	// 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.
193 194 195 196
	cmd := []string{
		pathf("%s/bin/go", goroot_bootstrap),
		"install",
		"-gcflags=-l",
197
		"-tags=math_big_pure_go compiler_bootstrap",
198 199 200
	}
	if vflag > 0 {
		cmd = append(cmd, "-v")
201 202 203 204 205 206
	}
	if tool := os.Getenv("GOBOOTSTRAP_TOOLEXEC"); tool != "" {
		cmd = append(cmd, "-toolexec="+tool)
	}
	cmd = append(cmd, "bootstrap/cmd/...")
	run(workspace, ShowOutput|CheckExit, cmd...)
207 208 209

	// Copy binaries into tool binary directory.
	for _, name := range bootstrapDirs {
210 211 212 213
		if !strings.HasPrefix(name, "cmd/") {
			continue
		}
		name = name[len("cmd/"):]
214
		if !strings.Contains(name, "/") {
215
			copyfile(pathf("%s/%s%s", tooldir, name, exe), pathf("%s/bin/%s%s", workspace, name, exe), writeExec)
216 217 218
		}
	}

219 220 221
	if vflag > 0 {
		xprintf("\n")
	}
222 223
}

224
var ssaRewriteFileSubstring = filepath.FromSlash("src/cmd/compile/internal/ssa/rewrite")
225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254

// 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)
	if fileArch == strings.TrimSuffix(runtime.GOARCH, "le") {
		return "", false
	}
	if fileArch == strings.TrimSuffix(os.Getenv("GOARCH"), "le") {
		return "", false
	}
	return archCaps, true
}

255
func bootstrapRewriteFile(srcFile string) string {
256 257 258 259 260
	// 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 {
261 262 263
		return fmt.Sprintf(`// Code generated by go tool dist; DO NOT EDIT.

package ssa
264 265 266 267 268 269

func rewriteValue%s(v *Value) bool { panic("unused during bootstrap") }
func rewriteBlock%s(b *Block) bool { panic("unused during bootstrap") }
`, archCaps, archCaps)
	}

270
	return bootstrapFixImports(srcFile)
271 272
}

273 274
func bootstrapFixImports(srcFile string) string {
	lines := strings.SplitAfter(readfile(srcFile), "\n")
275 276 277 278 279 280 281 282 283 284
	inBlock := false
	for i, line := range lines {
		if strings.HasPrefix(line, "import (") {
			inBlock = true
			continue
		}
		if inBlock && strings.HasPrefix(line, ")") {
			inBlock = false
			continue
		}
285
		if strings.HasPrefix(line, `import "`) || strings.HasPrefix(line, `import . "`) ||
286
			inBlock && (strings.HasPrefix(line, "\t\"") || strings.HasPrefix(line, "\t. \"")) {
287 288 289 290 291 292 293 294
			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
295 296 297
		}
	}

298
	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]
299 300 301

	return strings.Join(lines, "")
}