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/cmd. 22 // The list is assumed to have two kinds of entries: names without slashes, 23 // which are commands, and entries beginning with internal/, which are 24 // packages supporting the commands. 25 var bootstrapDirs = []string{ 26 "asm", 27 "asm/internal/arch", 28 "asm/internal/asm", 29 "asm/internal/flags", 30 "asm/internal/lex", 31 "compile", 32 "compile/internal/amd64", 33 "compile/internal/arm", 34 "compile/internal/arm64", 35 "compile/internal/big", 36 "compile/internal/gc", 37 "compile/internal/ppc64", 38 "compile/internal/x86", 39 "internal/gcprog", 40 "internal/obj", 41 "internal/obj/arm", 42 "internal/obj/arm64", 43 "internal/obj/ppc64", 44 "internal/obj/x86", 45 "link", 46 "link/internal/amd64", 47 "link/internal/arm", 48 "link/internal/arm64", 49 "link/internal/ld", 50 "link/internal/ppc64", 51 "link/internal/x86", 52 } 53 54 func bootstrapBuildTools() { 55 goroot_bootstrap := os.Getenv("GOROOT_BOOTSTRAP") 56 if goroot_bootstrap == "" { 57 goroot_bootstrap = pathf("%s/go1.4", os.Getenv("HOME")) 58 } 59 xprintf("##### Building Go toolchain using %s.\n", goroot_bootstrap) 60 61 mkzbootstrap(pathf("%s/src/cmd/internal/obj/zbootstrap.go", goroot)) 62 63 // Use $GOROOT/pkg/bootstrap as the bootstrap workspace root. 64 // We use a subdirectory of $GOROOT/pkg because that's the 65 // space within $GOROOT where we store all generated objects. 66 // We could use a temporary directory outside $GOROOT instead, 67 // but it is easier to debug on failure if the files are in a known location. 68 workspace := pathf("%s/pkg/bootstrap", goroot) 69 xremoveall(workspace) 70 base := pathf("%s/src/bootstrap", workspace) 71 xmkdirall(base) 72 73 // Copy source code into $GOROOT/pkg/bootstrap and rewrite import paths. 74 for _, dir := range bootstrapDirs { 75 src := pathf("%s/src/cmd/%s", goroot, dir) 76 dst := pathf("%s/%s", base, dir) 77 xmkdirall(dst) 78 for _, name := range xreaddirfiles(src) { 79 srcFile := pathf("%s/%s", src, name) 80 text := readfile(srcFile) 81 text = bootstrapFixImports(text, srcFile) 82 writefile(text, pathf("%s/%s", dst, name), 0) 83 } 84 } 85 86 // Set up environment for invoking Go 1.4 go command. 87 // GOROOT points at Go 1.4 GOROOT, 88 // GOPATH points at our bootstrap workspace, 89 // GOBIN is empty, so that binaries are installed to GOPATH/bin, 90 // and GOOS, GOHOSTOS, GOARCH, and GOHOSTOS are empty, 91 // so that Go 1.4 builds whatever kind of binary it knows how to build. 92 // Restore GOROOT, GOPATH, and GOBIN when done. 93 // Don't bother with GOOS, GOHOSTOS, GOARCH, and GOHOSTARCH, 94 // because setup will take care of those when bootstrapBuildTools returns. 95 96 defer os.Setenv("GOROOT", os.Getenv("GOROOT")) 97 os.Setenv("GOROOT", goroot_bootstrap) 98 99 defer os.Setenv("GOPATH", os.Getenv("GOPATH")) 100 os.Setenv("GOPATH", workspace) 101 102 defer os.Setenv("GOBIN", os.Getenv("GOBIN")) 103 os.Setenv("GOBIN", "") 104 105 os.Setenv("GOOS", "") 106 os.Setenv("GOHOSTOS", "") 107 os.Setenv("GOARCH", "") 108 os.Setenv("GOHOSTARCH", "") 109 110 // Run Go 1.4 to build binaries. 111 run(workspace, ShowOutput|CheckExit, pathf("%s/bin/go", goroot_bootstrap), "install", "-v", "bootstrap/...") 112 113 // Copy binaries into tool binary directory. 114 for _, name := range bootstrapDirs { 115 if !strings.Contains(name, "/") { 116 copyfile(pathf("%s/%s%s", tooldir, name, exe), pathf("%s/bin/%s%s", workspace, name, exe), writeExec) 117 } 118 } 119 120 xprintf("\n") 121 } 122 123 func bootstrapFixImports(text, srcFile string) string { 124 lines := strings.SplitAfter(text, "\n") 125 inBlock := false 126 for i, line := range lines { 127 if strings.HasPrefix(line, "import (") { 128 inBlock = true 129 continue 130 } 131 if inBlock && strings.HasPrefix(line, ")") { 132 inBlock = false 133 continue 134 } 135 if strings.HasPrefix(line, `import "`) || strings.HasPrefix(line, `import . "`) || 136 inBlock && (strings.HasPrefix(line, "\t\"") || strings.HasPrefix(line, "\t. \"")) { 137 lines[i] = strings.Replace(line, `"cmd/`, `"bootstrap/`, -1) 138 } 139 } 140 141 lines[0] = "// Do not edit. Bootstrap copy of " + srcFile + "\n\n//line " + srcFile + ":1\n" + lines[0] 142 143 return strings.Join(lines, "") 144 } 145