...
Run Format

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

View as plain text