Black Lives Matter. Support the Equal Justice Initiative.

Source file src/cmd/dist/buildtool.go

Documentation: cmd/dist

     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.
     4  
     5  // Build toolchain using Go 1.4.
     6  //
     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.
    11  
    12  package main
    13  
    14  import (
    15  	"fmt"
    16  	"os"
    17  	"path/filepath"
    18  	"runtime"
    19  	"strings"
    20  )
    21  
    22  // bootstrapDirs is a list of directories holding code that must be
    23  // compiled with a Go 1.4 toolchain to produce the bootstrapTargets.
    24  // All directories in this list are relative to and must be below $GOROOT/src.
    25  //
    26  // The list has have two kinds of entries: names beginning with cmd/ with
    27  // no other slashes, which are commands, and other paths, which are packages
    28  // supporting the commands. Packages in the standard library can be listed
    29  // if a newer copy needs to be substituted for the Go 1.4 copy when used
    30  // by the command packages.
    31  // These will be imported during bootstrap as bootstrap/name, like bootstrap/math/big.
    32  var bootstrapDirs = []string{
    33  	"cmd/asm",
    34  	"cmd/asm/internal/arch",
    35  	"cmd/asm/internal/asm",
    36  	"cmd/asm/internal/flags",
    37  	"cmd/asm/internal/lex",
    38  	"cmd/cgo",
    39  	"cmd/compile",
    40  	"cmd/compile/internal/amd64",
    41  	"cmd/compile/internal/arm",
    42  	"cmd/compile/internal/arm64",
    43  	"cmd/compile/internal/gc",
    44  	"cmd/compile/internal/logopt",
    45  	"cmd/compile/internal/mips",
    46  	"cmd/compile/internal/mips64",
    47  	"cmd/compile/internal/ppc64",
    48  	"cmd/compile/internal/riscv64",
    49  	"cmd/compile/internal/s390x",
    50  	"cmd/compile/internal/ssa",
    51  	"cmd/compile/internal/syntax",
    52  	"cmd/compile/internal/types",
    53  	"cmd/compile/internal/x86",
    54  	"cmd/compile/internal/wasm",
    55  	"cmd/internal/bio",
    56  	"cmd/internal/gcprog",
    57  	"cmd/internal/dwarf",
    58  	"cmd/internal/edit",
    59  	"cmd/internal/goobj2",
    60  	"cmd/internal/objabi",
    61  	"cmd/internal/obj",
    62  	"cmd/internal/obj/arm",
    63  	"cmd/internal/obj/arm64",
    64  	"cmd/internal/obj/mips",
    65  	"cmd/internal/obj/ppc64",
    66  	"cmd/internal/obj/riscv",
    67  	"cmd/internal/obj/s390x",
    68  	"cmd/internal/obj/x86",
    69  	"cmd/internal/obj/wasm",
    70  	"cmd/internal/src",
    71  	"cmd/internal/sys",
    72  	"cmd/link",
    73  	"cmd/link/internal/amd64",
    74  	"cmd/link/internal/arm",
    75  	"cmd/link/internal/arm64",
    76  	"cmd/link/internal/benchmark",
    77  	"cmd/link/internal/ld",
    78  	"cmd/link/internal/loadelf",
    79  	"cmd/link/internal/loader",
    80  	"cmd/link/internal/loadmacho",
    81  	"cmd/link/internal/loadpe",
    82  	"cmd/link/internal/loadxcoff",
    83  	"cmd/link/internal/mips",
    84  	"cmd/link/internal/mips64",
    85  	"cmd/link/internal/ppc64",
    86  	"cmd/link/internal/riscv64",
    87  	"cmd/link/internal/s390x",
    88  	"cmd/link/internal/sym",
    89  	"cmd/link/internal/x86",
    90  	"compress/flate",
    91  	"compress/zlib",
    92  	"cmd/link/internal/wasm",
    93  	"container/heap",
    94  	"debug/dwarf",
    95  	"debug/elf",
    96  	"debug/macho",
    97  	"debug/pe",
    98  	"internal/goversion",
    99  	"internal/race",
   100  	"internal/unsafeheader",
   101  	"internal/xcoff",
   102  	"math/big",
   103  	"math/bits",
   104  	"sort",
   105  }
   106  
   107  // File prefixes that are ignored by go/build anyway, and cause
   108  // problems with editor generated temporary files (#18931).
   109  var ignorePrefixes = []string{
   110  	".",
   111  	"_",
   112  }
   113  
   114  // File suffixes that use build tags introduced since Go 1.4.
   115  // These must not be copied into the bootstrap build directory.
   116  var ignoreSuffixes = []string{
   117  	"_arm64.s",
   118  	"_arm64_test.s",
   119  	"_arm64.go",
   120  	"_riscv64.s",
   121  	"_riscv64.go",
   122  	"_wasm.s",
   123  	"_wasm.go",
   124  }
   125  
   126  func bootstrapBuildTools() {
   127  	goroot_bootstrap := os.Getenv("GOROOT_BOOTSTRAP")
   128  	if goroot_bootstrap == "" {
   129  		goroot_bootstrap = pathf("%s/go1.4", os.Getenv("HOME"))
   130  	}
   131  	xprintf("Building Go toolchain1 using %s.\n", goroot_bootstrap)
   132  
   133  	mkzbootstrap(pathf("%s/src/cmd/internal/objabi/zbootstrap.go", goroot))
   134  
   135  	// Use $GOROOT/pkg/bootstrap as the bootstrap workspace root.
   136  	// We use a subdirectory of $GOROOT/pkg because that's the
   137  	// space within $GOROOT where we store all generated objects.
   138  	// We could use a temporary directory outside $GOROOT instead,
   139  	// but it is easier to debug on failure if the files are in a known location.
   140  	workspace := pathf("%s/pkg/bootstrap", goroot)
   141  	xremoveall(workspace)
   142  	xatexit(func() { xremoveall(workspace) })
   143  	base := pathf("%s/src/bootstrap", workspace)
   144  	xmkdirall(base)
   145  
   146  	// Copy source code into $GOROOT/pkg/bootstrap and rewrite import paths.
   147  	writefile("module bootstrap\n", pathf("%s/%s", base, "go.mod"), 0)
   148  	for _, dir := range bootstrapDirs {
   149  		src := pathf("%s/src/%s", goroot, dir)
   150  		dst := pathf("%s/%s", base, dir)
   151  		xmkdirall(dst)
   152  		if dir == "cmd/cgo" {
   153  			// Write to src because we need the file both for bootstrap
   154  			// and for later in the main build.
   155  			mkzdefaultcc("", pathf("%s/zdefaultcc.go", src))
   156  		}
   157  	Dir:
   158  		for _, name := range xreaddirfiles(src) {
   159  			for _, pre := range ignorePrefixes {
   160  				if strings.HasPrefix(name, pre) {
   161  					continue Dir
   162  				}
   163  			}
   164  			for _, suf := range ignoreSuffixes {
   165  				if strings.HasSuffix(name, suf) {
   166  					continue Dir
   167  				}
   168  			}
   169  			srcFile := pathf("%s/%s", src, name)
   170  			dstFile := pathf("%s/%s", dst, name)
   171  			text := bootstrapRewriteFile(srcFile)
   172  			writefile(text, dstFile, 0)
   173  		}
   174  	}
   175  
   176  	// Set up environment for invoking Go 1.4 go command.
   177  	// GOROOT points at Go 1.4 GOROOT,
   178  	// GOPATH points at our bootstrap workspace,
   179  	// GOBIN is empty, so that binaries are installed to GOPATH/bin,
   180  	// and GOOS, GOHOSTOS, GOARCH, and GOHOSTOS are empty,
   181  	// so that Go 1.4 builds whatever kind of binary it knows how to build.
   182  	// Restore GOROOT, GOPATH, and GOBIN when done.
   183  	// Don't bother with GOOS, GOHOSTOS, GOARCH, and GOHOSTARCH,
   184  	// because setup will take care of those when bootstrapBuildTools returns.
   185  
   186  	defer os.Setenv("GOROOT", os.Getenv("GOROOT"))
   187  	os.Setenv("GOROOT", goroot_bootstrap)
   188  
   189  	defer os.Setenv("GOPATH", os.Getenv("GOPATH"))
   190  	os.Setenv("GOPATH", workspace)
   191  
   192  	defer os.Setenv("GOBIN", os.Getenv("GOBIN"))
   193  	os.Setenv("GOBIN", "")
   194  
   195  	os.Setenv("GOOS", "")
   196  	os.Setenv("GOHOSTOS", "")
   197  	os.Setenv("GOARCH", "")
   198  	os.Setenv("GOHOSTARCH", "")
   199  
   200  	// Run Go 1.4 to build binaries. Use -gcflags=-l to disable inlining to
   201  	// workaround bugs in Go 1.4's compiler. See discussion thread:
   202  	// https://groups.google.com/d/msg/golang-dev/Ss7mCKsvk8w/Gsq7VYI0AwAJ
   203  	// Use the math_big_pure_go build tag to disable the assembly in math/big
   204  	// which may contain unsupported instructions.
   205  	// Note that if we are using Go 1.10 or later as bootstrap, the -gcflags=-l
   206  	// only applies to the final cmd/go binary, but that's OK: if this is Go 1.10
   207  	// or later we don't need to disable inlining to work around bugs in the Go 1.4 compiler.
   208  	cmd := []string{
   209  		pathf("%s/bin/go", goroot_bootstrap),
   210  		"install",
   211  		"-gcflags=-l",
   212  		"-tags=math_big_pure_go compiler_bootstrap",
   213  	}
   214  	if vflag > 0 {
   215  		cmd = append(cmd, "-v")
   216  	}
   217  	if tool := os.Getenv("GOBOOTSTRAP_TOOLEXEC"); tool != "" {
   218  		cmd = append(cmd, "-toolexec="+tool)
   219  	}
   220  	cmd = append(cmd, "bootstrap/cmd/...")
   221  	run(base, ShowOutput|CheckExit, cmd...)
   222  
   223  	// Copy binaries into tool binary directory.
   224  	for _, name := range bootstrapDirs {
   225  		if !strings.HasPrefix(name, "cmd/") {
   226  			continue
   227  		}
   228  		name = name[len("cmd/"):]
   229  		if !strings.Contains(name, "/") {
   230  			copyfile(pathf("%s/%s%s", tooldir, name, exe), pathf("%s/bin/%s%s", workspace, name, exe), writeExec)
   231  		}
   232  	}
   233  
   234  	if vflag > 0 {
   235  		xprintf("\n")
   236  	}
   237  }
   238  
   239  var ssaRewriteFileSubstring = filepath.FromSlash("src/cmd/compile/internal/ssa/rewrite")
   240  
   241  // isUnneededSSARewriteFile reports whether srcFile is a
   242  // src/cmd/compile/internal/ssa/rewriteARCHNAME.go file for an
   243  // architecture that isn't for the current runtime.GOARCH.
   244  //
   245  // When unneeded is true archCaps is the rewrite base filename without
   246  // the "rewrite" prefix or ".go" suffix: AMD64, 386, ARM, ARM64, etc.
   247  func isUnneededSSARewriteFile(srcFile string) (archCaps string, unneeded bool) {
   248  	if !strings.Contains(srcFile, ssaRewriteFileSubstring) {
   249  		return "", false
   250  	}
   251  	fileArch := strings.TrimSuffix(strings.TrimPrefix(filepath.Base(srcFile), "rewrite"), ".go")
   252  	if fileArch == "" {
   253  		return "", false
   254  	}
   255  	b := fileArch[0]
   256  	if b == '_' || ('a' <= b && b <= 'z') {
   257  		return "", false
   258  	}
   259  	archCaps = fileArch
   260  	fileArch = strings.ToLower(fileArch)
   261  	fileArch = strings.TrimSuffix(fileArch, "splitload")
   262  	if fileArch == os.Getenv("GOHOSTARCH") {
   263  		return "", false
   264  	}
   265  	if fileArch == strings.TrimSuffix(runtime.GOARCH, "le") {
   266  		return "", false
   267  	}
   268  	if fileArch == strings.TrimSuffix(os.Getenv("GOARCH"), "le") {
   269  		return "", false
   270  	}
   271  	return archCaps, true
   272  }
   273  
   274  func bootstrapRewriteFile(srcFile string) string {
   275  	// During bootstrap, generate dummy rewrite files for
   276  	// irrelevant architectures. We only need to build a bootstrap
   277  	// binary that works for the current runtime.GOARCH.
   278  	// This saves 6+ seconds of bootstrap.
   279  	if archCaps, ok := isUnneededSSARewriteFile(srcFile); ok {
   280  		return fmt.Sprintf(`// Code generated by go tool dist; DO NOT EDIT.
   281  
   282  package ssa
   283  
   284  func rewriteValue%s(v *Value) bool { panic("unused during bootstrap") }
   285  func rewriteBlock%s(b *Block) bool { panic("unused during bootstrap") }
   286  `, archCaps, archCaps)
   287  	}
   288  
   289  	return bootstrapFixImports(srcFile)
   290  }
   291  
   292  func bootstrapFixImports(srcFile string) string {
   293  	lines := strings.SplitAfter(readfile(srcFile), "\n")
   294  	inBlock := false
   295  	for i, line := range lines {
   296  		if strings.HasPrefix(line, "import (") {
   297  			inBlock = true
   298  			continue
   299  		}
   300  		if inBlock && strings.HasPrefix(line, ")") {
   301  			inBlock = false
   302  			continue
   303  		}
   304  		if strings.HasPrefix(line, `import "`) || strings.HasPrefix(line, `import . "`) ||
   305  			inBlock && (strings.HasPrefix(line, "\t\"") || strings.HasPrefix(line, "\t. \"")) {
   306  			line = strings.Replace(line, `"cmd/`, `"bootstrap/cmd/`, -1)
   307  			for _, dir := range bootstrapDirs {
   308  				if strings.HasPrefix(dir, "cmd/") {
   309  					continue
   310  				}
   311  				line = strings.Replace(line, `"`+dir+`"`, `"bootstrap/`+dir+`"`, -1)
   312  			}
   313  			lines[i] = line
   314  		}
   315  	}
   316  
   317  	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]
   318  
   319  	return strings.Join(lines, "")
   320  }
   321  

View as plain text