github.com/gagliardetto/golang-go@v0.0.0-20201020153340-53909ea70814/cmd/dist/build.go (about) 1 // Copyright 2012 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 package main 6 7 import ( 8 "bytes" 9 "encoding/json" 10 "flag" 11 "fmt" 12 "io/ioutil" 13 "log" 14 "os" 15 "os/exec" 16 "path/filepath" 17 "sort" 18 "strings" 19 "sync" 20 "time" 21 ) 22 23 // Initialization for any invocation. 24 25 // The usual variables. 26 var ( 27 goarch string 28 gobin string 29 gohostarch string 30 gohostos string 31 goos string 32 goarm string 33 go386 string 34 gomips string 35 gomips64 string 36 goppc64 string 37 goroot string 38 goroot_final string 39 goextlinkenabled string 40 gogcflags string // For running built compiler 41 goldflags string 42 workdir string 43 tooldir string 44 oldgoos string 45 oldgoarch string 46 exe string 47 defaultcc map[string]string 48 defaultcxx map[string]string 49 defaultcflags string 50 defaultldflags string 51 defaultpkgconfig string 52 defaultldso string 53 54 rebuildall bool 55 defaultclang bool 56 57 vflag int // verbosity 58 ) 59 60 // The known architectures. 61 var okgoarch = []string{ 62 "386", 63 "amd64", 64 "arm", 65 "arm64", 66 "mips", 67 "mipsle", 68 "mips64", 69 "mips64le", 70 "ppc64", 71 "ppc64le", 72 "riscv64", 73 "s390x", 74 "sparc64", 75 "wasm", 76 } 77 78 // The known operating systems. 79 var okgoos = []string{ 80 "darwin", 81 "dragonfly", 82 "illumos", 83 "js", 84 "linux", 85 "android", 86 "solaris", 87 "freebsd", 88 "nacl", // keep; 89 "netbsd", 90 "openbsd", 91 "plan9", 92 "windows", 93 "aix", 94 } 95 96 // find reports the first index of p in l[0:n], or else -1. 97 func find(p string, l []string) int { 98 for i, s := range l { 99 if p == s { 100 return i 101 } 102 } 103 return -1 104 } 105 106 // xinit handles initialization of the various global state, like goroot and goarch. 107 func xinit() { 108 b := os.Getenv("GOROOT") 109 if b == "" { 110 fatalf("$GOROOT must be set") 111 } 112 goroot = filepath.Clean(b) 113 if modRoot := findModuleRoot(goroot); modRoot != "" { 114 fatalf("found go.mod file in %s: $GOROOT must not be inside a module", modRoot) 115 } 116 117 b = os.Getenv("GOROOT_FINAL") 118 if b == "" { 119 b = goroot 120 } 121 goroot_final = b 122 123 b = os.Getenv("GOBIN") 124 if b == "" { 125 b = pathf("%s/bin", goroot) 126 } 127 gobin = b 128 129 b = os.Getenv("GOOS") 130 if b == "" { 131 b = gohostos 132 } 133 goos = b 134 if find(goos, okgoos) < 0 { 135 fatalf("unknown $GOOS %s", goos) 136 } 137 138 b = os.Getenv("GOARM") 139 if b == "" { 140 b = xgetgoarm() 141 } 142 goarm = b 143 144 b = os.Getenv("GO386") 145 if b == "" { 146 if cansse2() { 147 b = "sse2" 148 } else { 149 b = "387" 150 } 151 } 152 go386 = b 153 154 b = os.Getenv("GOMIPS") 155 if b == "" { 156 b = "hardfloat" 157 } 158 gomips = b 159 160 b = os.Getenv("GOMIPS64") 161 if b == "" { 162 b = "hardfloat" 163 } 164 gomips64 = b 165 166 b = os.Getenv("GOPPC64") 167 if b == "" { 168 b = "power8" 169 } 170 goppc64 = b 171 172 if p := pathf("%s/src/all.bash", goroot); !isfile(p) { 173 fatalf("$GOROOT is not set correctly or not exported\n"+ 174 "\tGOROOT=%s\n"+ 175 "\t%s does not exist", goroot, p) 176 } 177 178 b = os.Getenv("GOHOSTARCH") 179 if b != "" { 180 gohostarch = b 181 } 182 if find(gohostarch, okgoarch) < 0 { 183 fatalf("unknown $GOHOSTARCH %s", gohostarch) 184 } 185 186 b = os.Getenv("GOARCH") 187 if b == "" { 188 b = gohostarch 189 } 190 goarch = b 191 if find(goarch, okgoarch) < 0 { 192 fatalf("unknown $GOARCH %s", goarch) 193 } 194 195 b = os.Getenv("GO_EXTLINK_ENABLED") 196 if b != "" { 197 if b != "0" && b != "1" { 198 fatalf("unknown $GO_EXTLINK_ENABLED %s", b) 199 } 200 goextlinkenabled = b 201 } 202 203 gogcflags = os.Getenv("BOOT_GO_GCFLAGS") 204 goldflags = os.Getenv("BOOT_GO_LDFLAGS") 205 206 cc, cxx := "gcc", "g++" 207 if defaultclang { 208 cc, cxx = "clang", "clang++" 209 } 210 defaultcc = compilerEnv("CC", cc) 211 defaultcxx = compilerEnv("CXX", cxx) 212 213 defaultcflags = os.Getenv("CFLAGS") 214 defaultldflags = os.Getenv("LDFLAGS") 215 216 b = os.Getenv("PKG_CONFIG") 217 if b == "" { 218 b = "pkg-config" 219 } 220 defaultpkgconfig = b 221 222 defaultldso = os.Getenv("GO_LDSO") 223 224 // For tools being invoked but also for os.ExpandEnv. 225 os.Setenv("GO386", go386) 226 os.Setenv("GOARCH", goarch) 227 os.Setenv("GOARM", goarm) 228 os.Setenv("GOHOSTARCH", gohostarch) 229 os.Setenv("GOHOSTOS", gohostos) 230 os.Setenv("GOOS", goos) 231 os.Setenv("GOMIPS", gomips) 232 os.Setenv("GOMIPS64", gomips64) 233 os.Setenv("GOPPC64", goppc64) 234 os.Setenv("GOROOT", goroot) 235 os.Setenv("GOROOT_FINAL", goroot_final) 236 237 // Use a build cache separate from the default user one. 238 // Also one that will be wiped out during startup, so that 239 // make.bash really does start from a clean slate. 240 os.Setenv("GOCACHE", pathf("%s/pkg/obj/go-build", goroot)) 241 242 // Make the environment more predictable. 243 os.Setenv("LANG", "C") 244 os.Setenv("LANGUAGE", "en_US.UTF8") 245 246 workdir = xworkdir() 247 xatexit(rmworkdir) 248 249 tooldir = pathf("%s/pkg/tool/%s_%s", goroot, gohostos, gohostarch) 250 } 251 252 // compilerEnv returns a map from "goos/goarch" to the 253 // compiler setting to use for that platform. 254 // The entry for key "" covers any goos/goarch not explicitly set in the map. 255 // For example, compilerEnv("CC", "gcc") returns the C compiler settings 256 // read from $CC, defaulting to gcc. 257 // 258 // The result is a map because additional environment variables 259 // can be set to change the compiler based on goos/goarch settings. 260 // The following applies to all envNames but CC is assumed to simplify 261 // the presentation. 262 // 263 // If no environment variables are set, we use def for all goos/goarch. 264 // $CC, if set, applies to all goos/goarch but is overridden by the following. 265 // $CC_FOR_TARGET, if set, applies to all goos/goarch except gohostos/gohostarch, 266 // but is overridden by the following. 267 // If gohostos=goos and gohostarch=goarch, then $CC_FOR_TARGET applies even for gohostos/gohostarch. 268 // $CC_FOR_goos_goarch, if set, applies only to goos/goarch. 269 func compilerEnv(envName, def string) map[string]string { 270 m := map[string]string{"": def} 271 272 if env := os.Getenv(envName); env != "" { 273 m[""] = env 274 } 275 if env := os.Getenv(envName + "_FOR_TARGET"); env != "" { 276 if gohostos != goos || gohostarch != goarch { 277 m[gohostos+"/"+gohostarch] = m[""] 278 } 279 m[""] = env 280 } 281 282 for _, goos := range okgoos { 283 for _, goarch := range okgoarch { 284 if env := os.Getenv(envName + "_FOR_" + goos + "_" + goarch); env != "" { 285 m[goos+"/"+goarch] = env 286 } 287 } 288 } 289 290 return m 291 } 292 293 // compilerEnvLookup returns the compiler settings for goos/goarch in map m. 294 func compilerEnvLookup(m map[string]string, goos, goarch string) string { 295 if cc := m[goos+"/"+goarch]; cc != "" { 296 return cc 297 } 298 return m[""] 299 } 300 301 // rmworkdir deletes the work directory. 302 func rmworkdir() { 303 if vflag > 1 { 304 errprintf("rm -rf %s\n", workdir) 305 } 306 xremoveall(workdir) 307 } 308 309 // Remove trailing spaces. 310 func chomp(s string) string { 311 return strings.TrimRight(s, " \t\r\n") 312 } 313 314 func branchtag(branch string) (tag string, precise bool) { 315 log := run(goroot, CheckExit, "git", "log", "--decorate=full", "--format=format:%d", "master.."+branch) 316 tag = branch 317 for row, line := range strings.Split(log, "\n") { 318 // Each line is either blank, or looks like 319 // (tag: refs/tags/go1.4rc2, refs/remotes/origin/release-branch.go1.4, refs/heads/release-branch.go1.4) 320 // We need to find an element starting with refs/tags/. 321 const s = " refs/tags/" 322 i := strings.Index(line, s) 323 if i < 0 { 324 continue 325 } 326 // Trim off known prefix. 327 line = line[i+len(s):] 328 // The tag name ends at a comma or paren. 329 j := strings.IndexAny(line, ",)") 330 if j < 0 { 331 continue // malformed line; ignore it 332 } 333 tag = line[:j] 334 if row == 0 { 335 precise = true // tag denotes HEAD 336 } 337 break 338 } 339 return 340 } 341 342 // findgoversion determines the Go version to use in the version string. 343 func findgoversion() string { 344 // The $GOROOT/VERSION file takes priority, for distributions 345 // without the source repo. 346 path := pathf("%s/VERSION", goroot) 347 if isfile(path) { 348 b := chomp(readfile(path)) 349 // Commands such as "dist version > VERSION" will cause 350 // the shell to create an empty VERSION file and set dist's 351 // stdout to its fd. dist in turn looks at VERSION and uses 352 // its content if available, which is empty at this point. 353 // Only use the VERSION file if it is non-empty. 354 if b != "" { 355 // Some builders cross-compile the toolchain on linux-amd64 356 // and then copy the toolchain to the target builder (say, linux-arm) 357 // for use there. But on non-release (devel) branches, the compiler 358 // used on linux-amd64 will be an amd64 binary, and the compiler 359 // shipped to linux-arm will be an arm binary, so they will have different 360 // content IDs (they are binaries for different architectures) and so the 361 // packages compiled by the running-on-amd64 compiler will appear 362 // stale relative to the running-on-arm compiler. Avoid this by setting 363 // the version string to something that doesn't begin with devel. 364 // Then the version string will be used in place of the content ID, 365 // and the packages will look up-to-date. 366 // TODO(rsc): Really the builders could be writing out a better VERSION file instead, 367 // but it is easier to change cmd/dist than to try to make changes to 368 // the builder while Brad is away. 369 if strings.HasPrefix(b, "devel") { 370 if hostType := os.Getenv("META_BUILDLET_HOST_TYPE"); strings.Contains(hostType, "-cross") { 371 fmt.Fprintf(os.Stderr, "warning: changing VERSION from %q to %q\n", b, "builder "+hostType) 372 b = "builder " + hostType 373 } 374 } 375 return b 376 } 377 } 378 379 // The $GOROOT/VERSION.cache file is a cache to avoid invoking 380 // git every time we run this command. Unlike VERSION, it gets 381 // deleted by the clean command. 382 path = pathf("%s/VERSION.cache", goroot) 383 if isfile(path) { 384 return chomp(readfile(path)) 385 } 386 387 // Show a nicer error message if this isn't a Git repo. 388 if !isGitRepo() { 389 fatalf("FAILED: not a Git repo; must put a VERSION file in $GOROOT") 390 } 391 392 // Otherwise, use Git. 393 // What is the current branch? 394 branch := chomp(run(goroot, CheckExit, "git", "rev-parse", "--abbrev-ref", "HEAD")) 395 396 // What are the tags along the current branch? 397 tag := "devel" 398 precise := false 399 400 // If we're on a release branch, use the closest matching tag 401 // that is on the release branch (and not on the master branch). 402 if strings.HasPrefix(branch, "release-branch.") { 403 tag, precise = branchtag(branch) 404 } 405 406 if !precise { 407 // Tag does not point at HEAD; add hash and date to version. 408 tag += chomp(run(goroot, CheckExit, "git", "log", "-n", "1", "--format=format: +%h %cd", "HEAD")) 409 } 410 411 // Cache version. 412 writefile(tag, path, 0) 413 414 return tag 415 } 416 417 // isGitRepo reports whether the working directory is inside a Git repository. 418 func isGitRepo() bool { 419 // NB: simply checking the exit code of `git rev-parse --git-dir` would 420 // suffice here, but that requires deviating from the infrastructure 421 // provided by `run`. 422 gitDir := chomp(run(goroot, 0, "git", "rev-parse", "--git-dir")) 423 if !filepath.IsAbs(gitDir) { 424 gitDir = filepath.Join(goroot, gitDir) 425 } 426 return isdir(gitDir) 427 } 428 429 /* 430 * Initial tree setup. 431 */ 432 433 // The old tools that no longer live in $GOBIN or $GOROOT/bin. 434 var oldtool = []string{ 435 "5a", "5c", "5g", "5l", 436 "6a", "6c", "6g", "6l", 437 "8a", "8c", "8g", "8l", 438 "9a", "9c", "9g", "9l", 439 "6cov", 440 "6nm", 441 "6prof", 442 "cgo", 443 "ebnflint", 444 "goapi", 445 "gofix", 446 "goinstall", 447 "gomake", 448 "gopack", 449 "gopprof", 450 "gotest", 451 "gotype", 452 "govet", 453 "goyacc", 454 "quietgcc", 455 } 456 457 // Unreleased directories (relative to $GOROOT) that should 458 // not be in release branches. 459 var unreleased = []string{ 460 "src/cmd/newlink", 461 "src/cmd/objwriter", 462 "src/debug/goobj", 463 "src/old", 464 } 465 466 // setup sets up the tree for the initial build. 467 func setup() { 468 // Create bin directory. 469 if p := pathf("%s/bin", goroot); !isdir(p) { 470 xmkdir(p) 471 } 472 473 // Create package directory. 474 if p := pathf("%s/pkg", goroot); !isdir(p) { 475 xmkdir(p) 476 } 477 478 p := pathf("%s/pkg/%s_%s", goroot, gohostos, gohostarch) 479 if rebuildall { 480 xremoveall(p) 481 } 482 xmkdirall(p) 483 484 if goos != gohostos || goarch != gohostarch { 485 p := pathf("%s/pkg/%s_%s", goroot, goos, goarch) 486 if rebuildall { 487 xremoveall(p) 488 } 489 xmkdirall(p) 490 } 491 492 // Create object directory. 493 // We used to use it for C objects. 494 // Now we use it for the build cache, to separate dist's cache 495 // from any other cache the user might have. 496 p = pathf("%s/pkg/obj/go-build", goroot) 497 if rebuildall { 498 xremoveall(p) 499 } 500 xmkdirall(p) 501 xatexit(func() { xremoveall(p) }) 502 503 // Create tool directory. 504 // We keep it in pkg/, just like the object directory above. 505 if rebuildall { 506 xremoveall(tooldir) 507 } 508 xmkdirall(tooldir) 509 510 // Remove tool binaries from before the tool/gohostos_gohostarch 511 xremoveall(pathf("%s/bin/tool", goroot)) 512 513 // Remove old pre-tool binaries. 514 for _, old := range oldtool { 515 xremove(pathf("%s/bin/%s", goroot, old)) 516 } 517 518 // If $GOBIN is set and has a Go compiler, it must be cleaned. 519 for _, char := range "56789" { 520 if isfile(pathf("%s/%c%s", gobin, char, "g")) { 521 for _, old := range oldtool { 522 xremove(pathf("%s/%s", gobin, old)) 523 } 524 break 525 } 526 } 527 528 // For release, make sure excluded things are excluded. 529 goversion := findgoversion() 530 if strings.HasPrefix(goversion, "release.") || (strings.HasPrefix(goversion, "go") && !strings.Contains(goversion, "beta")) { 531 for _, dir := range unreleased { 532 if p := pathf("%s/%s", goroot, dir); isdir(p) { 533 fatalf("%s should not exist in release build", p) 534 } 535 } 536 } 537 } 538 539 /* 540 * Tool building 541 */ 542 543 // deptab lists changes to the default dependencies for a given prefix. 544 // deps ending in /* read the whole directory; deps beginning with - 545 // exclude files with that prefix. 546 // Note that this table applies only to the build of cmd/go, 547 // after the main compiler bootstrap. 548 var deptab = []struct { 549 prefix string // prefix of target 550 dep []string // dependency tweaks for targets with that prefix 551 }{ 552 {"github.com/gagliardetto/golang-go/cmd/go/not-internal/cfg", []string{ 553 "zdefaultcc.go", 554 "zosarch.go", 555 }}, 556 {"runtime/internal/sys", []string{ 557 "zversion.go", 558 }}, 559 {"go/build", []string{ 560 "zcgo.go", 561 }}, 562 } 563 564 // depsuffix records the allowed suffixes for source files. 565 var depsuffix = []string{ 566 ".s", 567 ".go", 568 } 569 570 // gentab records how to generate some trivial files. 571 var gentab = []struct { 572 nameprefix string 573 gen func(string, string) 574 }{ 575 {"zdefaultcc.go", mkzdefaultcc}, 576 {"zosarch.go", mkzosarch}, 577 {"zversion.go", mkzversion}, 578 {"zcgo.go", mkzcgo}, 579 580 // not generated anymore, but delete the file if we see it 581 {"enam.c", nil}, 582 {"anames5.c", nil}, 583 {"anames6.c", nil}, 584 {"anames8.c", nil}, 585 {"anames9.c", nil}, 586 } 587 588 // installed maps from a dir name (as given to install) to a chan 589 // closed when the dir's package is installed. 590 var installed = make(map[string]chan struct{}) 591 var installedMu sync.Mutex 592 593 func install(dir string) { 594 <-startInstall(dir) 595 } 596 597 func startInstall(dir string) chan struct{} { 598 installedMu.Lock() 599 ch := installed[dir] 600 if ch == nil { 601 ch = make(chan struct{}) 602 installed[dir] = ch 603 go runInstall(dir, ch) 604 } 605 installedMu.Unlock() 606 return ch 607 } 608 609 // runInstall installs the library, package, or binary associated with dir, 610 // which is relative to $GOROOT/src. 611 func runInstall(pkg string, ch chan struct{}) { 612 if pkg == "net" || pkg == "os/user" || pkg == "crypto/x509" { 613 fatalf("go_bootstrap cannot depend on cgo package %s", pkg) 614 } 615 616 defer close(ch) 617 618 if pkg == "unsafe" { 619 return 620 } 621 622 if vflag > 0 { 623 if goos != gohostos || goarch != gohostarch { 624 errprintf("%s (%s/%s)\n", pkg, goos, goarch) 625 } else { 626 errprintf("%s\n", pkg) 627 } 628 } 629 630 workdir := pathf("%s/%s", workdir, pkg) 631 xmkdirall(workdir) 632 633 var clean []string 634 defer func() { 635 for _, name := range clean { 636 xremove(name) 637 } 638 }() 639 640 // dir = full path to pkg. 641 dir := pathf("%s/src/%s", goroot, pkg) 642 name := filepath.Base(dir) 643 644 // ispkg predicts whether the package should be linked as a binary, based 645 // on the name. There should be no "main" packages in vendor, since 646 // 'go mod vendor' will only copy imported packages there. 647 ispkg := !strings.HasPrefix(pkg, "github.com/gagliardetto/golang-go/cmd/") || strings.Contains(pkg, "/internal/") || strings.Contains(pkg, "/vendor/") 648 649 // Start final link command line. 650 // Note: code below knows that link.p[targ] is the target. 651 var ( 652 link []string 653 targ int 654 ispackcmd bool 655 ) 656 if ispkg { 657 // Go library (package). 658 ispackcmd = true 659 link = []string{"pack", packagefile(pkg)} 660 targ = len(link) - 1 661 xmkdirall(filepath.Dir(link[targ])) 662 } else { 663 // Go command. 664 elem := name 665 if elem == "go" { 666 elem = "go_bootstrap" 667 } 668 link = []string{pathf("%s/link", tooldir)} 669 if goos == "android" { 670 link = append(link, "-buildmode=pie") 671 } 672 if goldflags != "" { 673 link = append(link, goldflags) 674 } 675 link = append(link, "-extld="+compilerEnvLookup(defaultcc, goos, goarch)) 676 link = append(link, "-o", pathf("%s/%s%s", tooldir, elem, exe)) 677 targ = len(link) - 1 678 } 679 ttarg := mtime(link[targ]) 680 681 // Gather files that are sources for this target. 682 // Everything in that directory, and any target-specific 683 // additions. 684 files := xreaddir(dir) 685 686 // Remove files beginning with . or _, 687 // which are likely to be editor temporary files. 688 // This is the same heuristic build.ScanDir uses. 689 // There do exist real C files beginning with _, 690 // so limit that check to just Go files. 691 files = filter(files, func(p string) bool { 692 return !strings.HasPrefix(p, ".") && (!strings.HasPrefix(p, "_") || !strings.HasSuffix(p, ".go")) 693 }) 694 695 for _, dt := range deptab { 696 if pkg == dt.prefix || strings.HasSuffix(dt.prefix, "/") && strings.HasPrefix(pkg, dt.prefix) { 697 for _, p := range dt.dep { 698 p = os.ExpandEnv(p) 699 files = append(files, p) 700 } 701 } 702 } 703 files = uniq(files) 704 705 // Convert to absolute paths. 706 for i, p := range files { 707 if !filepath.IsAbs(p) { 708 files[i] = pathf("%s/%s", dir, p) 709 } 710 } 711 712 // Is the target up-to-date? 713 var gofiles, sfiles, missing []string 714 stale := rebuildall 715 files = filter(files, func(p string) bool { 716 for _, suf := range depsuffix { 717 if strings.HasSuffix(p, suf) { 718 goto ok 719 } 720 } 721 return false 722 ok: 723 t := mtime(p) 724 if !t.IsZero() && !strings.HasSuffix(p, ".a") && !shouldbuild(p, pkg) { 725 return false 726 } 727 if strings.HasSuffix(p, ".go") { 728 gofiles = append(gofiles, p) 729 } else if strings.HasSuffix(p, ".s") { 730 sfiles = append(sfiles, p) 731 } 732 if t.After(ttarg) { 733 stale = true 734 } 735 if t.IsZero() { 736 missing = append(missing, p) 737 } 738 return true 739 }) 740 741 // If there are no files to compile, we're done. 742 if len(files) == 0 { 743 return 744 } 745 746 if !stale { 747 return 748 } 749 750 // For package runtime, copy some files into the work space. 751 if pkg == "runtime" { 752 xmkdirall(pathf("%s/pkg/include", goroot)) 753 // For use by assembly and C files. 754 copyfile(pathf("%s/pkg/include/textflag.h", goroot), 755 pathf("%s/src/runtime/textflag.h", goroot), 0) 756 copyfile(pathf("%s/pkg/include/funcdata.h", goroot), 757 pathf("%s/src/runtime/funcdata.h", goroot), 0) 758 copyfile(pathf("%s/pkg/include/asm_ppc64x.h", goroot), 759 pathf("%s/src/runtime/asm_ppc64x.h", goroot), 0) 760 } 761 762 // Generate any missing files; regenerate existing ones. 763 for _, p := range files { 764 elem := filepath.Base(p) 765 for _, gt := range gentab { 766 if gt.gen == nil { 767 continue 768 } 769 if strings.HasPrefix(elem, gt.nameprefix) { 770 if vflag > 1 { 771 errprintf("generate %s\n", p) 772 } 773 gt.gen(dir, p) 774 // Do not add generated file to clean list. 775 // In runtime, we want to be able to 776 // build the package with the go tool, 777 // and it assumes these generated files already 778 // exist (it does not know how to build them). 779 // The 'clean' command can remove 780 // the generated files. 781 goto built 782 } 783 } 784 // Did not rebuild p. 785 if find(p, missing) >= 0 { 786 fatalf("missing file %s", p) 787 } 788 built: 789 } 790 791 // Resolve imported packages to actual package paths. 792 // Make sure they're installed. 793 importMap := make(map[string]string) 794 for _, p := range gofiles { 795 for _, imp := range readimports(p) { 796 importMap[imp] = resolveVendor(imp, dir) 797 } 798 } 799 sortedImports := make([]string, 0, len(importMap)) 800 for imp := range importMap { 801 sortedImports = append(sortedImports, imp) 802 } 803 sort.Strings(sortedImports) 804 805 for _, dep := range importMap { 806 startInstall(dep) 807 } 808 for _, dep := range importMap { 809 install(dep) 810 } 811 812 if goos != gohostos || goarch != gohostarch { 813 // We've generated the right files; the go command can do the build. 814 if vflag > 1 { 815 errprintf("skip build for cross-compile %s\n", pkg) 816 } 817 return 818 } 819 820 asmArgs := []string{ 821 pathf("%s/asm", tooldir), 822 "-I", workdir, 823 "-I", pathf("%s/pkg/include", goroot), 824 "-D", "GOOS_" + goos, 825 "-D", "GOARCH_" + goarch, 826 "-D", "GOOS_GOARCH_" + goos + "_" + goarch, 827 } 828 if goarch == "mips" || goarch == "mipsle" { 829 // Define GOMIPS_value from gomips. 830 asmArgs = append(asmArgs, "-D", "GOMIPS_"+gomips) 831 } 832 if goarch == "mips64" || goarch == "mips64le" { 833 // Define GOMIPS64_value from gomips64. 834 asmArgs = append(asmArgs, "-D", "GOMIPS64_"+gomips64) 835 } 836 goasmh := pathf("%s/go_asm.h", workdir) 837 838 // Collect symabis from assembly code. 839 var symabis string 840 if len(sfiles) > 0 { 841 symabis = pathf("%s/symabis", workdir) 842 var wg sync.WaitGroup 843 asmabis := append(asmArgs[:len(asmArgs):len(asmArgs)], "-gensymabis", "-o", symabis) 844 asmabis = append(asmabis, sfiles...) 845 if err := ioutil.WriteFile(goasmh, nil, 0666); err != nil { 846 fatalf("cannot write empty go_asm.h: %s", err) 847 } 848 bgrun(&wg, dir, asmabis...) 849 bgwait(&wg) 850 } 851 852 // Build an importcfg file for the compiler. 853 buf := &bytes.Buffer{} 854 for _, imp := range sortedImports { 855 if imp == "unsafe" { 856 continue 857 } 858 dep := importMap[imp] 859 if imp != dep { 860 fmt.Fprintf(buf, "importmap %s=%s\n", imp, dep) 861 } 862 fmt.Fprintf(buf, "packagefile %s=%s\n", dep, packagefile(dep)) 863 } 864 importcfg := pathf("%s/importcfg", workdir) 865 if err := ioutil.WriteFile(importcfg, buf.Bytes(), 0666); err != nil { 866 fatalf("cannot write importcfg file: %v", err) 867 } 868 869 var archive string 870 // The next loop will compile individual non-Go files. 871 // Hand the Go files to the compiler en masse. 872 // For packages containing assembly, this writes go_asm.h, which 873 // the assembly files will need. 874 pkgName := pkg 875 if strings.HasPrefix(pkg, "github.com/gagliardetto/golang-go/cmd/") && strings.Count(pkg, "/") == 1 { 876 pkgName = "main" 877 } 878 b := pathf("%s/_go_.a", workdir) 879 clean = append(clean, b) 880 if !ispackcmd { 881 link = append(link, b) 882 } else { 883 archive = b 884 } 885 886 // Compile Go code. 887 compile := []string{pathf("%s/compile", tooldir), "-std", "-pack", "-o", b, "-p", pkgName, "-importcfg", importcfg} 888 if gogcflags != "" { 889 compile = append(compile, strings.Fields(gogcflags)...) 890 } 891 if pkg == "runtime" { 892 compile = append(compile, "-+") 893 } 894 if len(sfiles) > 0 { 895 compile = append(compile, "-asmhdr", goasmh) 896 } 897 if symabis != "" { 898 compile = append(compile, "-symabis", symabis) 899 } 900 if goos == "android" { 901 compile = append(compile, "-shared") 902 } 903 904 compile = append(compile, gofiles...) 905 var wg sync.WaitGroup 906 // We use bgrun and immediately wait for it instead of calling run() synchronously. 907 // This executes all jobs through the bgwork channel and allows the process 908 // to exit cleanly in case an error occurs. 909 bgrun(&wg, dir, compile...) 910 bgwait(&wg) 911 912 // Compile the files. 913 for _, p := range sfiles { 914 // Assembly file for a Go package. 915 compile := asmArgs[:len(asmArgs):len(asmArgs)] 916 917 doclean := true 918 b := pathf("%s/%s", workdir, filepath.Base(p)) 919 920 // Change the last character of the output file (which was c or s). 921 b = b[:len(b)-1] + "o" 922 compile = append(compile, "-o", b, p) 923 bgrun(&wg, dir, compile...) 924 925 link = append(link, b) 926 if doclean { 927 clean = append(clean, b) 928 } 929 } 930 bgwait(&wg) 931 932 if ispackcmd { 933 xremove(link[targ]) 934 dopack(link[targ], archive, link[targ+1:]) 935 return 936 } 937 938 // Remove target before writing it. 939 xremove(link[targ]) 940 bgrun(&wg, "", link...) 941 bgwait(&wg) 942 } 943 944 // packagefile returns the path to a compiled .a file for the given package 945 // path. Paths may need to be resolved with resolveVendor first. 946 func packagefile(pkg string) string { 947 return pathf("%s/pkg/%s_%s/%s.a", goroot, goos, goarch, pkg) 948 } 949 950 // matchfield reports whether the field (x,y,z) matches this build. 951 // all the elements in the field must be satisfied. 952 func matchfield(f string) bool { 953 for _, tag := range strings.Split(f, ",") { 954 if !matchtag(tag) { 955 return false 956 } 957 } 958 return true 959 } 960 961 // matchtag reports whether the tag (x or !x) matches this build. 962 func matchtag(tag string) bool { 963 if tag == "" { 964 return false 965 } 966 if tag[0] == '!' { 967 if len(tag) == 1 || tag[1] == '!' { 968 return false 969 } 970 return !matchtag(tag[1:]) 971 } 972 return tag == "gc" || tag == goos || tag == goarch || tag == "cmd_go_bootstrap" || tag == "go1.1" || (goos == "android" && tag == "linux") || (goos == "illumos" && tag == "solaris") 973 } 974 975 // shouldbuild reports whether we should build this file. 976 // It applies the same rules that are used with context tags 977 // in package go/build, except it's less picky about the order 978 // of GOOS and GOARCH. 979 // We also allow the special tag cmd_go_bootstrap. 980 // See ../go/bootstrap.go and package go/build. 981 func shouldbuild(file, pkg string) bool { 982 // Check file name for GOOS or GOARCH. 983 name := filepath.Base(file) 984 excluded := func(list []string, ok string) bool { 985 for _, x := range list { 986 if x == ok || (ok == "android" && x == "linux") || (ok == "illumos" && x == "solaris") { 987 continue 988 } 989 i := strings.Index(name, x) 990 if i <= 0 || name[i-1] != '_' { 991 continue 992 } 993 i += len(x) 994 if i == len(name) || name[i] == '.' || name[i] == '_' { 995 return true 996 } 997 } 998 return false 999 } 1000 if excluded(okgoos, goos) || excluded(okgoarch, goarch) { 1001 return false 1002 } 1003 1004 // Omit test files. 1005 if strings.Contains(name, "_test") { 1006 return false 1007 } 1008 1009 // Check file contents for // +build lines. 1010 for _, p := range strings.Split(readfile(file), "\n") { 1011 p = strings.TrimSpace(p) 1012 if p == "" { 1013 continue 1014 } 1015 code := p 1016 i := strings.Index(code, "//") 1017 if i > 0 { 1018 code = strings.TrimSpace(code[:i]) 1019 } 1020 if code == "package documentation" { 1021 return false 1022 } 1023 if code == "package main" && pkg != "github.com/gagliardetto/golang-go/cmd/go" && pkg != "github.com/gagliardetto/golang-go/cmd/cgo" { 1024 return false 1025 } 1026 if !strings.HasPrefix(p, "//") { 1027 break 1028 } 1029 if !strings.Contains(p, "+build") { 1030 continue 1031 } 1032 fields := strings.Fields(p[2:]) 1033 if len(fields) < 1 || fields[0] != "+build" { 1034 continue 1035 } 1036 for _, p := range fields[1:] { 1037 if matchfield(p) { 1038 goto fieldmatch 1039 } 1040 } 1041 return false 1042 fieldmatch: 1043 } 1044 1045 return true 1046 } 1047 1048 // copy copies the file src to dst, via memory (so only good for small files). 1049 func copyfile(dst, src string, flag int) { 1050 if vflag > 1 { 1051 errprintf("cp %s %s\n", src, dst) 1052 } 1053 writefile(readfile(src), dst, flag) 1054 } 1055 1056 // dopack copies the package src to dst, 1057 // appending the files listed in extra. 1058 // The archive format is the traditional Unix ar format. 1059 func dopack(dst, src string, extra []string) { 1060 bdst := bytes.NewBufferString(readfile(src)) 1061 for _, file := range extra { 1062 b := readfile(file) 1063 // find last path element for archive member name 1064 i := strings.LastIndex(file, "/") + 1 1065 j := strings.LastIndex(file, `\`) + 1 1066 if i < j { 1067 i = j 1068 } 1069 fmt.Fprintf(bdst, "%-16.16s%-12d%-6d%-6d%-8o%-10d`\n", file[i:], 0, 0, 0, 0644, len(b)) 1070 bdst.WriteString(b) 1071 if len(b)&1 != 0 { 1072 bdst.WriteByte(0) 1073 } 1074 } 1075 writefile(bdst.String(), dst, 0) 1076 } 1077 1078 var runtimegen = []string{ 1079 "zaexperiment.h", 1080 "zversion.go", 1081 } 1082 1083 // cleanlist is a list of packages with generated files and commands. 1084 var cleanlist = []string{ 1085 "runtime/internal/sys", 1086 "github.com/gagliardetto/golang-go/cmd/cgo", 1087 "github.com/gagliardetto/golang-go/cmd/go/not-internal/cfg", 1088 "go/build", 1089 } 1090 1091 func clean() { 1092 for _, name := range cleanlist { 1093 path := pathf("%s/src/%s", goroot, name) 1094 // Remove generated files. 1095 for _, elem := range xreaddir(path) { 1096 for _, gt := range gentab { 1097 if strings.HasPrefix(elem, gt.nameprefix) { 1098 xremove(pathf("%s/%s", path, elem)) 1099 } 1100 } 1101 } 1102 // Remove generated binary named for directory. 1103 if strings.HasPrefix(name, "github.com/gagliardetto/golang-go/cmd/") { 1104 xremove(pathf("%s/%s", path, name[4:])) 1105 } 1106 } 1107 1108 // remove runtimegen files. 1109 path := pathf("%s/src/runtime", goroot) 1110 for _, elem := range runtimegen { 1111 xremove(pathf("%s/%s", path, elem)) 1112 } 1113 1114 if rebuildall { 1115 // Remove object tree. 1116 xremoveall(pathf("%s/pkg/obj/%s_%s", goroot, gohostos, gohostarch)) 1117 1118 // Remove installed packages and tools. 1119 xremoveall(pathf("%s/pkg/%s_%s", goroot, gohostos, gohostarch)) 1120 xremoveall(pathf("%s/pkg/%s_%s", goroot, goos, goarch)) 1121 xremoveall(pathf("%s/pkg/%s_%s_race", goroot, gohostos, gohostarch)) 1122 xremoveall(pathf("%s/pkg/%s_%s_race", goroot, goos, goarch)) 1123 xremoveall(tooldir) 1124 1125 // Remove cached version info. 1126 xremove(pathf("%s/VERSION.cache", goroot)) 1127 } 1128 } 1129 1130 /* 1131 * command implementations 1132 */ 1133 1134 // The env command prints the default environment. 1135 func cmdenv() { 1136 path := flag.Bool("p", false, "emit updated PATH") 1137 plan9 := flag.Bool("9", false, "emit plan 9 syntax") 1138 windows := flag.Bool("w", false, "emit windows syntax") 1139 xflagparse(0) 1140 1141 format := "%s=\"%s\"\n" 1142 switch { 1143 case *plan9: 1144 format = "%s='%s'\n" 1145 case *windows: 1146 format = "set %s=%s\r\n" 1147 } 1148 1149 xprintf(format, "GOARCH", goarch) 1150 xprintf(format, "GOBIN", gobin) 1151 xprintf(format, "GOCACHE", os.Getenv("GOCACHE")) 1152 xprintf(format, "GODEBUG", os.Getenv("GODEBUG")) 1153 xprintf(format, "GOHOSTARCH", gohostarch) 1154 xprintf(format, "GOHOSTOS", gohostos) 1155 xprintf(format, "GOOS", goos) 1156 xprintf(format, "GOPROXY", os.Getenv("GOPROXY")) 1157 xprintf(format, "GOROOT", goroot) 1158 xprintf(format, "GOTMPDIR", os.Getenv("GOTMPDIR")) 1159 xprintf(format, "GOTOOLDIR", tooldir) 1160 if goarch == "arm" { 1161 xprintf(format, "GOARM", goarm) 1162 } 1163 if goarch == "386" { 1164 xprintf(format, "GO386", go386) 1165 } 1166 if goarch == "mips" || goarch == "mipsle" { 1167 xprintf(format, "GOMIPS", gomips) 1168 } 1169 if goarch == "mips64" || goarch == "mips64le" { 1170 xprintf(format, "GOMIPS64", gomips64) 1171 } 1172 if goarch == "ppc64" || goarch == "ppc64le" { 1173 xprintf(format, "GOPPC64", goppc64) 1174 } 1175 1176 if *path { 1177 sep := ":" 1178 if gohostos == "windows" { 1179 sep = ";" 1180 } 1181 xprintf(format, "PATH", fmt.Sprintf("%s%s%s", gobin, sep, os.Getenv("PATH"))) 1182 } 1183 } 1184 1185 var ( 1186 timeLogEnabled = os.Getenv("GOBUILDTIMELOGFILE") != "" 1187 timeLogMu sync.Mutex 1188 timeLogFile *os.File 1189 timeLogStart time.Time 1190 ) 1191 1192 func timelog(op, name string) { 1193 if !timeLogEnabled { 1194 return 1195 } 1196 timeLogMu.Lock() 1197 defer timeLogMu.Unlock() 1198 if timeLogFile == nil { 1199 f, err := os.OpenFile(os.Getenv("GOBUILDTIMELOGFILE"), os.O_RDWR|os.O_APPEND, 0666) 1200 if err != nil { 1201 log.Fatal(err) 1202 } 1203 buf := make([]byte, 100) 1204 n, _ := f.Read(buf) 1205 s := string(buf[:n]) 1206 if i := strings.Index(s, "\n"); i >= 0 { 1207 s = s[:i] 1208 } 1209 i := strings.Index(s, " start") 1210 if i < 0 { 1211 log.Fatalf("time log %s does not begin with start line", os.Getenv("GOBULDTIMELOGFILE")) 1212 } 1213 t, err := time.Parse(time.UnixDate, s[:i]) 1214 if err != nil { 1215 log.Fatalf("cannot parse time log line %q: %v", s, err) 1216 } 1217 timeLogStart = t 1218 timeLogFile = f 1219 } 1220 t := time.Now() 1221 fmt.Fprintf(timeLogFile, "%s %+.1fs %s %s\n", t.Format(time.UnixDate), t.Sub(timeLogStart).Seconds(), op, name) 1222 } 1223 1224 var toolchain = []string{"github.com/gagliardetto/golang-go/cmd/asm", "github.com/gagliardetto/golang-go/cmd/cgo", "github.com/gagliardetto/golang-go/cmd/compile", "github.com/gagliardetto/golang-go/cmd/link"} 1225 1226 // The bootstrap command runs a build from scratch, 1227 // stopping at having installed the go_bootstrap command. 1228 // 1229 // WARNING: This command runs after cmd/dist is built with Go 1.4. 1230 // It rebuilds and installs cmd/dist with the new toolchain, so other 1231 // commands (like "go tool dist test" in run.bash) can rely on bug fixes 1232 // made since Go 1.4, but this function cannot. In particular, the uses 1233 // of os/exec in this function cannot assume that 1234 // cmd.Env = append(os.Environ(), "X=Y") 1235 // sets $X to Y in the command's environment. That guarantee was 1236 // added after Go 1.4, and in fact in Go 1.4 it was typically the opposite: 1237 // if $X was already present in os.Environ(), most systems preferred 1238 // that setting, not the new one. 1239 func cmdbootstrap() { 1240 timelog("start", "dist bootstrap") 1241 defer timelog("end", "dist bootstrap") 1242 1243 var noBanner bool 1244 var debug bool 1245 flag.BoolVar(&rebuildall, "a", rebuildall, "rebuild all") 1246 flag.BoolVar(&debug, "d", debug, "enable debugging of bootstrap process") 1247 flag.BoolVar(&noBanner, "no-banner", noBanner, "do not print banner") 1248 1249 xflagparse(0) 1250 1251 // Set GOPATH to an internal directory. We shouldn't actually 1252 // need to store files here, since the toolchain won't 1253 // depend on modules outside of vendor directories, but if 1254 // GOPATH points somewhere else (e.g., to GOROOT), the 1255 // go tool may complain. 1256 os.Setenv("GOPATH", pathf("%s/pkg/obj/gopath", goroot)) 1257 1258 if debug { 1259 // cmd/buildid is used in debug mode. 1260 toolchain = append(toolchain, "github.com/gagliardetto/golang-go/cmd/buildid") 1261 } 1262 1263 if isdir(pathf("%s/src/pkg", goroot)) { 1264 fatalf("\n\n"+ 1265 "The Go package sources have moved to $GOROOT/src.\n"+ 1266 "*** %s still exists. ***\n"+ 1267 "It probably contains stale files that may confuse the build.\n"+ 1268 "Please (check what's there and) remove it and try again.\n"+ 1269 "See https://golang.org/s/go14nopkg\n", 1270 pathf("%s/src/pkg", goroot)) 1271 } 1272 1273 if rebuildall { 1274 clean() 1275 } 1276 1277 setup() 1278 1279 timelog("build", "toolchain1") 1280 checkCC() 1281 bootstrapBuildTools() 1282 1283 // Remember old content of $GOROOT/bin for comparison below. 1284 oldBinFiles, _ := filepath.Glob(pathf("%s/bin/*", goroot)) 1285 1286 // For the main bootstrap, building for host os/arch. 1287 oldgoos = goos 1288 oldgoarch = goarch 1289 goos = gohostos 1290 goarch = gohostarch 1291 os.Setenv("GOHOSTARCH", gohostarch) 1292 os.Setenv("GOHOSTOS", gohostos) 1293 os.Setenv("GOARCH", goarch) 1294 os.Setenv("GOOS", goos) 1295 1296 timelog("build", "go_bootstrap") 1297 xprintf("Building Go bootstrap cmd/go (go_bootstrap) using Go toolchain1.\n") 1298 install("runtime") // dependency not visible in sources; also sets up textflag.h 1299 install("github.com/gagliardetto/golang-go/cmd/go") 1300 if vflag > 0 { 1301 xprintf("\n") 1302 } 1303 1304 gogcflags = os.Getenv("GO_GCFLAGS") // we were using $BOOT_GO_GCFLAGS until now 1305 goldflags = os.Getenv("GO_LDFLAGS") // we were using $BOOT_GO_LDFLAGS until now 1306 goBootstrap := pathf("%s/go_bootstrap", tooldir) 1307 cmdGo := pathf("%s/go", gobin) 1308 if debug { 1309 run("", ShowOutput|CheckExit, pathf("%s/compile", tooldir), "-V=full") 1310 copyfile(pathf("%s/compile1", tooldir), pathf("%s/compile", tooldir), writeExec) 1311 } 1312 1313 // To recap, so far we have built the new toolchain 1314 // (cmd/asm, cmd/cgo, cmd/compile, cmd/link) 1315 // using Go 1.4's toolchain and go command. 1316 // Then we built the new go command (as go_bootstrap) 1317 // using the new toolchain and our own build logic (above). 1318 // 1319 // toolchain1 = mk(new toolchain, go1.4 toolchain, go1.4 cmd/go) 1320 // go_bootstrap = mk(new cmd/go, toolchain1, cmd/dist) 1321 // 1322 // The toolchain1 we built earlier is built from the new sources, 1323 // but because it was built using cmd/go it has no build IDs. 1324 // The eventually installed toolchain needs build IDs, so we need 1325 // to do another round: 1326 // 1327 // toolchain2 = mk(new toolchain, toolchain1, go_bootstrap) 1328 // 1329 timelog("build", "toolchain2") 1330 if vflag > 0 { 1331 xprintf("\n") 1332 } 1333 xprintf("Building Go toolchain2 using go_bootstrap and Go toolchain1.\n") 1334 os.Setenv("CC", compilerEnvLookup(defaultcc, goos, goarch)) 1335 goInstall(goBootstrap, append([]string{"-i"}, toolchain...)...) 1336 if debug { 1337 run("", ShowOutput|CheckExit, pathf("%s/compile", tooldir), "-V=full") 1338 run("", ShowOutput|CheckExit, pathf("%s/buildid", tooldir), pathf("%s/pkg/%s_%s/runtime/internal/sys.a", goroot, goos, goarch)) 1339 copyfile(pathf("%s/compile2", tooldir), pathf("%s/compile", tooldir), writeExec) 1340 } 1341 1342 // Toolchain2 should be semantically equivalent to toolchain1, 1343 // but it was built using the new compilers instead of the Go 1.4 compilers, 1344 // so it should at the least run faster. Also, toolchain1 had no build IDs 1345 // in the binaries, while toolchain2 does. In non-release builds, the 1346 // toolchain's build IDs feed into constructing the build IDs of built targets, 1347 // so in non-release builds, everything now looks out-of-date due to 1348 // toolchain2 having build IDs - that is, due to the go command seeing 1349 // that there are new compilers. In release builds, the toolchain's reported 1350 // version is used in place of the build ID, and the go command does not 1351 // see that change from toolchain1 to toolchain2, so in release builds, 1352 // nothing looks out of date. 1353 // To keep the behavior the same in both non-release and release builds, 1354 // we force-install everything here. 1355 // 1356 // toolchain3 = mk(new toolchain, toolchain2, go_bootstrap) 1357 // 1358 timelog("build", "toolchain3") 1359 if vflag > 0 { 1360 xprintf("\n") 1361 } 1362 xprintf("Building Go toolchain3 using go_bootstrap and Go toolchain2.\n") 1363 goInstall(goBootstrap, append([]string{"-a", "-i"}, toolchain...)...) 1364 if debug { 1365 run("", ShowOutput|CheckExit, pathf("%s/compile", tooldir), "-V=full") 1366 run("", ShowOutput|CheckExit, pathf("%s/buildid", tooldir), pathf("%s/pkg/%s_%s/runtime/internal/sys.a", goroot, goos, goarch)) 1367 copyfile(pathf("%s/compile3", tooldir), pathf("%s/compile", tooldir), writeExec) 1368 } 1369 checkNotStale(goBootstrap, append(toolchain, "runtime/internal/sys")...) 1370 1371 if goos == oldgoos && goarch == oldgoarch { 1372 // Common case - not setting up for cross-compilation. 1373 timelog("build", "toolchain") 1374 if vflag > 0 { 1375 xprintf("\n") 1376 } 1377 xprintf("Building packages and commands for %s/%s.\n", goos, goarch) 1378 } else { 1379 // GOOS/GOARCH does not match GOHOSTOS/GOHOSTARCH. 1380 // Finish GOHOSTOS/GOHOSTARCH installation and then 1381 // run GOOS/GOARCH installation. 1382 timelog("build", "host toolchain") 1383 if vflag > 0 { 1384 xprintf("\n") 1385 } 1386 xprintf("Building packages and commands for host, %s/%s.\n", goos, goarch) 1387 goInstall(goBootstrap, "std", "cmd") 1388 checkNotStale(goBootstrap, "std", "cmd") 1389 checkNotStale(cmdGo, "std", "cmd") 1390 1391 timelog("build", "target toolchain") 1392 if vflag > 0 { 1393 xprintf("\n") 1394 } 1395 goos = oldgoos 1396 goarch = oldgoarch 1397 os.Setenv("GOOS", goos) 1398 os.Setenv("GOARCH", goarch) 1399 os.Setenv("CC", compilerEnvLookup(defaultcc, goos, goarch)) 1400 xprintf("Building packages and commands for target, %s/%s.\n", goos, goarch) 1401 } 1402 targets := []string{"std", "cmd"} 1403 if goos == "js" && goarch == "wasm" { 1404 // Skip the cmd tools for js/wasm. They're not usable. 1405 targets = targets[:1] 1406 } 1407 goInstall(goBootstrap, targets...) 1408 checkNotStale(goBootstrap, targets...) 1409 checkNotStale(cmdGo, targets...) 1410 if debug { 1411 run("", ShowOutput|CheckExit, pathf("%s/compile", tooldir), "-V=full") 1412 run("", ShowOutput|CheckExit, pathf("%s/buildid", tooldir), pathf("%s/pkg/%s_%s/runtime/internal/sys.a", goroot, goos, goarch)) 1413 checkNotStale(goBootstrap, append(toolchain, "runtime/internal/sys")...) 1414 copyfile(pathf("%s/compile4", tooldir), pathf("%s/compile", tooldir), writeExec) 1415 } 1416 1417 // Check that there are no new files in $GOROOT/bin other than 1418 // go and gofmt and $GOOS_$GOARCH (target bin when cross-compiling). 1419 binFiles, _ := filepath.Glob(pathf("%s/bin/*", goroot)) 1420 ok := map[string]bool{} 1421 for _, f := range oldBinFiles { 1422 ok[f] = true 1423 } 1424 for _, f := range binFiles { 1425 elem := strings.TrimSuffix(filepath.Base(f), ".exe") 1426 if !ok[f] && elem != "go" && elem != "gofmt" && elem != goos+"_"+goarch { 1427 fatalf("unexpected new file in $GOROOT/bin: %s", elem) 1428 } 1429 } 1430 1431 // Remove go_bootstrap now that we're done. 1432 xremove(pathf("%s/go_bootstrap", tooldir)) 1433 1434 if goos == "android" { 1435 // Make sure the exec wrapper will sync a fresh $GOROOT to the device. 1436 xremove(pathf("%s/go_android_exec-adb-sync-status", os.TempDir())) 1437 } 1438 1439 if wrapperPath := wrapperPathFor(goos, goarch); wrapperPath != "" { 1440 oldcc := os.Getenv("CC") 1441 os.Setenv("GOOS", gohostos) 1442 os.Setenv("GOARCH", gohostarch) 1443 os.Setenv("CC", compilerEnvLookup(defaultcc, gohostos, gohostarch)) 1444 goCmd(cmdGo, "build", "-o", pathf("%s/go_%s_%s_exec%s", gobin, goos, goarch, exe), wrapperPath) 1445 // Restore environment. 1446 // TODO(elias.naur): support environment variables in goCmd? 1447 os.Setenv("GOOS", goos) 1448 os.Setenv("GOARCH", goarch) 1449 os.Setenv("CC", oldcc) 1450 } 1451 1452 // Print trailing banner unless instructed otherwise. 1453 if !noBanner { 1454 banner() 1455 } 1456 } 1457 1458 func wrapperPathFor(goos, goarch string) string { 1459 switch { 1460 case goos == "android": 1461 if gohostos != "android" { 1462 return pathf("%s/misc/android/go_android_exec.go", goroot) 1463 } 1464 case goos == "darwin" && (goarch == "arm" || goarch == "arm64"): 1465 if gohostos != "darwin" || (gohostarch != "arm" && gohostarch != "arm64") { 1466 return pathf("%s/misc/ios/go_darwin_arm_exec.go", goroot) 1467 } 1468 } 1469 return "" 1470 } 1471 1472 func goInstall(goBinary string, args ...string) { 1473 goCmd(goBinary, "install", args...) 1474 } 1475 1476 func goCmd(goBinary string, cmd string, args ...string) { 1477 goCmd := []string{goBinary, cmd, "-gcflags=all=" + gogcflags, "-ldflags=all=" + goldflags} 1478 if vflag > 0 { 1479 goCmd = append(goCmd, "-v") 1480 } 1481 1482 // Force only one process at a time on vx32 emulation. 1483 if gohostos == "plan9" && os.Getenv("sysname") == "vx32" { 1484 goCmd = append(goCmd, "-p=1") 1485 } 1486 1487 run(goroot, ShowOutput|CheckExit, append(goCmd, args...)...) 1488 } 1489 1490 func checkNotStale(goBinary string, targets ...string) { 1491 out := run(goroot, CheckExit, 1492 append([]string{ 1493 goBinary, 1494 "list", "-gcflags=all=" + gogcflags, "-ldflags=all=" + goldflags, 1495 "-f={{if .Stale}}\tSTALE {{.ImportPath}}: {{.StaleReason}}{{end}}", 1496 }, targets...)...) 1497 if strings.Contains(out, "\tSTALE ") { 1498 os.Setenv("GODEBUG", "gocachehash=1") 1499 for _, target := range []string{"runtime/internal/sys", "github.com/gagliardetto/golang-go/cmd/dist", "github.com/gagliardetto/golang-go/cmd/link"} { 1500 if strings.Contains(out, "STALE "+target) { 1501 run(goroot, ShowOutput|CheckExit, goBinary, "list", "-f={{.ImportPath}} {{.Stale}}", target) 1502 break 1503 } 1504 } 1505 fatalf("unexpected stale targets reported by %s list -gcflags=\"%s\" -ldflags=\"%s\" for %v:\n%s", goBinary, gogcflags, goldflags, targets, out) 1506 } 1507 } 1508 1509 // Cannot use go/build directly because cmd/dist for a new release 1510 // builds against an old release's go/build, which may be out of sync. 1511 // To reduce duplication, we generate the list for go/build from this. 1512 // 1513 // We list all supported platforms in this list, so that this is the 1514 // single point of truth for supported platforms. This list is used 1515 // by 'go tool dist list'. 1516 var cgoEnabled = map[string]bool{ 1517 "aix/ppc64": true, 1518 "darwin/386": false, // Issue 31751 1519 "darwin/amd64": true, 1520 "darwin/arm": true, 1521 "darwin/arm64": true, 1522 "dragonfly/amd64": true, 1523 "freebsd/386": true, 1524 "freebsd/amd64": true, 1525 "freebsd/arm": true, 1526 "freebsd/arm64": true, 1527 "illumos/amd64": true, 1528 "linux/386": true, 1529 "linux/amd64": true, 1530 "linux/arm": true, 1531 "linux/arm64": true, 1532 "linux/ppc64": false, 1533 "linux/ppc64le": true, 1534 "linux/mips": true, 1535 "linux/mipsle": true, 1536 "linux/mips64": true, 1537 "linux/mips64le": true, 1538 "linux/riscv64": false, // Issue 36641 1539 "linux/s390x": true, 1540 "linux/sparc64": true, 1541 "android/386": true, 1542 "android/amd64": true, 1543 "android/arm": true, 1544 "android/arm64": true, 1545 "js/wasm": false, 1546 "netbsd/386": true, 1547 "netbsd/amd64": true, 1548 "netbsd/arm": true, 1549 "netbsd/arm64": true, 1550 "openbsd/386": true, 1551 "openbsd/amd64": true, 1552 "openbsd/arm": true, 1553 "openbsd/arm64": true, 1554 "plan9/386": false, 1555 "plan9/amd64": false, 1556 "plan9/arm": false, 1557 "solaris/amd64": true, 1558 "windows/386": true, 1559 "windows/amd64": true, 1560 "windows/arm": false, 1561 } 1562 1563 // List of platforms which are supported but not complete yet. These get 1564 // filtered out of cgoEnabled for 'dist list'. See golang.org/issue/28944 1565 var incomplete = map[string]bool{ 1566 "linux/sparc64": true, 1567 } 1568 1569 func needCC() bool { 1570 switch os.Getenv("CGO_ENABLED") { 1571 case "1": 1572 return true 1573 case "0": 1574 return false 1575 } 1576 return cgoEnabled[gohostos+"/"+gohostarch] 1577 } 1578 1579 func checkCC() { 1580 if !needCC() { 1581 return 1582 } 1583 if output, err := exec.Command(defaultcc[""], "--help").CombinedOutput(); err != nil { 1584 outputHdr := "" 1585 if len(output) > 0 { 1586 outputHdr = "\nCommand output:\n\n" 1587 } 1588 fatalf("cannot invoke C compiler %q: %v\n\n"+ 1589 "Go needs a system C compiler for use with cgo.\n"+ 1590 "To set a C compiler, set CC=the-compiler.\n"+ 1591 "To disable cgo, set CGO_ENABLED=0.\n%s%s", defaultcc[""], err, outputHdr, output) 1592 } 1593 } 1594 1595 func findModuleRoot(dir string) (root string) { 1596 for { 1597 if fi, err := os.Stat(filepath.Join(dir, "go.mod")); err == nil && !fi.IsDir() { 1598 return dir 1599 } 1600 d := filepath.Dir(dir) 1601 if d == dir { 1602 break 1603 } 1604 dir = d 1605 } 1606 return "" 1607 } 1608 1609 func defaulttarg() string { 1610 // xgetwd might return a path with symlinks fully resolved, and if 1611 // there happens to be symlinks in goroot, then the hasprefix test 1612 // will never succeed. Instead, we use xrealwd to get a canonical 1613 // goroot/src before the comparison to avoid this problem. 1614 pwd := xgetwd() 1615 src := pathf("%s/src/", goroot) 1616 real_src := xrealwd(src) 1617 if !strings.HasPrefix(pwd, real_src) { 1618 fatalf("current directory %s is not under %s", pwd, real_src) 1619 } 1620 pwd = pwd[len(real_src):] 1621 // guard against xrealwd returning the directory without the trailing / 1622 pwd = strings.TrimPrefix(pwd, "/") 1623 1624 return pwd 1625 } 1626 1627 // Install installs the list of packages named on the command line. 1628 func cmdinstall() { 1629 xflagparse(-1) 1630 1631 if flag.NArg() == 0 { 1632 install(defaulttarg()) 1633 } 1634 1635 for _, arg := range flag.Args() { 1636 install(arg) 1637 } 1638 } 1639 1640 // Clean deletes temporary objects. 1641 func cmdclean() { 1642 xflagparse(0) 1643 clean() 1644 } 1645 1646 // Banner prints the 'now you've installed Go' banner. 1647 func cmdbanner() { 1648 xflagparse(0) 1649 banner() 1650 } 1651 1652 func banner() { 1653 if vflag > 0 { 1654 xprintf("\n") 1655 } 1656 xprintf("---\n") 1657 xprintf("Installed Go for %s/%s in %s\n", goos, goarch, goroot) 1658 xprintf("Installed commands in %s\n", gobin) 1659 1660 if !xsamefile(goroot_final, goroot) { 1661 // If the files are to be moved, don't check that gobin 1662 // is on PATH; assume they know what they are doing. 1663 } else if gohostos == "plan9" { 1664 // Check that gobin is bound before /bin. 1665 pid := strings.Replace(readfile("#c/pid"), " ", "", -1) 1666 ns := fmt.Sprintf("/proc/%s/ns", pid) 1667 if !strings.Contains(readfile(ns), fmt.Sprintf("bind -b %s /bin", gobin)) { 1668 xprintf("*** You need to bind %s before /bin.\n", gobin) 1669 } 1670 } else { 1671 // Check that gobin appears in $PATH. 1672 pathsep := ":" 1673 if gohostos == "windows" { 1674 pathsep = ";" 1675 } 1676 if !strings.Contains(pathsep+os.Getenv("PATH")+pathsep, pathsep+gobin+pathsep) { 1677 xprintf("*** You need to add %s to your PATH.\n", gobin) 1678 } 1679 } 1680 1681 if !xsamefile(goroot_final, goroot) { 1682 xprintf("\n"+ 1683 "The binaries expect %s to be copied or moved to %s\n", 1684 goroot, goroot_final) 1685 } 1686 } 1687 1688 // Version prints the Go version. 1689 func cmdversion() { 1690 xflagparse(0) 1691 xprintf("%s\n", findgoversion()) 1692 } 1693 1694 // cmdlist lists all supported platforms. 1695 func cmdlist() { 1696 jsonFlag := flag.Bool("json", false, "produce JSON output") 1697 xflagparse(0) 1698 1699 var plats []string 1700 for p := range cgoEnabled { 1701 if incomplete[p] { 1702 continue 1703 } 1704 plats = append(plats, p) 1705 } 1706 sort.Strings(plats) 1707 1708 if !*jsonFlag { 1709 for _, p := range plats { 1710 xprintf("%s\n", p) 1711 } 1712 return 1713 } 1714 1715 type jsonResult struct { 1716 GOOS string 1717 GOARCH string 1718 CgoSupported bool 1719 } 1720 var results []jsonResult 1721 for _, p := range plats { 1722 fields := strings.Split(p, "/") 1723 results = append(results, jsonResult{ 1724 GOOS: fields[0], 1725 GOARCH: fields[1], 1726 CgoSupported: cgoEnabled[p]}) 1727 } 1728 out, err := json.MarshalIndent(results, "", "\t") 1729 if err != nil { 1730 fatalf("json marshal error: %v", err) 1731 } 1732 if _, err := os.Stdout.Write(out); err != nil { 1733 fatalf("write failed: %v", err) 1734 } 1735 }