github.com/dannin/go@v0.0.0-20161031215817-d35dfd405eaa/src/cmd/dist/buildtool.go (about)

     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  	"os"
    16  	"strings"
    17  )
    18  
    19  // bootstrapDirs is a list of directories holding code that must be
    20  // compiled with a Go 1.4 toolchain to produce the bootstrapTargets.
    21  // All directories in this list are relative to and must be below $GOROOT/src.
    22  //
    23  // The list has have two kinds of entries: names beginning with cmd/ with
    24  // no other slashes, which are commands, and other paths, which are packages
    25  // supporting the commands. Packages in the standard library can be listed
    26  // if a newer copy needs to be substituted for the Go 1.4 copy when used
    27  // by the command packages.
    28  // These will be imported during bootstrap as bootstrap/name, like bootstrap/math/big.
    29  var bootstrapDirs = []string{
    30  	"cmd/asm",
    31  	"cmd/asm/internal/arch",
    32  	"cmd/asm/internal/asm",
    33  	"cmd/asm/internal/flags",
    34  	"cmd/asm/internal/lex",
    35  	"cmd/compile",
    36  	"cmd/compile/internal/amd64",
    37  	"cmd/compile/internal/arm",
    38  	"cmd/compile/internal/arm64",
    39  	"cmd/compile/internal/gc",
    40  	"cmd/compile/internal/mips64",
    41  	"cmd/compile/internal/ppc64",
    42  	"cmd/compile/internal/s390x",
    43  	"cmd/compile/internal/ssa",
    44  	"cmd/compile/internal/syntax",
    45  	"cmd/compile/internal/x86",
    46  	"cmd/internal/bio",
    47  	"cmd/internal/gcprog",
    48  	"cmd/internal/dwarf",
    49  	"cmd/internal/obj",
    50  	"cmd/internal/obj/arm",
    51  	"cmd/internal/obj/arm64",
    52  	"cmd/internal/obj/mips",
    53  	"cmd/internal/obj/ppc64",
    54  	"cmd/internal/obj/s390x",
    55  	"cmd/internal/obj/x86",
    56  	"cmd/internal/sys",
    57  	"cmd/link",
    58  	"cmd/link/internal/amd64",
    59  	"cmd/link/internal/arm",
    60  	"cmd/link/internal/arm64",
    61  	"cmd/link/internal/ld",
    62  	"cmd/link/internal/mips64",
    63  	"cmd/link/internal/ppc64",
    64  	"cmd/link/internal/s390x",
    65  	"cmd/link/internal/x86",
    66  	"debug/pe",
    67  	"math/big",
    68  }
    69  
    70  // File suffixes that use build tags introduced since Go 1.4.
    71  // These must not be copied into the bootstrap build directory.
    72  var ignoreSuffixes = []string{
    73  	"_arm64.s",
    74  	"_arm64.go",
    75  }
    76  
    77  func bootstrapBuildTools() {
    78  	goroot_bootstrap := os.Getenv("GOROOT_BOOTSTRAP")
    79  	if goroot_bootstrap == "" {
    80  		goroot_bootstrap = pathf("%s/go1.4", os.Getenv("HOME"))
    81  	}
    82  	xprintf("##### Building Go toolchain using %s.\n", goroot_bootstrap)
    83  
    84  	mkzbootstrap(pathf("%s/src/cmd/internal/obj/zbootstrap.go", goroot))
    85  
    86  	// Use $GOROOT/pkg/bootstrap as the bootstrap workspace root.
    87  	// We use a subdirectory of $GOROOT/pkg because that's the
    88  	// space within $GOROOT where we store all generated objects.
    89  	// We could use a temporary directory outside $GOROOT instead,
    90  	// but it is easier to debug on failure if the files are in a known location.
    91  	workspace := pathf("%s/pkg/bootstrap", goroot)
    92  	xremoveall(workspace)
    93  	base := pathf("%s/src/bootstrap", workspace)
    94  	xmkdirall(base)
    95  
    96  	// Copy source code into $GOROOT/pkg/bootstrap and rewrite import paths.
    97  	for _, dir := range bootstrapDirs {
    98  		src := pathf("%s/src/%s", goroot, dir)
    99  		dst := pathf("%s/%s", base, dir)
   100  		xmkdirall(dst)
   101  	Dir:
   102  		for _, name := range xreaddirfiles(src) {
   103  			for _, suf := range ignoreSuffixes {
   104  				if strings.HasSuffix(name, suf) {
   105  					continue Dir
   106  				}
   107  			}
   108  			srcFile := pathf("%s/%s", src, name)
   109  			text := readfile(srcFile)
   110  			text = bootstrapFixImports(text, srcFile)
   111  			writefile(text, pathf("%s/%s", dst, name), 0)
   112  		}
   113  	}
   114  
   115  	// Set up environment for invoking Go 1.4 go command.
   116  	// GOROOT points at Go 1.4 GOROOT,
   117  	// GOPATH points at our bootstrap workspace,
   118  	// GOBIN is empty, so that binaries are installed to GOPATH/bin,
   119  	// and GOOS, GOHOSTOS, GOARCH, and GOHOSTOS are empty,
   120  	// so that Go 1.4 builds whatever kind of binary it knows how to build.
   121  	// Restore GOROOT, GOPATH, and GOBIN when done.
   122  	// Don't bother with GOOS, GOHOSTOS, GOARCH, and GOHOSTARCH,
   123  	// because setup will take care of those when bootstrapBuildTools returns.
   124  
   125  	defer os.Setenv("GOROOT", os.Getenv("GOROOT"))
   126  	os.Setenv("GOROOT", goroot_bootstrap)
   127  
   128  	defer os.Setenv("GOPATH", os.Getenv("GOPATH"))
   129  	os.Setenv("GOPATH", workspace)
   130  
   131  	defer os.Setenv("GOBIN", os.Getenv("GOBIN"))
   132  	os.Setenv("GOBIN", "")
   133  
   134  	os.Setenv("GOOS", "")
   135  	os.Setenv("GOHOSTOS", "")
   136  	os.Setenv("GOARCH", "")
   137  	os.Setenv("GOHOSTARCH", "")
   138  
   139  	// Run Go 1.4 to build binaries. Use -gcflags=-l to disable inlining to
   140  	// workaround bugs in Go 1.4's compiler. See discussion thread:
   141  	// https://groups.google.com/d/msg/golang-dev/Ss7mCKsvk8w/Gsq7VYI0AwAJ
   142  	// Use the math_big_pure_go build tag to disable the assembly in math/big
   143  	// which may contain unsupported instructions.
   144  	run(workspace, ShowOutput|CheckExit, pathf("%s/bin/go", goroot_bootstrap), "install", "-gcflags=-l", "-tags=math_big_pure_go", "-v", "bootstrap/cmd/...")
   145  
   146  	// Copy binaries into tool binary directory.
   147  	for _, name := range bootstrapDirs {
   148  		if !strings.HasPrefix(name, "cmd/") {
   149  			continue
   150  		}
   151  		name = name[len("cmd/"):]
   152  		if !strings.Contains(name, "/") {
   153  			copyfile(pathf("%s/%s%s", tooldir, name, exe), pathf("%s/bin/%s%s", workspace, name, exe), writeExec)
   154  		}
   155  	}
   156  
   157  	xprintf("\n")
   158  }
   159  
   160  func bootstrapFixImports(text, srcFile string) string {
   161  	lines := strings.SplitAfter(text, "\n")
   162  	inBlock := false
   163  	for i, line := range lines {
   164  		if strings.HasPrefix(line, "import (") {
   165  			inBlock = true
   166  			continue
   167  		}
   168  		if inBlock && strings.HasPrefix(line, ")") {
   169  			inBlock = false
   170  			continue
   171  		}
   172  		if strings.HasPrefix(line, `import "`) || strings.HasPrefix(line, `import . "`) ||
   173  			inBlock && (strings.HasPrefix(line, "\t\"") || strings.HasPrefix(line, "\t. \"")) {
   174  			line = strings.Replace(line, `"cmd/`, `"bootstrap/cmd/`, -1)
   175  			for _, dir := range bootstrapDirs {
   176  				if strings.HasPrefix(dir, "cmd/") {
   177  					continue
   178  				}
   179  				line = strings.Replace(line, `"`+dir+`"`, `"bootstrap/`+dir+`"`, -1)
   180  			}
   181  			lines[i] = line
   182  		}
   183  	}
   184  
   185  	lines[0] = "// Do not edit. Bootstrap copy of " + srcFile + "\n\n//line " + srcFile + ":1\n" + lines[0]
   186  
   187  	return strings.Join(lines, "")
   188  }